11name : SDLC / SDK Update
2+ run-name : " SDK ${{inputs.run-mode == 'Update' && format('Update - {0}', inputs.sdk-version) || format('Test #{0} - {1}', inputs.pr-id, inputs.sdk-version)}}"
23
34on :
45 workflow_dispatch :
6+ inputs :
7+ run-mode :
8+ description : " Run Mode"
9+ type : choice
10+ options :
11+ - Test # used for testing sdk-internal repo PRs
12+ - Update # opens a PR in this repo updating the SDK
13+ default : Update
14+ sdk-version :
15+ description : " SDK Version"
16+ required : true
17+ default : " 1.0.0-283-7b5d9db"
18+ sdk-swift-ref :
19+ description : " sdk-swift repo git ref"
20+ required : true
21+ default : " c2817139d7da49037841215d37a2f931525bf0fc"
22+ pr-id :
23+ description : " Pull Request ID (Test mode only)"
524
6- permissions :
7- contents : read
25+ env :
26+ _BOT_NAME : " bw-ghapp[bot]"
27+ _BOT_EMAIL : " 178206702+bw-ghapp[bot]@users.noreply.github.com"
28+ _SDK_DEPENDENCY_NAME : " BitwardenSdk"
829
930jobs :
1031 update :
11- name : Update SDK
32+ name : Update and PR
33+ if : ${{ inputs.run-mode == 'Update' }}
1234 runs-on : ubuntu-24.04
35+ permissions :
36+ id-token : write
1337
1438 steps :
15- - name : Placeholder
16- run : echo ":feelsgood:" >> $GITHUB_STEP_SUMMARY
39+ - name : Log in to Azure
40+ uses : bitwarden/gh-actions/azure-login@main
41+ with :
42+ subscription_id : ${{ secrets.AZURE_SUBSCRIPTION_ID }}
43+ tenant_id : ${{ secrets.AZURE_TENANT_ID }}
44+ client_id : ${{ secrets.AZURE_CLIENT_ID }}
45+
46+ - name : Get Azure Key Vault secrets
47+ id : get-kv-secrets
48+ uses : bitwarden/gh-actions/get-keyvault-secrets@main
49+ with :
50+ keyvault : gh-org-bitwarden
51+ secrets : " BW-GHAPP-ID,BW-GHAPP-KEY"
52+
53+ - name : Log out from Azure
54+ uses : bitwarden/gh-actions/azure-logout@main
55+
56+ - name : Generate GH App token
57+ uses : actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b # v2.1.1
58+ id : app-token
59+ with :
60+ app-id : ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }}
61+ private-key : ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }}
62+ permission-pull-requests : write
63+ permission-actions : read
64+ permission-contents : write
65+
66+ - name : Check out repo
67+ uses : actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
68+ with :
69+ token : ${{ steps.app-token.outputs.token }}
70+ fetch-depth : 0
71+
72+ - name : Log inputs to job summary
73+ uses : ./.github/actions/log-inputs
74+ with :
75+ inputs : ${{ toJson(inputs) }}
76+
77+ - name : Switch to branch
78+ id : switch-branch
79+ run : |
80+ BRANCH_NAME="sdlc/sdk-update"
81+ echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
82+
83+ if git switch $BRANCH_NAME; then
84+ echo "✅ Switched to existing branch: $BRANCH_NAME"
85+ echo "updating_existing_branch=true" >> $GITHUB_OUTPUT
86+ else
87+ echo "📝 Creating new branch: $BRANCH_NAME"
88+ git switch -c $BRANCH_NAME
89+ echo "updating_existing_branch=false" >> $GITHUB_OUTPUT
90+ fi
91+
92+ - name : Prevent updating the branch when the last committer isn't the bot
93+ if : ${{ steps.switch-branch.outputs.updating_existing_branch == 'true' }}
94+ env :
95+ GH_TOKEN : ${{ steps.app-token.outputs.token }}
96+ _BRANCH_NAME : ${{ steps.switch-branch.outputs.branch_name }}
97+ run : |
98+ LATEST_COMMIT_AUTHOR=$(git log -1 --format='%ae' $_BRANCH_NAME)
99+
100+ echo "Latest commit author in branch ($_BRANCH_NAME): $LATEST_COMMIT_AUTHOR"
101+ echo "Expected bot email: $_BOT_EMAIL"
102+
103+ if [ "$LATEST_COMMIT_AUTHOR" != "$_BOT_EMAIL" ]; then
104+ echo "::error::Branch $_BRANCH_NAME has a commit not made by the bot." \
105+ "This indicates manual changes have been made to the branch," \
106+ "PR has to be merged or closed before running this workflow again."
107+ echo "👀 Fetching existing PR..."
108+ gh pr list --head $_BRANCH_NAME --base main --state open --json number --jq '.[0].number // empty'
109+ EXISTING_PR=$(gh pr list --head $_BRANCH_NAME --base main --state open --json number --jq '.[0].number // empty')
110+ if [ -z "$EXISTING_PR" ]; then
111+ echo "::error::Couldn't find an existing PR for branch $_BRANCH_NAME."
112+ exit 1
113+ fi
114+ PR_URL="https://github.com/${{ github.repository }}/pull/$EXISTING_PR"
115+ echo "## ❌ Merge or close: $PR_URL" >> $GITHUB_STEP_SUMMARY
116+ exit 1
117+ fi
118+
119+ echo "✅ Branch tip commit was made by the bot. Safe to proceed."
120+
121+ # Using main to retrieve the changelog on consecutive updates of the same PR.
122+ - name : Get current SDK version from main branch
123+ id : get-current-sdk
124+ env :
125+ GH_TOKEN : ${{ steps.app-token.outputs.token }}
126+ run : |
127+ SDK_SWIFT_REF=$(git show origin/main:project-common.yml | yq '.packages.BitwardenSdk.revision')
128+ if [ -z "$SDK_SWIFT_REF" ]; then
129+ echo "::error::Failed to get current SDK version from main branch."
130+ exit 1
131+ fi
132+
133+ echo "👀 sdk-swift ref: $SDK_SWIFT_REF"
134+
135+ COMMIT_MESSAGE=$(gh api "repos/bitwarden/sdk-swift/commits/$SDK_SWIFT_REF" --jq '.commit.message')
136+ echo "👀 sdk-swift ref commit message: \"$COMMIT_MESSAGE\""
137+ SDK_INTERNAL_REF=$(echo "$COMMIT_MESSAGE" | grep -oE '[a-f0-9]{40}')
138+ if [ -z "$SDK_INTERNAL_REF" ]; then
139+ echo "::error::Failed to parse sdk-internal ref from commit message."
140+ exit 1
141+ fi
142+
143+ echo ""
144+ echo "📋 Current sdk-swift ref (from main): $SDK_SWIFT_REF"
145+ echo "📋 Current sdk-internal ref (parsed from commit): $SDK_INTERNAL_REF"
146+ echo "sdk-swift-ref=$SDK_SWIFT_REF" >> $GITHUB_OUTPUT
147+ echo "sdk-internal-ref=$SDK_INTERNAL_REF" >> $GITHUB_OUTPUT
148+
149+ - name : Detect downgrade and prevent updating to the current version
150+ id : detect-downgrade
151+ env :
152+ GH_TOKEN : ${{ steps.app-token.outputs.token }}
153+ _CURRENT_SDK_SWIFT_REF : ${{ steps.get-current-sdk.outputs.sdk-swift-ref }}
154+ _NEW_SDK_SWIFT_REF : ${{ inputs.sdk-swift-ref }}
155+ run : |
156+ if [ "$_CURRENT_SDK_SWIFT_REF" = "$_NEW_SDK_SWIFT_REF" ]; then
157+ echo "::error::Provided sdk-swift ref is the same as the current version in main."
158+ exit 1
159+ fi
160+
161+ COMPARE_RESULT=$(gh api "repos/bitwarden/sdk-swift/compare/$_CURRENT_SDK_SWIFT_REF...$_NEW_SDK_SWIFT_REF" --jq '.status')
162+
163+ if [ "$COMPARE_RESULT" = "behind" ]; then
164+ echo "::warning::The new SDK version ($_NEW_SDK_SWIFT_REF) is older than the current version ($_CURRENT_SDK_SWIFT_REF)"
165+ echo "downgrading=true" >> $GITHUB_OUTPUT
166+ else
167+ echo "✅ New SDK version is newer - proceeding with update"
168+ echo "downgrading=false" >> $GITHUB_OUTPUT
169+ fi
170+
171+ - name : Update SDK Version
172+ env :
173+ _SDK_VERSION : ${{ inputs.sdk-version }}
174+ _SDK_SWIFT_REF : ${{ inputs.sdk-swift-ref }}
175+ run : |
176+ ./Scripts/update-sdk-version.sh "$_SDK_DEPENDENCY_NAME" "$_SDK_SWIFT_REF" "$_SDK_VERSION"
177+
178+ - name : Create branch and commit
179+ env :
180+ _SDK_VERSION : ${{ inputs.sdk-version }}
181+ _SDK_SWIFT_REF : ${{ inputs.sdk-swift-ref }}
182+ _BRANCH_NAME : ${{ steps.switch-branch.outputs.branch_name }}
183+ run : |
184+ echo "👀 Committing SDK version update..."
185+ _SDK_SWIFT_REF_SHORT="${_SDK_SWIFT_REF:0:7}"
186+
187+ git config user.name "$_BOT_NAME"
188+ git config user.email "$_BOT_EMAIL"
189+
190+ git add project-common.yml
191+ git commit -m "SDK Update - $_SDK_SWIFT_REF_SHORT ($_SDK_VERSION)"
192+ git push origin $_BRANCH_NAME
193+
194+ - name : Create or Update Pull Request
195+ env :
196+ GH_TOKEN : ${{ steps.app-token.outputs.token }}
197+ _BRANCH_NAME : ${{ steps.switch-branch.outputs.branch_name }}
198+ _NEW_SDK_VERSION : ${{ inputs.sdk-version }}
199+ _NEW_SDK_SWIFT_REF : ${{ inputs.sdk-swift-ref }}
200+ _OLD_SDK_SWIFT_REF : ${{ steps.get-current-sdk.outputs.sdk-swift-ref }}
201+ _OLD_SDK_INTERNAL_REF : ${{ steps.get-current-sdk.outputs.sdk-internal-ref }}
202+ _DOWNGRADING : ${{ steps.detect-downgrade.outputs.downgrading }}
203+ run : |
204+ _NEW_SDK_INTERNAL_REF=$(echo "$_NEW_SDK_VERSION" | cut -d'-' -f3-)
205+ PR_BODY="Updates the SDK from \`$_OLD_SDK_SWIFT_REF\` to \`$_NEW_SDK_SWIFT_REF\`"
206+
207+ if [ "$_DOWNGRADING" = "true" ]; then
208+ PR_BODY="$PR_BODY\n\n## :warning: Downgrading SDK to an older version. :warning:"
209+ PR_TITLE_ACTION="Downgrading"
210+ else
211+ CHANGELOG=$(./Scripts/get-repo-changelog.sh "bitwarden/sdk-internal" "$_OLD_SDK_INTERNAL_REF" "$_NEW_SDK_INTERNAL_REF")
212+ PR_BODY="$PR_BODY\n\n## What's Changed\n\n$CHANGELOG"
213+ PR_TITLE_ACTION="Updating"
214+ fi
215+
216+ EXISTING_PR=$(gh pr list --head $_BRANCH_NAME --base main --state open --json number --jq '.[0].number // empty')
217+ _NEW_SDK_SWIFT_REF_SHORT="${_NEW_SDK_SWIFT_REF:0:7}"
218+
219+ if [ -n "$EXISTING_PR" ]; then
220+ echo "🔄 Updating existing PR #$EXISTING_PR..."
221+ echo -e "$PR_BODY" | gh pr edit $EXISTING_PR \
222+ --title "$PR_TITLE_ACTION SDK to $_NEW_SDK_SWIFT_REF_SHORT ($_NEW_SDK_VERSION)" \
223+ --body-file -
224+ PR_URL="https://github.com/${{ github.repository }}/pull/$EXISTING_PR"
225+ echo "## ✅ Updated PR: $PR_URL" >> $GITHUB_STEP_SUMMARY
226+ else
227+ echo "📝 Creating new PR..."
228+ PR_URL=$(echo -e "$PR_BODY" | gh pr create \
229+ --title "$PR_TITLE_ACTION SDK to $_NEW_SDK_SWIFT_REF_SHORT ($_NEW_SDK_VERSION)" \
230+ --body-file - \
231+ --base main \
232+ --head $_BRANCH_NAME \
233+ --label "automated-pr" \
234+ --label "t:ci")
235+ echo "## 🚀 Created PR: $PR_URL" >> $GITHUB_STEP_SUMMARY
236+ fi
0 commit comments