diff --git a/.github/workflows/README.md b/.github/workflows/README.md index be6efb918fb6..3a8477b607de 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -48,6 +48,7 @@ We've found that the best way to avoid this pitfall is to always wrap any refere 1. Review all modifications to our workflows with extra scrutiny, it is important to get it correct the first time. 1. Test workflow changes in your own public fork, for example: https://github.com/Andrew-Test-Org/Public-Test-Repo 1. Only trusted users will be allowed write access to the repository, however, it's good to add logic checks in actions to prevent human error. +1. Do not add repo secrets to the environment at the workflow or job level. Only add them to the environment at the step level. ## Further Reading 📖 1. https://securitylab.github.com/research/github-actions-preventing-pwn-requests @@ -57,23 +58,23 @@ We've found that the best way to avoid this pitfall is to always wrap any refere The GitHub workflows require a large list of secrets to deploy, notify and test the code: 1. `LARGE_SECRET_PASSPHRASE` - decrypts secrets stored in various encrypted files stored in GitHub repository. To create updated versions of these encrypted files, refer to steps 1-4 of [this encrypted secrets help page](https://docs.github.com/en/actions/reference/encrypted-secrets#limits-for-secrets) using the `LARGE_SECRET_PASSPHRASE`. 1. `android/app/my-upload-key.keystore.gpg` - 2. `android/app/android-fastlane-json-key.json.gpg` - 3. `ios/chat_expensify_appstore.mobileprovision` - 4. `ios/Certificates.p12.gpg` -2. `SLACK_WEBHOOK` - Sends Slack notifications via Slack WebHook https://expensify.slack.com/services/B01AX48D7MM -3. `OS_BOTIFY_TOKEN` - Personal access token for @OSBotify user in GitHub -4. `CLA_BOTIFY_TOKEN` - Personal access token for @CLABotify user in GitHub -5. `CSC_LINK` - Required to be set for desktop code signing: https://www.electron.build/code-signing.html#travis-appveyor-and-other-ci-servers -6. `CSC_KEY_PASSWORD` - Required to be set for desktop code signing: https://www.electron.build/code-signing.html#travis-appveyor-and-other-ci-servers -7. `APPLE_ID` - Required for notarizing desktop code in `desktop/notarize.js` -8. `APPLE_ID_PASSWORD` - Required for notarizing desktop code in `desktop/notarize.js` -9. `AWS_ACCESS_KEY_ID` - Required for hosting website and desktop compiled code -10. `AWS_SECRET_ACCESS_KEY` - Required for hosting website and desktop compiled code -11. `CLOUDFLARE_TOKEN` - Required for hosting website -12. `APPLE_CONTACT_EMAIL` - Email used for contact between Expensify and Apple for https://appstoreconnect.apple.com/ -13. `APPLE_CONTACT_PHONE` - Phone number used for contact between Expensify and Apple for https://appstoreconnect.apple.com/ -14. `APPLE_DEMO_EMAIL` - Demo account email used for https://appstoreconnect.apple.com/ -15. `APPLE_DEMO_PASSWORD` - Demo account password used for https://appstoreconnect.apple.com/ + 1. `android/app/android-fastlane-json-key.json.gpg` + 1. `ios/chat_expensify_appstore.mobileprovision` + 1. `ios/Certificates.p12.gpg` +1. `SLACK_WEBHOOK` - Sends Slack notifications via Slack WebHook https://expensify.slack.com/services/B01AX48D7MM +1. `OS_BOTIFY_TOKEN` - Personal access token for @OSBotify user in GitHub +1. `CLA_BOTIFY_TOKEN` - Personal access token for @CLABotify user in GitHub +1. `CSC_LINK` - Required to be set for desktop code signing: https://www.electron.build/code-signing.html#travis-appveyor-and-other-ci-servers +1. `CSC_KEY_PASSWORD` - Required to be set for desktop code signing: https://www.electron.build/code-signing.html#travis-appveyor-and-other-ci-servers +1. `APPLE_ID` - Required for notarizing desktop code in `desktop/notarize.js` +1. `APPLE_ID_PASSWORD` - Required for notarizing desktop code in `desktop/notarize.js` +1. `AWS_ACCESS_KEY_ID` - Required for hosting website and desktop compiled code +1. `AWS_SECRET_ACCESS_KEY` - Required for hosting website and desktop compiled code +1. `CLOUDFLARE_TOKEN` - Required for hosting website +1. `APPLE_CONTACT_EMAIL` - Email used for contact between Expensify and Apple for https://appstoreconnect.apple.com/ +1. `APPLE_CONTACT_PHONE` - Phone number used for contact between Expensify and Apple for https://appstoreconnect.apple.com/ +1. `APPLE_DEMO_EMAIL` - Demo account email used for https://appstoreconnect.apple.com/ +1. `APPLE_DEMO_PASSWORD` - Demo account password used for https://appstoreconnect.apple.com/ ## Actions @@ -81,9 +82,9 @@ All these _workflows_ are comprised of atomic _actions_. Most of the time, we ca All our actions are stored in the neighboring directory [`.github/actions`](https://github.com/Expensify/App/tree/main/.github/actions). Each action is a module comprised of three parts: -1) An [action metadata file](https://docs.github.com/en/free-pro-team@latest/actions/creating-actions/creating-a-javascript-action#creating-an-action-metadata-file) called `action.yml`. This describes the action, gives it a name, and defines its inputs and outputs. -2) A Node.js script, whose name matches the module. This is where you can implement the custom logic for your action. -3) A compiled file called index.js. This is a compiled output of the file from (2) and should _NEVER_ be directly modified. +1. An [action metadata file](https://docs.github.com/en/free-pro-team@latest/actions/creating-actions/creating-a-javascript-action#creating-an-action-metadata-file) called `action.yml`. This describes the action, gives it a name, and defines its inputs and outputs. +1. A Node.js script, whose name matches the module. This is where you can implement the custom logic for your action. +1. A compiled file called index.js. This is a compiled output of the file from (2) and should _NEVER_ be directly modified. ### Why do actions need to be compiled? diff --git a/.github/workflows/cherryPick.yml b/.github/workflows/cherryPick.yml index 373ecbe259ab..b39d6943f0f1 100644 --- a/.github/workflows/cherryPick.yml +++ b/.github/workflows/cherryPick.yml @@ -142,15 +142,15 @@ jobs: - name: Create Pull Request id: createPullRequest - # Version: 2.4.3 - uses: repo-sync/pull-request@65194d8015be7624d231796ddee1cd52a5023cb3 - with: - source_branch: ${{ github.actor }}-cherry-pick-staging-${{ github.event.inputs.PULL_REQUEST_NUMBER }} - destination_branch: staging - github_token: ${{ secrets.OS_BOTIFY_TOKEN }} - pr_title: '🍒 Cherry pick PR #${{ github.event.inputs.PULL_REQUEST_NUMBER }} to staging 🍒' - pr_body: '🍒 Cherry pick https://github.com/Expensify/App/pull/${{ github.event.inputs.PULL_REQUEST_NUMBER }} to staging 🍒' - pr_label: automerge + run: | + gh pr create \ + --title "🍒 Cherry pick PR #${{ github.event.inputs.PULL_REQUEST_NUMBER }} to staging 🍒" \ + --body "🍒 Cherry pick https://github.com/Expensify/App/pull/${{ github.event.inputs.PULL_REQUEST_NUMBER }} to staging 🍒" \ + --label "automerge" \ + --base "staging" + echo "::set-output name=PR_NUMBER::$(gh pr view --json 'number' --jq '.number')" + env: + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - name: Check if ShortVersionString is up to date id: isShortVersionStringUpdated @@ -158,51 +158,42 @@ jobs: - name: Auto-assign PR if there are merge conflicts or if the bundle versions are mismatched if: ${{ !fromJSON(steps.cherryPick.outputs.SHOULD_AUTOMERGE) || !fromJSON(steps.isShortVersionStringUpdated.outputs.BUNDLE_VERSIONS_MATCH) }} - uses: actions-ecosystem/action-add-labels@a8ae047fee0ca28235f9764e1c478d2136dc15c1 - with: - number: ${{ steps.createPullRequest.outputs.pr_number }} - labels: | - Engineering - Hourly + run: gh pr edit --add-label "Engineering,Hourly" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Assign the PR to the deployer if: ${{ !fromJSON(steps.cherryPick.outputs.SHOULD_AUTOMERGE) }} - uses: actions-ecosystem/action-add-assignees@a73fcabd82d847c5e7433fcfdd58ef9f7e8a3993 - with: - number: ${{ steps.createPullRequest.outputs.pr_number }} - github_token: ${{ secrets.GITHUB_TOKEN }} - assignees: ${{ steps.getCPMergeCommit.outputs.MERGE_ACTOR }} + run: gh pr edit --add-assignee ${{ steps.getCPMergeCommit.outputs.MERGE_ACTOR }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: If PR has merge conflicts, comment with instructions for assignee if: ${{ !fromJSON(steps.cherryPick.outputs.SHOULD_AUTOMERGE) }} - uses: actions-ecosystem/action-create-comment@cd098164398331c50e7dfdd0dfa1b564a1873fac - with: - github_token: ${{ secrets.OS_BOTIFY_TOKEN }} - number: ${{ steps.createPullRequest.outputs.pr_number }} - body: | - This pull request has merge conflicts and can not be automatically merged. :disappointed: - Please manually resolve the conflicts, push your changes, and then request another reviewer to review and merge. - **Important:** There may be conflicts that GitHub is not able to detect, so please _carefully_ review this pull request before approving. + run: | + gh pr comment --body \ + "This pull request has merge conflicts and can not be automatically merged. :disappointed: + Please manually resolve the conflicts, push your changes, and then request another reviewer to review and merge. + **Important:** There may be conflicts that GitHub is not able to detect, so please _carefully_ review this pull request before approving." + env: + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - name: If PR has a bundle version mismatch, comment with the instructions for assignee if: ${{ !fromJSON(steps.isShortVersionStringUpdated.outputs.BUNDLE_VERSIONS_MATCH) }} - uses: actions-ecosystem/action-create-comment@cd098164398331c50e7dfdd0dfa1b564a1873fac - with: - github_token: ${{ secrets.OS_BOTIFY_TOKEN }} - number: ${{ steps.createPullRequest.outputs.pr_number }} - body: | - The CFBundleShortVersionString value in this PR is not compatible with the CFBundleVersion, so cherry picking it will result in an iOS deploy failure. - Please manually resolve the mismatch, push your changes, and then request another reviewer to review and merge. - **Important:** This mismatch can be caused by a failed Update Protected Branch workflow followed by a manual CP, but please confirm the cause of the mismatch before updating any version numbers. + run: | + gh pr comment --body \ + "The CFBundleShortVersionString value in this PR is not compatible with the CFBundleVersion, so cherry picking it will result in an iOS deploy failure. + Please manually resolve the mismatch, push your changes, and then request another reviewer to review and merge. + **Important:** This mismatch can be caused by a failed Update Protected Branch workflow followed by a manual CP, but please confirm the cause of the mismatch before updating any version numbers." + env: + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - - name: Check for an auto approve + - name: Auto-approve the PR # Important: only auto-approve if there was no merge conflict! if: ${{ fromJSON(steps.cherryPick.outputs.SHOULD_AUTOMERGE) }} - # Version: 2.0.0 - uses: hmarr/auto-approve-action@6a9ec7556f0a7fa5b49527a1eea4878b8a22d2e0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - pull-request-number: ${{ steps.createPullRequest.outputs.pr_number }} + run: gh pr review --approve + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Check if pull request is mergeable id: isPullRequestMergeable @@ -211,14 +202,12 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PULL_REQUEST_NUMBER: ${{ steps.createPullRequest.outputs.pr_number }} - - name: Check for an auto merge + - name: Auto-merge the PR # Important: only auto-merge if there was no merge conflict! if: ${{ fromJSON(steps.cherryPick.outputs.SHOULD_AUTOMERGE) && fromJSON(steps.isPullRequestMergeable.outputs.IS_MERGEABLE) }} - # Version: 0.12.0 - uses: pascalgn/automerge-action@39d831e1bb389bd242626bc25d4060064a97181c + run: gh pr merge --merge --delete-branch env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - PULL_REQUEST: ${{ steps.createPullRequest.outputs.pr_number }} # Create a local git tag on staging so that GitUtils.getPullRequestsMergedBetween can use `git log` to generate a # list of pull requests that were merged between this version tag and another. diff --git a/.github/workflows/updateProtectedBranch.yml b/.github/workflows/updateProtectedBranch.yml index 61f5aeada49b..40f00fb63cd0 100644 --- a/.github/workflows/updateProtectedBranch.yml +++ b/.github/workflows/updateProtectedBranch.yml @@ -77,19 +77,18 @@ jobs: git checkout -b update-${{ github.event.inputs.TARGET_BRANCH }}-from-${{ env.SOURCE_BRANCH }} git merge -Xtheirs ${{ env.SOURCE_BRANCH }} git push --set-upstream origin update-${{ github.event.inputs.TARGET_BRANCH }}-from-${{ env.SOURCE_BRANCH }} - echo "SOURCE_BRANCH=update-${{ github.event.inputs.TARGET_BRANCH }}-from-${{ env.SOURCE_BRANCH }}" >> "$GITHUB_ENV" - name: Create Pull Request id: createPullRequest - # Version: 2.4.3 - uses: repo-sync/pull-request@65194d8015be7624d231796ddee1cd52a5023cb3 - with: - source_branch: ${{ env.SOURCE_BRANCH }} - destination_branch: ${{ github.event.inputs.TARGET_BRANCH }} - github_token: ${{ secrets.OS_BOTIFY_TOKEN }} - pr_title: Update version to ${{ env.NEW_VERSION }} on ${{ github.event.inputs.TARGET_BRANCH }} - pr_body: Update version to ${{ env.NEW_VERSION }} - pr_label: automerge + 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 }} + echo "::set-output name=PR_NUMBER::$(gh pr view --json 'number' --jq '.number')" + env: + GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - name: Check changed files if: ${{ github.event.inputs.TARGET_BRANCH == 'main' }} @@ -98,46 +97,41 @@ jobs: uses: umani/changed-files@1d252c611c64289d35243fc37ece7323ea5e93e1 with: repo-token: ${{ secrets.GITHUB_TOKEN }} - pr-number: ${{ steps.createPullRequest.outputs.pr_number }} + 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 != '') }} run: exit 1 - - name: Check for an auto approve - # Version: 2.0.0 - uses: hmarr/auto-approve-action@6a9ec7556f0a7fa5b49527a1eea4878b8a22d2e0 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - pull-request-number: ${{ steps.createPullRequest.outputs.pr_number }} + - name: Auto-approve the PR + run: gh pr review --approve + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Check if pull request is mergeable id: isPullRequestMergeable uses: Expensify/App/.github/actions/isPullRequestMergeable@main with: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PULL_REQUEST_NUMBER: ${{ steps.createPullRequest.outputs.pr_number }} + PULL_REQUEST_NUMBER: ${{ steps.createPullRequest.outputs.PR_NUMBER }} - name: Leave comment if PR is not mergeable if: ${{ !fromJSON(steps.isPullRequestMergeable.outputs.IS_MERGEABLE) }} - uses: actions-ecosystem/action-create-comment@cd098164398331c50e7dfdd0dfa1b564a1873fac - with: - github_token: ${{ secrets.OS_BOTIFY_TOKEN }} - number: ${{ steps.createPullRequest.outputs.pr_number }} - 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. + 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: ${{ secrets.OS_BOTIFY_TOKEN }} - name: Fail workflow if PR is not mergeable if: ${{ steps.isPullRequestMergeable.outputs.IS_MERGEABLE == 'false' }} run: exit 1 - - name: Check for an auto merge - # Version: 0.12.0 - uses: pascalgn/automerge-action@39d831e1bb389bd242626bc25d4060064a97181c + - name: Auto-merge the PR + run: gh pr merge --merge --delete-branch env: GITHUB_TOKEN: ${{ secrets.OS_BOTIFY_TOKEN }} - PULL_REQUEST: ${{ steps.createPullRequest.outputs.pr_number }} # This Slack step is duplicated in all workflows, if you make a change to this step, make sure to update all # the other workflows with the same change