Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
c9c5c11
Add script to update bitwarden sdk revision value
LRNcardozoWDF Aug 22, 2025
4eeb9cd
Merge branch 'main' into cmcg/sdk-update-new-workflow
LRNcardozoWDF Aug 22, 2025
a0a47fe
Add workflow to update sdk version
LRNcardozoWDF Aug 22, 2025
ee73781
Change folder name and replaced sed by yq
LRNcardozoWDF Aug 22, 2025
252d3c2
Move bot name to env var
vvolkgang Sep 1, 2025
fc046d9
Set token permissions
vvolkgang Sep 1, 2025
45000e4
Fix switch to branch step
vvolkgang Sep 1, 2025
0106366
Get current SDK version from main
vvolkgang Sep 1, 2025
2fa3756
Prevent updating branch when devs are fixing breaking changes
vvolkgang Sep 1, 2025
2eff15d
Add script to fetch repo changelogs
vvolkgang Sep 2, 2025
5e06248
Merge branch 'main' into cmcg/sdk-update-new-workflow
vvolkgang Sep 2, 2025
6d93319
Update project-common.yml instead of app specific files
vvolkgang Sep 2, 2025
bef4fb5
Remove sdk-package, not used on iOS
vvolkgang Sep 2, 2025
c0e0734
Add inputs for git refs
vvolkgang Sep 2, 2025
d12b2a8
Implement get current sdk refs (both from sdk-swift and sdk-internal)
vvolkgang Sep 2, 2025
184b083
Update commit message
vvolkgang Sep 2, 2025
8171d14
Use sdk-swift-ref on update-sdk script
vvolkgang Sep 2, 2025
30d39a6
Implement create or update PR
vvolkgang Sep 2, 2025
e7ef69b
update sdk script sets sdk version as a comment now
vvolkgang Sep 2, 2025
f6a693a
Refactor log messages
vvolkgang Sep 2, 2025
2cba47f
Fix script path
vvolkgang Sep 2, 2025
a6ee6a0
Remove sdk-internal-ref input, fetch it from sdk-version instead
vvolkgang Sep 3, 2025
efc6300
Use short commit hash for commit message and PR title
vvolkgang Sep 3, 2025
20bd3c5
Remove commented test job code
vvolkgang Sep 3, 2025
854f391
Update defaults
vvolkgang Sep 3, 2025
f237082
Detect downgrades
vvolkgang Sep 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
230 changes: 225 additions & 5 deletions .github/workflows/sdlc-sdk-update.yml
Original file line number Diff line number Diff line change
@@ -1,16 +1,236 @@
name: SDLC / SDK Update
run-name: "SDK ${{inputs.run-mode == 'Update' && format('Update - {0}', inputs.sdk-version) || format('Test #{0} - {1}', inputs.pr-id, inputs.sdk-version)}}"

on:
workflow_dispatch:
inputs:
run-mode:
description: "Run Mode"
type: choice
options:
- Test # used for testing sdk-internal repo PRs
- Update # opens a PR in this repo updating the SDK
default: Update
sdk-version:
description: "SDK Version"
required: true
default: "1.0.0-283-7b5d9db"
sdk-swift-ref:
description: "sdk-swift repo git ref"
required: true
default: "c2817139d7da49037841215d37a2f931525bf0fc"
pr-id:
description: "Pull Request ID (Test mode only)"

permissions:
contents: read
env:
_BOT_NAME: "bw-ghapp[bot]"
_BOT_EMAIL: "178206702+bw-ghapp[bot]@users.noreply.github.com"
_SDK_DEPENDENCY_NAME: "BitwardenSdk"

jobs:
update:
name: Update SDK
name: Update and PR
if: ${{ inputs.run-mode == 'Update' }}
runs-on: ubuntu-24.04
permissions:
id-token: write

steps:
- name: Placeholder
run: echo ":feelsgood:" >> $GITHUB_STEP_SUMMARY
- 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-org-bitwarden
secrets: "BW-GHAPP-ID,BW-GHAPP-KEY"

- name: Log out from Azure
uses: bitwarden/gh-actions/azure-logout@main

- name: Generate GH App token
uses: actions/create-github-app-token@a8d616148505b5069dccd32f177bb87d7f39123b # v2.1.1
id: app-token
with:
app-id: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-ID }}
private-key: ${{ steps.get-kv-secrets.outputs.BW-GHAPP-KEY }}
permission-pull-requests: write
permission-actions: read
permission-contents: write

- name: Check out repo
uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955 # v4.3.0
with:
token: ${{ steps.app-token.outputs.token }}
fetch-depth: 0

- name: Log inputs to job summary
uses: ./.github/actions/log-inputs
with:
inputs: ${{ toJson(inputs) }}

- name: Switch to branch
id: switch-branch
run: |
BRANCH_NAME="sdlc/sdk-update"
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT

if git switch $BRANCH_NAME; then
echo "โœ… Switched to existing branch: $BRANCH_NAME"
echo "updating_existing_branch=true" >> $GITHUB_OUTPUT
else
echo "๐Ÿ“ Creating new branch: $BRANCH_NAME"
git switch -c $BRANCH_NAME
echo "updating_existing_branch=false" >> $GITHUB_OUTPUT
fi

- name: Prevent updating the branch when the last committer isn't the bot
if: ${{ steps.switch-branch.outputs.updating_existing_branch == 'true' }}
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
_BRANCH_NAME: ${{ steps.switch-branch.outputs.branch_name }}
run: |
LATEST_COMMIT_AUTHOR=$(git log -1 --format='%ae' $_BRANCH_NAME)

echo "Latest commit author in branch ($_BRANCH_NAME): $LATEST_COMMIT_AUTHOR"
echo "Expected bot email: $_BOT_EMAIL"

if [ "$LATEST_COMMIT_AUTHOR" != "$_BOT_EMAIL" ]; then
echo "::error::Branch $_BRANCH_NAME has a commit not made by the bot." \
"This indicates manual changes have been made to the branch," \
"PR has to be merged or closed before running this workflow again."
echo "๐Ÿ‘€ Fetching existing PR..."
gh pr list --head $_BRANCH_NAME --base main --state open --json number --jq '.[0].number // empty'
EXISTING_PR=$(gh pr list --head $_BRANCH_NAME --base main --state open --json number --jq '.[0].number // empty')
if [ -z "$EXISTING_PR" ]; then
echo "::error::Couldn't find an existing PR for branch $_BRANCH_NAME."
exit 1
fi
PR_URL="https://github.com/${{ github.repository }}/pull/$EXISTING_PR"
echo "## โŒ Merge or close: $PR_URL" >> $GITHUB_STEP_SUMMARY
exit 1
fi

echo "โœ… Branch tip commit was made by the bot. Safe to proceed."

# Using main to retrieve the changelog on consecutive updates of the same PR.
- name: Get current SDK version from main branch
id: get-current-sdk
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
run: |
SDK_SWIFT_REF=$(git show origin/main:project-common.yml | yq '.packages.BitwardenSdk.revision')
if [ -z "$SDK_SWIFT_REF" ]; then
echo "::error::Failed to get current SDK version from main branch."
exit 1
fi

echo "๐Ÿ‘€ sdk-swift ref: $SDK_SWIFT_REF"

COMMIT_MESSAGE=$(gh api "repos/bitwarden/sdk-swift/commits/$SDK_SWIFT_REF" --jq '.commit.message')
echo "๐Ÿ‘€ sdk-swift ref commit message: \"$COMMIT_MESSAGE\""
SDK_INTERNAL_REF=$(echo "$COMMIT_MESSAGE" | grep -oE '[a-f0-9]{40}')
if [ -z "$SDK_INTERNAL_REF" ]; then
echo "::error::Failed to parse sdk-internal ref from commit message."
exit 1
fi

echo ""
echo "๐Ÿ“‹ Current sdk-swift ref (from main): $SDK_SWIFT_REF"
echo "๐Ÿ“‹ Current sdk-internal ref (parsed from commit): $SDK_INTERNAL_REF"
echo "sdk-swift-ref=$SDK_SWIFT_REF" >> $GITHUB_OUTPUT
echo "sdk-internal-ref=$SDK_INTERNAL_REF" >> $GITHUB_OUTPUT

- name: Detect downgrade and prevent updating to the current version
id: detect-downgrade
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
_CURRENT_SDK_SWIFT_REF: ${{ steps.get-current-sdk.outputs.sdk-swift-ref }}
_NEW_SDK_SWIFT_REF: ${{ inputs.sdk-swift-ref }}
run: |
if [ "$_CURRENT_SDK_SWIFT_REF" = "$_NEW_SDK_SWIFT_REF" ]; then
echo "::error::Provided sdk-swift ref is the same as the current version in main."
exit 1
fi

COMPARE_RESULT=$(gh api "repos/bitwarden/sdk-swift/compare/$_CURRENT_SDK_SWIFT_REF...$_NEW_SDK_SWIFT_REF" --jq '.status')

if [ "$COMPARE_RESULT" = "behind" ]; then
echo "::warning::The new SDK version ($_NEW_SDK_SWIFT_REF) is older than the current version ($_CURRENT_SDK_SWIFT_REF)"
echo "downgrading=true" >> $GITHUB_OUTPUT
else
echo "โœ… New SDK version is newer - proceeding with update"
echo "downgrading=false" >> $GITHUB_OUTPUT
fi

- name: Update SDK Version
env:
_SDK_VERSION: ${{ inputs.sdk-version }}
_SDK_SWIFT_REF: ${{ inputs.sdk-swift-ref }}
run: |
./Scripts/update-sdk-version.sh "$_SDK_DEPENDENCY_NAME" "$_SDK_SWIFT_REF" "$_SDK_VERSION"

- name: Create branch and commit
env:
_SDK_VERSION: ${{ inputs.sdk-version }}
_SDK_SWIFT_REF: ${{ inputs.sdk-swift-ref }}
_BRANCH_NAME: ${{ steps.switch-branch.outputs.branch_name }}
run: |
echo "๐Ÿ‘€ Committing SDK version update..."
_SDK_SWIFT_REF_SHORT="${_SDK_SWIFT_REF:0:7}"

git config user.name "$_BOT_NAME"
git config user.email "$_BOT_EMAIL"

git add project-common.yml
git commit -m "SDK Update - $_SDK_SWIFT_REF_SHORT ($_SDK_VERSION)"
git push origin $_BRANCH_NAME

- name: Create or Update Pull Request
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
_BRANCH_NAME: ${{ steps.switch-branch.outputs.branch_name }}
_NEW_SDK_VERSION: ${{ inputs.sdk-version }}
_NEW_SDK_SWIFT_REF: ${{ inputs.sdk-swift-ref }}
_OLD_SDK_SWIFT_REF: ${{ steps.get-current-sdk.outputs.sdk-swift-ref }}
_OLD_SDK_INTERNAL_REF: ${{ steps.get-current-sdk.outputs.sdk-internal-ref }}
_DOWNGRADING: ${{ steps.detect-downgrade.outputs.downgrading }}
run: |
_NEW_SDK_INTERNAL_REF=$(echo "$_NEW_SDK_VERSION" | cut -d'-' -f3-)
PR_BODY="Updates the SDK from \`$_OLD_SDK_SWIFT_REF\` to \`$_NEW_SDK_SWIFT_REF\`"

if [ "$_DOWNGRADING" = "true" ]; then
PR_BODY="$PR_BODY\n\n## :warning: Downgrading SDK to an older version. :warning:"
PR_TITLE_ACTION="Downgrading"
else
CHANGELOG=$(./Scripts/get-repo-changelog.sh "bitwarden/sdk-internal" "$_OLD_SDK_INTERNAL_REF" "$_NEW_SDK_INTERNAL_REF")
PR_BODY="$PR_BODY\n\n## What's Changed\n\n$CHANGELOG"
PR_TITLE_ACTION="Updating"
fi

EXISTING_PR=$(gh pr list --head $_BRANCH_NAME --base main --state open --json number --jq '.[0].number // empty')
_NEW_SDK_SWIFT_REF_SHORT="${_NEW_SDK_SWIFT_REF:0:7}"

if [ -n "$EXISTING_PR" ]; then
echo "๐Ÿ”„ Updating existing PR #$EXISTING_PR..."
echo -e "$PR_BODY" | gh pr edit $EXISTING_PR \
--title "$PR_TITLE_ACTION SDK to $_NEW_SDK_SWIFT_REF_SHORT ($_NEW_SDK_VERSION)" \
--body-file -
PR_URL="https://github.com/${{ github.repository }}/pull/$EXISTING_PR"
echo "## โœ… Updated PR: $PR_URL" >> $GITHUB_STEP_SUMMARY
else
echo "๐Ÿ“ Creating new PR..."
PR_URL=$(echo -e "$PR_BODY" | gh pr create \
--title "$PR_TITLE_ACTION SDK to $_NEW_SDK_SWIFT_REF_SHORT ($_NEW_SDK_VERSION)" \
--body-file - \
--base main \
--head $_BRANCH_NAME \
--label "automated-pr" \
--label "t:ci")
echo "## ๐Ÿš€ Created PR: $PR_URL" >> $GITHUB_STEP_SUMMARY
fi
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,6 @@ Configs/export_options.plist
# LicensePlist
Bitwarden/Application/Support/Settings.bundle/Acknowledgements.latest_result.txt
Authenticator/Application/Support/Settings.bundle/Acknowledgements.latest_result.txt

# Backup files
*.bak
40 changes: 40 additions & 0 deletions Scripts/get-repo-changelog.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/bash

# Script to get changelog between two git refs from a given GitHub repo.
# Usage: ./scripts/get-repo-changelog.sh <repo> <current-ref> <new-ref>

set -euo pipefail

if [ $# -lt 2 ]; then
echo "Usage: $0 <repo> <current-ref> <new-ref>"
echo "Example: $0 bitwarden/sdk-internal 9fe3aeda fix-wasm-import"
exit 1
fi

REPO="$1"
CURRENT_REF="$2"
NEW_REF="$3"

CHANGELOG=$(gh api "repos/$REPO/compare/$CURRENT_REF...$NEW_REF" \
--jq '.commits[] | "- \(.commit.message | split("\n")[0])"' | head -20)

if [ -z "$CHANGELOG" ]; then
echo "No changes found between $CURRENT_REF and $NEW_REF"
exit 0
fi


# GitHub renders org/repo#123 as a link to a PR, removing the commit message when a PR ID is found
# including the raw changelog in a collapsible section in case the pattern matching fails
CLEANED_CHANGELOG=$(echo "$CHANGELOG" | sed -E "s|.*\(#([0-9]+)\).*|- $REPO#\1|")

echo "$CLEANED_CHANGELOG"
echo
echo "<details>
<summary>Raw changelog</summary>

\`\`\`
$CHANGELOG
\`\`\`
</details>
"
21 changes: 21 additions & 0 deletions Scripts/update-sdk-version.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/bin/bash

# Update SDK revision in project-common.yml

set -euo pipefail

if [ $# -lt 3 ]; then
echo "Usage: $0 <sdk-package> <sdk-swift-ref> <sdk-version>"
echo "Example: $0 BitwardenSdk 2a6609428275c758fcda5383bfb6b3166ec29eda 1.0.0-281-a1611ee"
exit 1
fi

SDK_PACKAGE="$1"
SDK_SWIFT_REF="$2"
SDK_VERSION="$3"
FILE="project-common.yml"

echo "๐Ÿ”ง Updating revision in $FILE..."
yq -i ".packages[\"$SDK_PACKAGE\"].revision = \"$SDK_SWIFT_REF\" | .packages[\"$SDK_PACKAGE\"].revision line_comment = \"$SDK_VERSION\"" "$FILE"
echo "โœ… Updated revision line:"
grep -A 3 "$SDK_PACKAGE:" "$FILE"
Loading