From a2d32a2e41144ba8e112aa3d8d1865989544b81a Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Tue, 3 Sep 2024 18:44:50 -0700 Subject: [PATCH 1/6] contents read --- .github/workflows/required-reviewers-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/required-reviewers-release.yml b/.github/workflows/required-reviewers-release.yml index df4021b80241..6f1a33d74c16 100644 --- a/.github/workflows/required-reviewers-release.yml +++ b/.github/workflows/required-reviewers-release.yml @@ -30,6 +30,7 @@ on: permissions: pull-requests: read + contents: read jobs: check_branch: From 6734551c8f190dc5bf0fed562f8417e8ed2727f9 Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Tue, 3 Sep 2024 18:47:34 -0700 Subject: [PATCH 2/6] pr-target --- .github/workflows/required-reviewers-release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/required-reviewers-release.yml b/.github/workflows/required-reviewers-release.yml index 6f1a33d74c16..9378cfab179f 100644 --- a/.github/workflows/required-reviewers-release.yml +++ b/.github/workflows/required-reviewers-release.yml @@ -4,7 +4,7 @@ name: Required release approval on: - pull_request: + pull_request_target: types: # This is triggered when the PR is opened. This is not strictly needed since the PR approval state is really # what's evaluated. However, running the job on PR open causes an immediate failure which will make it clearer to @@ -30,7 +30,6 @@ on: permissions: pull-requests: read - contents: read jobs: check_branch: From bf5b28a2f5546109220d1927b331b1fc5b8bc651 Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Wed, 4 Sep 2024 11:11:04 -0700 Subject: [PATCH 3/6] split workflows --- .github/CODEOWNERS | 6 +- .github/workflows/release-approval.yml | 137 ++++++++++++++++++ .github/workflows/release-branches.yml | 80 ++++++++++ .../workflows/required-reviewers-release.yml | 131 ----------------- 4 files changed, 221 insertions(+), 133 deletions(-) create mode 100644 .github/workflows/release-approval.yml create mode 100644 .github/workflows/release-branches.yml delete mode 100644 .github/workflows/required-reviewers-release.yml diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b0381ee1b69e..793b7691172d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -34,8 +34,10 @@ /.github/CODEOWNERS @microsoft/fluid-cr-api -# Changes to this workflow require approval from the Release Approvers team -/.github/workflows/required-reviewers-release.yml @microsoft/FluidFramework-ReleaseApprovers +# Changes to these workflows require approval from the Release Approvers team +# Will be re-enabled once workflows are stable. AB#14288 +# /.github/workflows/release-approval.yml @microsoft/FluidFramework-ReleaseApprovers +# /.github/workflows/release-branches.yml @microsoft/FluidFramework-ReleaseApprovers # ID compressor source /packages/runtime/id-compressor/src @microsoft/fluid-cr-id-compressor diff --git a/.github/workflows/release-approval.yml b/.github/workflows/release-approval.yml new file mode 100644 index 000000000000..e56bb4a1f336 --- /dev/null +++ b/.github/workflows/release-approval.yml @@ -0,0 +1,137 @@ +# release-approval.yml +# +# This workflow checks that a PR has been reviewed by a member of FluidFramework-ReleaseApprovers. +# +# This workflow is normally triggered by the completion of the release-branches workflow. However, it can also be run +# manually using the GitHub UI and providing a PR number. + +name: release-approval + +on: + workflow_run: + # Workflow is typically triggered by the completion of the release-branches workflow. + workflows: [release-branches] + # Only workflow runs from these branches will trigger this workflow. + branches: + - release/client/** + - release/server/** + - test/release/** + + # The workflow can be triggered manually in the GitHub UI. + workflow_dispatch: + inputs: + pr: + description: "PR number on which to run approval checks" + required: true + +permissions: + actions: read + pull-requests: read + +jobs: + on-failure: + name: Check upstream workflow status + if: github.event_name == "workflow_run" && github.event.workflow_run.conclusion == "failure" + runs-on: ubuntu-latest + steps: + - run: echo "The triggering workflow failed" + + metadata: + name: Get PR metadata + runs-on: ubuntu-latest + outputs: + pr_num: ${{ steps.workflow_run_load_pr.outputs.pr_num || steps.workflow_dispatch_load_pr.outputs.pr_num }} + is_release_branch: ${{ steps.workflow_run_load_pr.outputs.is_release_branch || steps.workflow_dispatch_load_pr.outputs.is_release_branch }} + steps: + + ### These steps run on workflow_run event only ### + - name: Download metadata + if: github.event_name == "workflow_run" + # release notes: https://github.com/dawidd6/action-download-artifact/releases/tag/v6 + uses: dawidd6/action-download-artifact@bd10f381a96414ce2b13a11bfa89902ba7cea07f # ratchet:dawidd6/action-download-artifact@v6 + with: + workflow: release-branches.yml + # workflow_conclusion: completed + run_id: ${{ github.event.workflow_run.id }} + name: release-branch-pr-metadata + path: ./results + + - name: "workflow_run: Load PR number" + id: workflow_run_load_pr + if: github.event_name == "workflow_run" + working-directory: ./results + run: echo "pr_num=$(cat pr)" >> $GITHUB_OUTPUT + + - name: "workflow_run: Load is_release_branch" + id: workflow_run_is_release_branch + if: github.event_name == "workflow_run" + working-directory: ./results + run: echo "is_release_branch=$(cat is_release_branch)" >> $GITHUB_OUTPUT + + ### These steps run on workflow_dispatch event only ### + - name: "workflow_dispatch: Load PR number" + id: workflow_dispatch_load_pr + if: github.event_name == "workflow_dispatch" + run: echo "pr_num=${{ github.event.inputs.pr }}" >> $GITHUB_OUTPUT + + - name: "workflow_dispatch: Load is_release_branch" + id: workflow_dispatch_is_release_branch + if: github.event_name == "workflow_dispatch" + run: echo "is_release_branch=true" >> $GITHUB_OUTPUT + + check_approval: + name: Check PR approval + if: needs.metadata.outputs.is_release_branch == 'true' + needs: metadata + runs-on: ubuntu-latest + steps: + # release notes: https://github.com/actions/checkout/releases/tag/v4.1.7 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # ratchet:actions/checkout@v4 + with: + # The default ref when triggered by the workflow_run event is the default branch -- main + # This means the build-tools from the main branch will always be used. + persist-credentials: false + submodules: false + + # install and configure node, pnpm and the changeset tools + # release notes: https://github.com/pnpm/action-setup/releases/tag/v4.0.0 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # ratchet:pnpm/action-setup@v4 + + # release notes: https://github.com/actions/setup-node/releases/tag/v4.0.3 + - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # ratchet:actions/setup-node@v4 + with: + node-version-file: .nvmrc + cache: "pnpm" + cache-dependency-path: pnpm-lock.yaml + + - name: Install Fluid build tools + continue-on-error: true + run: | + cd build-tools + pnpm install --frozen-lockfile + pnpm run build:compile + # We want flub available to call, so we run npm link in the build-cli package, which creates shims that are avilable on the PATH + # Use npm link instead of pnpm link because it handles bins better + cd packages/build-cli + npm link + + - name: Check build-tools installation + run: | + # Info for debugging + which flub + flub --help + flub commands + + - name: Check PR approval + env: + # The standard token doesn't have org:read permissions, and that scope can't be added using permissions in + # the workflow. + # GITHUB_TOKEN: ${{ secrets.ORGANIZATION_READ_PAT }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # This command will fail with an error if the PR is not approved, which + # will in turn cause the CI job to fail. + flub check prApproval \ + --pr ${{ needs.metadata.outputs.pr_num }} \ + --repo ${{ github.repository }} \ + --team FluidFramework-ReleaseApprovers diff --git a/.github/workflows/release-branches.yml b/.github/workflows/release-branches.yml new file mode 100644 index 000000000000..d4685d76cb80 --- /dev/null +++ b/.github/workflows/release-branches.yml @@ -0,0 +1,80 @@ +# release-branches.yml +# +# Checks if a PR is targeting a client or server release branch or not, and uploads a CI artifact containing the +# results, along with the PR number. This allows downstream workflows, such as release-approval, to be triggered by the +# completion of this workflow and take further action based on the target branch. + +name: release-branches +on: + pull_request: + types: + # This is triggered when the PR is opened. This is not strictly needed since the PR approval state is really + # what's evaluated. However, running the job on PR open causes an immediate failure which will make it clearer to + # the PR author what they need to do to unblock the merge. + - opened + + # This is triggered when the PR branch has new commits pushed to it. + - synchronize + + # This is triggered when the base branch changes; handles the case where you open a PR against one branch + # then change the base branch to a release branch. + - edited + branches: + - release/client/** + - release/server/** + - test/release/** + + # This workflow needs to run on review changes because it evaluates the review state. + pull_request_review: + types: + - submitted + - dismissed + +permissions: + pull-requests: read + +jobs: + check_branch: + name: Check target branch + runs-on: ubuntu-latest + outputs: + # This output will be set to true if the target branch is a release branch; false otherwise. + is_release_branch: ${{ steps.is-release-branch.outputs.is_release_branch || steps.not-release-branch.outputs.is_release_branch }} + steps: + - name: Target is a release branch + id: is-release-branch + if: | + startsWith(github.event.pull_request.base.ref, 'release/client/') || + startsWith(github.event.pull_request.base.ref, 'release/server/') || + startsWith(github.event.pull_request.base.ref, 'test/release/') + run: | + echo "is_release_branch=true" >> $GITHUB_OUTPUT + echo ":ship: Release branch detected" >> $GITHUB_STEP_SUMMARY + - name: Target is not a release branch + id: not-release-branch + if: | + !(startsWith(github.event.pull_request.base.ref, 'release/client/') || + startsWith(github.event.pull_request.base.ref, 'release/server/') || + startsWith(github.event.pull_request.base.ref, 'test/release/')) + run: | + echo "is_release_branch=false" >> $GITHUB_OUTPUT + echo ":no_entry_sign: No release branch detected" >> $GITHUB_STEP_SUMMARY + + save_metadata: + name: Save PR details + needs: check_branch + runs-on: ubuntu-latest + steps: + - name: Save PR number + run: echo ${{ github.event.pull_request.number }} > ./results/pr + + - name: Save is_release_branch + run: echo ${{ needs.check_branch.outputs.is_release_branch }} > ./results/is_release_branch + + - name: Upload results artifact + # release notes: https://github.com/actions/upload-artifact/releases/tag/v4.4.0 + uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # ratchet:actions/upload-artifact@v4.4.0 + with: + name: release-branch-pr-metadata + path: ./results + retention-days: 3 diff --git a/.github/workflows/required-reviewers-release.yml b/.github/workflows/required-reviewers-release.yml deleted file mode 100644 index 9378cfab179f..000000000000 --- a/.github/workflows/required-reviewers-release.yml +++ /dev/null @@ -1,131 +0,0 @@ -# required-reviewers-release.yml -# Checks if a release branch PR is approved by a member of FluidFramework-ReleaseApprovers. PRs targeting non-release -# branches are skipped, and - -name: Required release approval -on: - pull_request_target: - types: - # This is triggered when the PR is opened. This is not strictly needed since the PR approval state is really - # what's evaluated. However, running the job on PR open causes an immediate failure which will make it clearer to - # the PR author what they need to do to unblock the merge. - - opened - - # This is triggered when the base branch changes; handles the case where you open a PR against one branch - # then change the base branch to a release branch. - - edited - - # This is triggered when the PR branch has new commits pushed to it. - - synchronize - branches: - - release/client/** - - release/server/** - - test/release/** - - # This workflow needs to run on review changes because it evaluates the review state. - pull_request_review: - types: - - submitted - - dismissed - -permissions: - pull-requests: read - -jobs: - check_branch: - name: Check target branch - runs-on: ubuntu-latest - outputs: - # This output will be set to true if the target branch is a release branch; false otherwise. - is_release_branch: ${{ steps.is-release-branch.outputs.is_release_branch || steps.not-release-branch.outputs.is_release_branch }} - steps: - - name: Target is a release branch - id: is-release-branch - if: | - startsWith(github.event.pull_request.base.ref, 'release/client/') || - startsWith(github.event.pull_request.base.ref, 'release/server/') || - startsWith(github.event.pull_request.base.ref, 'test/release/') - run: | - echo "is_release_branch=true" >> $GITHUB_OUTPUT - echo ":ship: Release branch detected" >> $GITHUB_STEP_SUMMARY - - name: Target is not a release branch - id: not-release-branch - if: | - !(startsWith(github.event.pull_request.base.ref, 'release/client/') || - startsWith(github.event.pull_request.base.ref, 'release/server/') || - startsWith(github.event.pull_request.base.ref, 'test/release/')) - run: | - echo "is_release_branch=false" >> $GITHUB_OUTPUT - echo ":no_entry_sign: No release branch detected" >> $GITHUB_STEP_SUMMARY - - not_release_branch: - name: Check approval requirements - needs: check_branch - runs-on: ubuntu-latest - steps: - - name: Approval is required - if: needs.check_branch.outputs.is_release_branch == 'true' - run: | - echo ":vertical_traffic_light: Approval is required" >> $GITHUB_STEP_SUMMARY - - name: No special approval requirements - if: needs.check_branch.outputs.is_release_branch != 'true' - run: | - echo ":white_check_mark: No special approval required!" >> $GITHUB_STEP_SUMMARY - - check_approval: - name: Approved by required reviewers - needs: [check_branch, not_release_branch] - if: needs.check_branch.outputs.is_release_branch == 'true' - runs-on: ubuntu-latest - steps: - # release notes: https://github.com/actions/checkout/releases/tag/v4.1.7 - - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # ratchet:actions/checkout@v4 - with: - persist-credentials: false - submodules: false - # The pull_request_review event's default ref is the source branch - the one from the PR author. We don't want - # to build build-tools from that branch, though, because doing so would be a security risk. So instead, we - # check out the repo at the base ref. - ref: ${{ github.event.pull_request.base.ref }} - - # install and configure node, pnpm and the changeset tools - # release notes: https://github.com/pnpm/action-setup/releases/tag/v4.0.0 - - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # ratchet:pnpm/action-setup@v4 - - # release notes: https://github.com/actions/setup-node/releases/tag/v4.0.3 - - uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # ratchet:actions/setup-node@v4 - with: - node-version-file: .nvmrc - cache: "pnpm" - cache-dependency-path: pnpm-lock.yaml - - - name: Install Fluid build tools - continue-on-error: true - run: | - cd build-tools - pnpm install --frozen-lockfile - pnpm run build:compile - # We want flub available to call, so we run npm link in the build-cli package, which creates shims that are avilable on the PATH - # Use npm link instead of pnpm link because it handles bins better - cd packages/build-cli - npm link - - - name: Check build-tools installation - run: | - # Info for debugging - which flub - flub --help - flub commands - - - name: Check PR approval - env: - # The standard token doesn't have org:read permissions, and that scope can't be added using permissions in - # the workflow. - GITHUB_TOKEN: ${{ secrets.ORGANIZATION_READ_PAT }} - run: | - # This command will fail with an error if the PR is not approved, which - # will in turn cause the CI job to fail. - flub check prApproval \ - --pr ${{ github.event.pull_request.number }} \ - --repo ${{ github.repository }} \ - --team FluidFramework-ReleaseApprovers From 54581ca8ace6aeeafda6ae34ef90546719cf4c3b Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Wed, 4 Sep 2024 11:19:05 -0700 Subject: [PATCH 4/6] updates --- .github/workflows/release-approval.yml | 6 +++--- .github/workflows/release-branches.yml | 11 +++++++---- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release-approval.yml b/.github/workflows/release-approval.yml index e56bb4a1f336..18874b0f83c8 100644 --- a/.github/workflows/release-approval.yml +++ b/.github/workflows/release-approval.yml @@ -54,18 +54,18 @@ jobs: # workflow_conclusion: completed run_id: ${{ github.event.workflow_run.id }} name: release-branch-pr-metadata - path: ./results + path: ./artifacts - name: "workflow_run: Load PR number" id: workflow_run_load_pr if: github.event_name == "workflow_run" - working-directory: ./results + working-directory: ./artifacts run: echo "pr_num=$(cat pr)" >> $GITHUB_OUTPUT - name: "workflow_run: Load is_release_branch" id: workflow_run_is_release_branch if: github.event_name == "workflow_run" - working-directory: ./results + working-directory: ./artifacts run: echo "is_release_branch=$(cat is_release_branch)" >> $GITHUB_OUTPUT ### These steps run on workflow_dispatch event only ### diff --git a/.github/workflows/release-branches.yml b/.github/workflows/release-branches.yml index d4685d76cb80..b25e0b32344c 100644 --- a/.github/workflows/release-branches.yml +++ b/.github/workflows/release-branches.yml @@ -65,16 +65,19 @@ jobs: needs: check_branch runs-on: ubuntu-latest steps: + - name: Create artifacts folder + run: mkdir -p ./artifacts + - name: Save PR number - run: echo ${{ github.event.pull_request.number }} > ./results/pr + run: echo ${{ github.event.pull_request.number }} > ./artifacts/pr - name: Save is_release_branch - run: echo ${{ needs.check_branch.outputs.is_release_branch }} > ./results/is_release_branch + run: echo ${{ needs.check_branch.outputs.is_release_branch }} > ./artifacts/is_release_branch - - name: Upload results artifact + - name: Upload artifact # release notes: https://github.com/actions/upload-artifact/releases/tag/v4.4.0 uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # ratchet:actions/upload-artifact@v4.4.0 with: name: release-branch-pr-metadata - path: ./results + path: ./artifacts retention-days: 3 From 7b650cde2628c01537225afe7c3828e4c2344f26 Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Wed, 4 Sep 2024 11:23:53 -0700 Subject: [PATCH 5/6] dummy edit --- .releaseGroup | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.releaseGroup b/.releaseGroup index 0a7c21426677..4282f8256281 100644 --- a/.releaseGroup +++ b/.releaseGroup @@ -1 +1,3 @@ The presence of this file in a directory indicates it is the root of a release group. + +edit From 3ba3492ce2928797dd069ecd6531ad601b438a4a Mon Sep 17 00:00:00 2001 From: Tyler Butler Date: Wed, 4 Sep 2024 11:37:38 -0700 Subject: [PATCH 6/6] Apply suggestions from code review --- .releaseGroup | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.releaseGroup b/.releaseGroup index 4282f8256281..5e0fa0780396 100644 --- a/.releaseGroup +++ b/.releaseGroup @@ -1,3 +1,3 @@ The presence of this file in a directory indicates it is the root of a release group. -edit +edited