Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
140 changes: 140 additions & 0 deletions .github/actions/composite/updateProtectedBranch/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: Update Protected Branch

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer note: this action is largely the same as the deleted .github/workflows/updateProtectedBranch.yml, so comparing it to that might make it easier to review.

description: Create, approve, and merge a pull request against a protected branch

inputs:
TARGET_BRANCH:
description: The target branch to update. This becomes the base branch of the pull request.
required: true
SOURCE_BRANCH:
description: If updating main, you must also provide a head branch to update main with.
required: false
default: ''
OS_BOTIFY_TOKEN:
description: GitHub token for OSBotify
required: true
GPG_PASSPHRASE:
description: Passphrase used to decrypt GPG key for OSBotify
required: true
SLACK_WEBHOOK:
description: URL of the slack webhook
required: true

runs:
using: composite
steps:
- name: Validate target branch
if: ${{ !contains(fromJSON('["main", "staging", "production"]'), github.event.inputs.TARGET_BRANCH) }}
shell: bash
run: |
echo "Target branch must be one of ['main', 'staging', 'production]"
exit 1

# If updating main, SOURCE_BRANCH must not be empty
- name: Validate source branch
if: github.event.inputs.TARGET_BRANCH == 'main' && github.event.inputs.SOURCE_BRANCH == ''
shell: bash
run: |
echo "Cannot update main branch without specifying a source branch"
exit 1

# If updating staging, the source branch will always be main
# If updating production, the source branch will always be staging
- name: Set source branch
shell: bash
run: |
if [[ ${{ github.event.inputs.TARGET_BRANCH }} == 'staging' ]]; then
echo "SOURCE_BRANCH=main" >> "$GITHUB_ENV"
elif [[ ${{ github.event.inputs.TARGET_BRANCH }} == 'production' ]]; then
echo "SOURCE_BRANCH=staging" >> "$GITHUB_ENV"
else
echo "SOURCE_BRANCH=${{ github.event.inputs.SOURCE_BRANCH }}" >> "$GITHUB_ENV"
fi

- uses: Expensify/App/.github/actions/composite/setupGitForOSBotify@main

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I did an experiment and confirmed that you can use nested composite actions

with:
GPG_PASSPHRASE: ${{ inputs.GPG_PASSPHRASE }}

- name: Checkout source branch
shell: bash
run: git checkout ${{ env.SOURCE_BRANCH }}

- name: Set New Version
shell: bash
run: echo "NEW_VERSION=$(npm run print-version --silent)" >> "$GITHUB_ENV"

- name: Create temporary branch to resolve conflicts
if: ${{ contains(fromJSON('["staging", "production"]'), github.event.inputs.TARGET_BRANCH) }}
shell: bash
run: |
git checkout ${{ github.event.inputs.TARGET_BRANCH }}
BRANCH_NAME=update-${{ github.event.inputs.TARGET_BRANCH }}-from-${{ env.SOURCE_BRANCH }}
git checkout -b "$BRANCH_NAME"
git merge -Xtheirs ${{ env.SOURCE_BRANCH }}
git push --set-upstream origin "$BRANCH_NAME"

- name: Create Pull Request
id: createPullRequest
shell: bash
run: |
gh pr create \
--title "Update version to ${{ env.NEW_VERSION }} on ${{ github.event.inputs.TARGET_BRANCH }}" \
--body "Update version to ${{ env.NEW_VERSION }}" \
--label "automerge" \
--base ${{ github.event.inputs.TARGET_BRANCH }}
sleep 5
echo "::set-output name=PR_NUMBER::$(gh pr view --json 'number' --jq '.number')"
env:
GITHUB_TOKEN: ${{ inputs.OS_BOTIFY_TOKEN }}

- name: Check changed files
if: ${{ github.event.inputs.TARGET_BRANCH == 'main' }}
id: changedFiles
# Version: 3.3.0
uses: umani/changed-files@1d252c611c64289d35243fc37ece7323ea5e93e1
with:
repo-token: ${{ github.token }}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: I did an experiment and confirmed that, even though secrets are not directly available in an action, the full github context, including github.token is available.

pr-number: ${{ steps.createPullRequest.outputs.PR_NUMBER }}

- name: Validate changed files
if: ${{ github.event.inputs.TARGET_BRANCH == 'main' && (steps.changedFiles.outputs.files_updated != 'android/app/build.gradle ios/NewExpensify/Info.plist ios/NewExpensifyTests/Info.plist package-lock.json package.json' || steps.changedFiles.outputs.files_created != '' || steps.changedFiles.outputs.files_deleted != '') }}
shell: bash
run: exit 1

- name: Auto-approve the PR
shell: bash
run: gh pr review --approve
env:
GITHUB_TOKEN: ${{ github.token }}

- name: Check if pull request is mergeable
id: isPullRequestMergeable
uses: Expensify/App/.github/actions/javascript/isPullRequestMergeable@main
with:
GITHUB_TOKEN: ${{ github.token }}
PULL_REQUEST_NUMBER: ${{ steps.createPullRequest.outputs.PR_NUMBER }}

- name: Leave comment if PR is not mergeable
if: ${{ !fromJSON(steps.isPullRequestMergeable.outputs.IS_MERGEABLE) }}
shell: bash
run: |
gh pr comment --body \
":bell: @Expensify/mobile-deployers :bell: - The Update Protected Branch workflow has failed because this PR was not mergable.
If you are the deployer this week, please resolve the error and merge this PR to continue the deploy process."
env:
GITHUB_TOKEN: ${{ inputs.OS_BOTIFY_TOKEN }}

- name: Fail workflow if PR is not mergeable
if: ${{ steps.isPullRequestMergeable.outputs.IS_MERGEABLE == 'false' }}
shell: bash
run: exit 1

- name: Auto-merge the PR
shell: bash
run: gh pr merge ${{ steps.createPullRequest.outputs.PR_NUMBER }} --merge --delete-branch
env:
GITHUB_TOKEN: ${{ inputs.OS_BOTIFY_TOKEN }}

- if: ${{ failure() }}
uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main
with:
SLACK_WEBHOOK: ${{ inputs.SLACK_WEBHOOK }}
10 changes: 6 additions & 4 deletions .github/workflows/createNewVersion.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@ jobs:
git push origin ${{ env.VERSION_BRANCH }}

- name: Update main branch
uses: Expensify/App/.github/actions/javascript/triggerWorkflowAndWait@main
uses: Expensify/App/.github/actions/composite/updateProtectedBranch@main
with:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
WORKFLOW: updateProtectedBranch.yml
INPUTS: '{ "TARGET_BRANCH": "main", "SOURCE_BRANCH": "${{ env.VERSION_BRANCH }}" }'
TARGET_BRANCH: main
SOURCE_BRANCH: ${{ env.VERSION_BRANCH }}
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

- if: ${{ failure() }}
uses: Expensify/App/.github/actions/composite/announceFailedWorkflowInSlack@main
Expand Down
18 changes: 10 additions & 8 deletions .github/workflows/finishReleaseCycle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,11 +62,12 @@ jobs:
token: ${{ secrets.OS_BOTIFY_TOKEN }}

- name: Update production branch
uses: Expensify/App/.github/actions/javascript/triggerWorkflowAndWait@main
uses: Expensify/App/.github/actions/composite/updateProtectedBranch@main
with:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
WORKFLOW: updateProtectedBranch.yml
INPUTS: '{ "TARGET_BRANCH": "production" }'
TARGET_BRANCH: production
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

# Deploy deferred PRs to staging and create a new StagingDeployCash for the next release cycle.
createNewStagingDeployCash:
Expand Down Expand Up @@ -95,11 +96,12 @@ jobs:
INPUTS: '{ "SEMVER_LEVEL": "PATCH" }'

- name: Update staging branch to trigger staging deploy
uses: Expensify/App/.github/actions/javascript/triggerWorkflowAndWait@main
uses: Expensify/App/.github/actions/composite/updateProtectedBranch@main
with:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
WORKFLOW: updateProtectedBranch.yml
INPUTS: '{ "TARGET_BRANCH": "staging" }'
TARGET_BRANCH: staging
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

- name: Pull staging to get the new version
run: |
Expand Down
9 changes: 5 additions & 4 deletions .github/workflows/preDeploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,12 @@ jobs:

- name: Update staging branch from main
if: ${{ !fromJSON(needs.chooseDeployActions.outputs.isStagingDeployLocked) }}
uses: Expensify/App/.github/actions/javascript/triggerWorkflowAndWait@main
uses: Expensify/App/.github/actions/composite/updateProtectedBranch@main
with:
GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
WORKFLOW: updateProtectedBranch.yml
INPUTS: '{ "TARGET_BRANCH": "staging" }'
TARGET_BRANCH: staging
OS_BOTIFY_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }}
GPG_PASSPHRASE: ${{ secrets.LARGE_SECRET_PASSPHRASE }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

- name: Determine if this pull request will be cherry-picked
run: echo "DO_CHERRY_PICK=${{ fromJSON(needs.chooseDeployActions.outputs.isStagingDeployLocked) && fromJSON(needs.chooseDeployActions.outputs.shouldCherryPick) }}" >> "$GITHUB_ENV"
Expand Down
129 changes: 0 additions & 129 deletions .github/workflows/updateProtectedBranch.yml

This file was deleted.