name: Create GitHub Release on: workflow_dispatch: inputs: artifact-run-id: description: 'GitHub Action Run ID containing artifacts' required: true type: string release-ticket-id: description: 'Release Ticket ID - e.g. RELEASE-1762' required: true type: string env: ARTIFACTS_PATH: artifacts jobs: create-release: name: Create GitHub Release runs-on: ubuntu-24.04 permissions: contents: write id-token: write steps: - name: Check out repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Get branch from workflow run id: get_release_branch env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ARTIFACT_RUN_ID: ${{ inputs.artifact-run-id }} run: | workflow_data=$(gh run view $ARTIFACT_RUN_ID --json headBranch,workflowName) release_branch=$(echo "$workflow_data" | jq -r .headBranch) workflow_name=$(echo "$workflow_data" | jq -r .workflowName) # branch protection check if [[ "$release_branch" != "main" && ! "$release_branch" =~ ^release/ ]]; then echo "::error::Branch '$release_branch' is not 'main' or a release branch starting with 'release/'. Releases must be created from protected branches." exit 1 fi echo "release_branch=$release_branch" >> $GITHUB_OUTPUT echo "workflow_name=$workflow_name" >> $GITHUB_OUTPUT case "$workflow_name" in *"Password Manager"* | "Build") echo "app_name=Password Manager" >> $GITHUB_OUTPUT echo "app_name_suffix=bwpm" >> $GITHUB_OUTPUT ;; *"Authenticator"*) echo "app_name=Authenticator" >> $GITHUB_OUTPUT echo "app_name_suffix=bwa" >> $GITHUB_OUTPUT ;; *) echo "::error::Unknown workflow name: $workflow_name" exit 1 ;; esac - name: Get version info from run logs and set release tag name id: get_release_info env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ARTIFACT_RUN_ID: ${{ inputs.artifact-run-id }} _APP_NAME_SUFFIX: ${{ steps.get_release_branch.outputs.app_name_suffix }} run: | workflow_log=$(gh run view $ARTIFACT_RUN_ID --log) version_number_with_trailing_dot=$(grep -m 1 "Setting version code to" <<< "$workflow_log" | sed 's/.*Setting version code to //') version_number=${version_number_with_trailing_dot%.} # remove trailing dot version_name_with_trailing_dot=$(grep -m 1 "Setting version name to" <<< "$workflow_log" | sed 's/.*Setting version name to //') version_name=${version_name_with_trailing_dot%.} # remove trailing dot if [[ -z "$version_name" ]]; then echo "::warning::Version name not found. Using default value - 0.0.0" version_name="0.0.0" else echo "✅ Found version name: $version_name" fi if [[ -z "$version_number" ]]; then echo "::warning::Version number not found. Using default value - 0" version_number="0" else echo "✅ Found version number: $version_number" fi echo "version_number=$version_number" >> $GITHUB_OUTPUT echo "version_name=$version_name" >> $GITHUB_OUTPUT tag_name="v$version_name-$_APP_NAME_SUFFIX" # e.g. v2025.6.0-bwpm echo "🔖 New tag name: $tag_name" echo "tag_name=$tag_name" >> $GITHUB_OUTPUT last_release_tag=$(git tag -l --sort=-authordate | grep "$APP_NAME_SUFFIX" | head -n 1) echo "🔖 Last release tag: $last_release_tag" echo "last_release_tag=$last_release_tag" >> $GITHUB_OUTPUT - name: Download artifacts env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ARTIFACT_RUN_ID: ${{ inputs.artifact-run-id }} run: | gh run download $ARTIFACT_RUN_ID -D $ARTIFACTS_PATH file_count=$(find $ARTIFACTS_PATH -type f | wc -l) echo "Downloaded $file_count file(s)." if [ "$file_count" -gt 0 ]; then echo "Downloaded files:" find $ARTIFACTS_PATH -type f fi - name: Log in to Azure uses: bitwarden/gh-actions/azure-login@main with: subscription_id: ${{ secrets.AZURE_SUBSCRIPTION_ID }} tenant_id: ${{ secrets.AZURE_TENANT_ID }} client_id: ${{ secrets.AZURE_CLIENT_ID }} - name: Get Azure Key Vault secrets id: get-kv-secrets uses: bitwarden/gh-actions/get-keyvault-secrets@main with: keyvault: gh-android secrets: "JIRA-API-EMAIL,JIRA-API-TOKEN" - name: Log out from Azure uses: bitwarden/gh-actions/azure-logout@main - name: Get product release notes id: get_release_notes env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ARTIFACT_RUN_ID: ${{ inputs.artifact-run-id }} _VERSION_NAME: ${{ steps.get_release_info.outputs.version_name }} _RELEASE_TICKET_ID: ${{ inputs.release-ticket-id }} _JIRA_API_EMAIL: ${{ steps.get-kv-secrets.outputs.JIRA-API-EMAIL }} _JIRA_API_TOKEN: ${{ steps.get-kv-secrets.outputs.JIRA-API-TOKEN }} run: | echo "Getting product release notes" product_release_notes=$(python3 .github/scripts/jira-get-release-notes/jira_release_notes.py $_RELEASE_TICKET_ID $_JIRA_API_EMAIL $_JIRA_API_TOKEN) if [[ -z "$product_release_notes" || $product_release_notes == "Error checking"* ]]; then echo "::warning::Failed to fetch release notes from Jira. Output: $product_release_notes" product_release_notes="" else echo "✅ Product release notes:" echo "$product_release_notes" fi echo "$product_release_notes" > product_release_notes.txt - name: Create Release id: create_release env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} _APP_NAME: ${{ steps.get_release_branch.outputs.app_name }} _VERSION_NAME: ${{ steps.get_release_info.outputs.version_name }} _VERSION_NUMBER: ${{ steps.get_release_info.outputs.version_number }} _TARGET_COMMIT: ${{ steps.get_release_branch.outputs.release_branch }} _TAG_NAME: ${{ steps.get_release_info.outputs.tag_name }} _LAST_RELEASE_TAG: ${{ steps.get_release_info.outputs.last_release_tag }} run: | echo "⌛️ Creating release for $_APP_NAME $_VERSION_NAME ($_VERSION_NUMBER) on $_TARGET_COMMIT" release_url=$(gh release create "$_TAG_NAME" \ --title "$_APP_NAME $_VERSION_NAME ($_VERSION_NUMBER)" \ --target "$_TARGET_COMMIT" \ --generate-notes \ --notes-start-tag "$_LAST_RELEASE_TAG" \ --draft \ $ARTIFACTS_PATH/*/*) echo "✅ Release created: $release_url" # Get release info for outputs release_data=$(gh release view "$_TAG_NAME" --json id) release_id=$(echo "$release_data" | jq -r .id) echo "id=$release_id" >> $GITHUB_OUTPUT echo "url=$release_url" >> $GITHUB_OUTPUT - name: Update Release Description id: update_release_description env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ARTIFACT_RUN_ID: ${{ inputs.artifact-run-id }} _VERSION_NAME: ${{ steps.get_release_info.outputs.version_name }} _TAG_NAME: ${{ steps.get_release_info.outputs.tag_name }} run: | echo "Getting current release body. Tag: $_TAG_NAME" current_body=$(gh release view "$_TAG_NAME" --json body --jq .body) product_release_notes=$(cat product_release_notes.txt) # Update release description with product release notes and builds source updated_body="# Overview ${product_release_notes} ${current_body} **Builds Source:** https://github.com/${{ github.repository }}/actions/runs/$ARTIFACT_RUN_ID" new_release_url=$(gh release edit "$_TAG_NAME" --notes "$updated_body") # draft release links change after editing echo "release_url=$new_release_url" >> $GITHUB_OUTPUT - name: Add Release Summary env: _RELEASE_TAG: ${{ steps.get_release_info.outputs.tag_name }} _LAST_RELEASE_TAG: ${{ steps.get_release_info.outputs.last_release_tag }} _VERSION_NAME: ${{ steps.get_release_info.outputs.version_name }} _VERSION_NUMBER: ${{ steps.get_release_info.outputs.version_number }} _RELEASE_BRANCH: ${{ steps.get_release_branch.outputs.release_branch }} _RELEASE_URL: ${{ steps.update_release_description.outputs.release_url }} run: | echo "# :fish_cake: Release ready at:" >> $GITHUB_STEP_SUMMARY echo "$_RELEASE_URL" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [[ "$_VERSION_NAME" == "0.0.0" || "$_VERSION_NUMBER" == "0" ]]; then echo "> [!CAUTION]" >> $GITHUB_STEP_SUMMARY echo "> Version name or number wasn't previously found and a default value was used. You'll need to manually update the release Title, Tag and Description, specifically, the "Full Changelog" link." >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY fi echo ":clipboard: Confirm that the defined GitHub Release options are correct:" >> $GITHUB_STEP_SUMMARY echo " * :bookmark: New tag name: \`$_RELEASE_TAG\`" >> $GITHUB_STEP_SUMMARY echo " * :palm_tree: Target branch: \`$_RELEASE_BRANCH\`" >> $GITHUB_STEP_SUMMARY echo " * :ocean: Previous tag set in the description \"Full Changelog\" link: \`$_LAST_RELEASE_TAG\`" >> $GITHUB_STEP_SUMMARY echo " * :white_check_mark: Description has automated release notes and they match the commits in the release branch" >> $GITHUB_STEP_SUMMARY echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY echo "> Commits directly pushed to branches without a Pull Request won't appear in the automated release notes." >> $GITHUB_STEP_SUMMARY