@@ -3,38 +3,13 @@ name: Create GitHub Release
33on :
44 workflow_dispatch :
55 inputs :
6- version-name :
7- description : ' Version Name - E.g. "2024.11.1"'
8- required : true
9- type : string
10- version-number :
11- description : ' Version Number - E.g. "123456"'
12- required : true
13- type : string
146 artifact-run-id :
157 description : ' GitHub Action Run ID containing artifacts'
168 required : true
179 type : string
18- draft :
19- description : ' Create as draft release'
20- type : boolean
21- default : true
22- prerelease :
23- description : ' Mark as pre-release'
24- type : boolean
25- default : true
26- make-latest :
27- description : ' Set as the latest release'
28- type : boolean
29- branch-protection-type :
30- description : ' Branch protection type'
31- type : choice
32- options :
33- - Branch Name
34- - GitHub API
35- default : Branch Name
3610env :
3711 ARTIFACTS_PATH : artifacts
12+
3813jobs :
3914 create-release :
4015 name : Create GitHub Release
@@ -53,31 +28,85 @@ jobs:
5328 env :
5429 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
5530 ARTIFACT_RUN_ID : ${{ inputs.artifact-run-id }}
56- BRANCH_PROTECTION_TYPE : ${{ inputs.branch-protection-type }}
5731 run : |
58- release_branch=$(gh run view $ARTIFACT_RUN_ID --json headBranch -q .headBranch)
59-
60- case "$BRANCH_PROTECTION_TYPE" in
61- "Branch Name")
62- if [[ "$release_branch" != "main" && ! "$release_branch" =~ ^release/ ]]; then
63- echo "::error::Branch '$release_branch' is not 'main' or a release branch starting with 'release/'. Releases must be created from protected branches."
64- exit 1
65- fi
32+ workflow_data=$(gh run view $ARTIFACT_RUN_ID --json headBranch,workflowName)
33+ release_branch=$(echo "$workflow_data" | jq -r .headBranch)
34+ workflow_name=$(echo "$workflow_data" | jq -r .workflowName)
35+
36+ # branch protection check
37+ if [[ "$release_branch" != "main" && ! "$release_branch" =~ ^release/ ]]; then
38+ echo "::error::Branch '$release_branch' is not 'main' or a release branch starting with 'release/'. Releases must be created from protected branches."
39+ exit 1
40+ fi
41+
42+ echo "release_branch=$release_branch" >> $GITHUB_OUTPUT
43+ echo "workflow_name=$workflow_name" >> $GITHUB_OUTPUT
44+
45+ case "$workflow_name" in
46+ *"Password Manager"* | "Build")
47+ echo "app_name=Password Manager" >> $GITHUB_OUTPUT
6648 ;;
67- "GitHub API")
68- #NOTE requires token with "administration:read" scope
69- if ! gh api "repos/${{ github.repository }}/branches/$release_branch/protection" | grep -q "required_status_checks"; then
70- echo "::error::Branch '$release_branch' is not protected. Releases must be created from protected branches. If that's not correct, confirm if the github token user has the 'administration:read' scope."
71- exit 1
72- fi
49+ *"Authenticator"*)
50+ echo "app_name=Authenticator" >> $GITHUB_OUTPUT
7351 ;;
7452 *)
75- echo "::error::Unsupported branch protection type : $BRANCH_PROTECTION_TYPE "
53+ echo "::error::Unknown workflow name : $workflow_name "
7654 exit 1
7755 ;;
7856 esac
7957
80- echo "release_branch=$release_branch" >> $GITHUB_OUTPUT
58+ - name : Get version info from run logs and set release tag name
59+ id : get_release_info
60+ env :
61+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
62+ ARTIFACT_RUN_ID : ${{ inputs.artifact-run-id }}
63+ APP_NAME : ${{ steps.get_release_branch.outputs.app_name }}
64+ run : |
65+ workflow_log=$(gh run view $ARTIFACT_RUN_ID --log)
66+
67+ version_number_with_trailing_dot=$(grep -m 1 "Setting version code to" <<< "$workflow_log" | sed 's/.*Setting version code to //')
68+ version_number=${version_number_with_trailing_dot%.} # remove trailing dot
69+
70+ version_name_with_trailing_dot=$(grep -m 1 "Setting version name to" <<< "$workflow_log" | sed 's/.*Setting version name to //')
71+ version_name=${version_name_with_trailing_dot%.} # remove trailing dot
72+
73+ if [[ -z "$version_name" ]]; then
74+ echo "::warning::Version name not found. Using default value - 0.0.0"
75+ version_name="0.0.0"
76+ else
77+ echo "✅ Found version name: $version_name"
78+ fi
79+
80+ if [[ -z "$version_number" ]]; then
81+ echo "::warning::Version number not found. Using default value - 0"
82+ version_number="0"
83+ else
84+ echo "✅ Found version number: $version_number"
85+ fi
86+
87+ echo "version_number=$version_number" >> $GITHUB_OUTPUT
88+ echo "version_name=$version_name" >> $GITHUB_OUTPUT
89+
90+ case "$APP_NAME" in
91+ "Password Manager")
92+ app_name_suffix="bwpm"
93+ ;;
94+ "Authenticator")
95+ app_name_suffix="bwa"
96+ ;;
97+ *)
98+ echo "::error::Unknown app name: $APP_NAME"
99+ exit 1
100+ ;;
101+ esac
102+
103+ tag_name="v$version_name-$app_name_suffix" # e.g. v2025.6.0-bwpm
104+ echo "🔖 New tag name: $tag_name"
105+ echo "tag_name=$tag_name" >> $GITHUB_OUTPUT
106+
107+ last_release_tag=$(git tag -l --sort=-authordate | grep "$app_name_suffix" | head -n 1)
108+ echo "🔖 Last release tag: $last_release_tag"
109+ echo "last_release_tag=$last_release_tag" >> $GITHUB_OUTPUT
81110
82111 - name : Download artifacts
83112 env :
@@ -94,35 +123,76 @@ jobs:
94123
95124 - name : Create Release
96125 id : create_release
97- uses : softprops/action-gh-release@da05d552573ad5aba039eaac05058a918a7bf631 # v2.2.2
98- with :
99- tag_name : " v${{ inputs.version-name }}"
100- name : " ${{ inputs.version-name }} (${{ inputs.version-number }})"
101- prerelease : ${{ inputs.prerelease }}
102- draft : ${{ inputs.draft }}
103- make_latest : ${{ inputs.make-latest }}
104- target_commitish : ${{ steps.get_release_branch.outputs.release_branch }}
105- generate_release_notes : true
106- files : |
107- artifacts/**/*
126+ env :
127+ GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
128+ _APP_NAME : ${{ steps.get_release_branch.outputs.app_name }}
129+ _VERSION_NAME : ${{ steps.get_release_info.outputs.version_name }}
130+ _VERSION_NUMBER : ${{ steps.get_release_info.outputs.version_number }}
131+ _TARGET_COMMIT : ${{ steps.get_release_branch.outputs.release_branch }}
132+ _TAG_NAME : ${{ steps.get_release_info.outputs.tag_name }}
133+ _LAST_RELEASE_TAG : ${{ steps.get_release_info.outputs.last_release_tag }}
134+ run : |
135+ echo "⌛️ Creating release for $_APP_NAME $_VERSION_NAME ($_VERSION_NUMBER) on $_TARGET_COMMIT"
136+ release_url=$(gh release create "$_TAG_NAME" \
137+ --title "$_APP_NAME $_VERSION_NAME ($_VERSION_NUMBER)" \
138+ --target "$_TARGET_COMMIT" \
139+ --generate-notes \
140+ --notes-start-tag "$_LAST_RELEASE_TAG" \
141+ --draft \
142+ $ARTIFACTS_PATH/*/*)
143+
144+ echo "✅ Release created: $release_url"
145+
146+ # Get release info for outputs
147+ release_data=$(gh release view "$_TAG_NAME" --json id)
148+ release_id=$(echo "$release_data" | jq -r .id)
149+
150+ echo "id=$release_id" >> $GITHUB_OUTPUT
151+ echo "url=$release_url" >> $GITHUB_OUTPUT
108152
109153 - name : Update Release Description
154+ id : update_release_description
110155 env :
111156 GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
112- RELEASE_ID : ${{ steps.create_release.outputs.id }}
113- RELEASE_URL : ${{ steps.create_release.outputs.url }}
114157 ARTIFACT_RUN_ID : ${{ inputs.artifact-run-id }}
158+ _VERSION_NAME : ${{ steps.get_release_info.outputs.version_name }}
159+ _TAG_NAME : ${{ steps.get_release_info.outputs.tag_name }}
115160 run : |
116- # Get current release body
117- current_body=$(gh api /repos/${{ github.repository }}/releases/$RELEASE_ID --jq .body)
161+ echo "Getting current release body. Tag: $_TAG_NAME"
162+ current_body=$(gh release view "$_TAG_NAME" --json body --jq .body)
118163
119164 # Append build source to the end
120165 updated_body="${current_body}
121166 **Builds Source:** https://github.com/${{ github.repository }}/actions/runs/$ARTIFACT_RUN_ID"
122167
123- # Update release
124- gh api --method PATCH /repos/${{ github.repository }}/releases/$RELEASE_ID \
125- -f body="$updated_body"
168+ new_release_url=$(gh release edit "$_TAG_NAME" --notes "$updated_body")
169+
170+ # draft release links change after editing
171+ echo "release_url=$new_release_url" >> $GITHUB_OUTPUT
172+
173+ - name : Add Release Summary
174+ env :
175+ _RELEASE_TAG : ${{ steps.get_release_info.outputs.tag_name }}
176+ _LAST_RELEASE_TAG : ${{ steps.get_release_info.outputs.last_release_tag }}
177+ _VERSION_NAME : ${{ steps.get_release_info.outputs.version_name }}
178+ _VERSION_NUMBER : ${{ steps.get_release_info.outputs.version_number }}
179+ _RELEASE_BRANCH : ${{ steps.get_release_branch.outputs.release_branch }}
180+ _RELEASE_URL : ${{ steps.update_release_description.outputs.release_url }}
181+ run : |
182+ echo "# :fish_cake: Release ready at:" >> $GITHUB_STEP_SUMMARY
183+ echo "$_RELEASE_URL" >> $GITHUB_STEP_SUMMARY
184+ echo "" >> $GITHUB_STEP_SUMMARY
185+
186+ if [[ "$_VERSION_NAME" == "0.0.0" || "$_VERSION_NUMBER" == "0" ]]; then
187+ echo "> [!CAUTION]" >> $GITHUB_STEP_SUMMARY
188+ 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
189+ echo "" >> $GITHUB_STEP_SUMMARY
190+ fi
126191
127- echo "# :rocket: Release ready at:" >> $GITHUB_STEP_SUMMARY
128- echo "$RELEASE_URL" >> $GITHUB_STEP_SUMMARY
192+ echo ":clipboard: Confirm that the defined GitHub Release options are correct:" >> $GITHUB_STEP_SUMMARY
193+ echo " * :bookmark: New tag name: \`$_RELEASE_TAG\`" >> $GITHUB_STEP_SUMMARY
194+ echo " * :palm_tree: Target branch: \`$_RELEASE_BRANCH\`" >> $GITHUB_STEP_SUMMARY
195+ echo " * :ocean: Previous tag set in the description \"Full Changelog\" link: \`$_LAST_RELEASE_TAG\`" >> $GITHUB_STEP_SUMMARY
196+ echo " * :white_check_mark: Description has automated release notes and they match the commits in the release branch" >> $GITHUB_STEP_SUMMARY
197+ echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY
198+ echo "> Commits directly pushed to branches without a Pull Request won't appear in the automated release notes." >> $GITHUB_STEP_SUMMARY
0 commit comments