From 0c1c6e9ada090ac642f30f6045dc661b2a7199f1 Mon Sep 17 00:00:00 2001 From: George Joseph Date: Tue, 17 Oct 2023 06:59:43 -0600 Subject: [PATCH] .github: New PR Submit workflows The workflows that get triggered when PRs are submitted or updated have been replaced with ones that are more secure and have a higher level of parallelism. --- .github/workflows/PRSubmitActions.yml | 148 ++++++++++++++++++++++++++ .github/workflows/PRSubmitTests.yml | 113 ++++++++++++++++++++ 2 files changed, 261 insertions(+) create mode 100644 .github/workflows/PRSubmitActions.yml create mode 100644 .github/workflows/PRSubmitTests.yml diff --git a/.github/workflows/PRSubmitActions.yml b/.github/workflows/PRSubmitActions.yml new file mode 100644 index 0000000000..fb58f19015 --- /dev/null +++ b/.github/workflows/PRSubmitActions.yml @@ -0,0 +1,148 @@ +name: PRSubmitActions +run-name: "PRSubmitActions: Test ${{github.event.action}}" +on: + workflow_run: + workflows: [PRSubmitTests] + types: + - requested + - completed +env: + ACTION: ${{ github.event.action }} + CONCLUSION: ${{ github.event.workflow_run.conclusion }} + REPO: ${{ github.repository }} + +jobs: + PRSubmitActions: + runs-on: ubuntu-latest + steps: + - name: Get PR Number + id: getpr + uses: actions/github-script@v6 + with: + retries: 5 + script: | + let search = `repo:${context.repo.owner}/${context.repo.repo} ${context.payload.workflow_run.head_sha}`; + let prs = await github.rest.search.issuesAndPullRequests({ + q: search, + }); + if (prs.data.total_count == 0) { + core.setFailed(`Unable to get PR for ${context.payload.workflow_run.head_sha}`); + return; + } + let pr_number = prs.data.items[0].number; + core.setOutput('pr_number', pr_number); + return; + + - name: Set Label + id: setlabel + uses: actions/github-script@v6 + env: + PR_NUMBER: ${{ steps.getpr.outputs.PR_NUMBER }} + LABEL_TIP: ${{ vars.PR_SUBMIT_TESTING_IN_PROGRESS }} + LABEL_PASS: ${{ vars.PR_SUBMIT_TESTS_PASSED }} + LABEL_FAIL: ${{ vars.PR_SUBMIT_TESTS_FAILED }} + with: + retries: 5 + script: | + let label; + if (process.env.ACTION === 'requested') { + label = process.env.LABEL_TIP; + } else { + if ( process.env.CONCLUSION === 'success' ) { + label = process.env.LABEL_PASS; + } else { + label = process.env.LABEL_FAIL; + } + } + core.info(`Setting label ${label}`); + github.rest.issues.setLabels({ + issue_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + labels: [ label ] + }); + return; + + - name: Get cherry-pick branches + if: github.event.action == 'completed' + id: getbranches + uses: asterisk/asterisk-ci-actions/GetCherryPickBranchesFromPR@main + with: + repo: ${{env.REPO}} + pr_number: ${{steps.getpr.outputs.PR_NUMBER}} + cherry_pick_regex: ${{vars.CHERRY_PICK_REGEX}} + github_token: ${{secrets.GITHUB_TOKEN}} + + - name: Add cherry-pick reminder + if: github.event.action == 'completed' + uses: actions/github-script@v6 + env: + PR_NUMBER: ${{steps.getpr.outputs.PR_NUMBER}} + CHERRY_PICK_REMINDER: ${{vars.CHERRY_PICK_REMINDER}} + BRANCHES_OUTPUT: ${{toJSON(steps.getbranches.outputs)}} + BRANCH_COUNT: ${{steps.getbranches.outputs.branch_count}} + FORCED_NONE: ${{steps.getbranches.outputs.forced_none}} + with: + retries: 5 + script: | + if (process.env.FORCED_NONE === 'true' || + process.env.BRANCH_COUNT > 0) { + core.info("No cherry-pick reminder needed."); + return; + } + let comments = await github.rest.issues.listComments({ + issue_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + }); + let found = false; + for (const c of comments.data) { + if (c.body.startsWith("")) { + found = true; + break; + } + } + if (found) { + core.info("Cherry-pick reminder already exists."); + return; + } + core.info("Adding cherry-pick reminder."); + await github.rest.issues.createComment({ + issue_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + body: process.env.CHERRY_PICK_REMINDER + }) + return; + + - name: Add reviewers + if: github.event.action == 'completed' + uses: actions/github-script@v6 + env: + PR_NUMBER: ${{steps.getpr.outputs.PR_NUMBER}} + REVIEWERS: ${{vars.PR_REVIEWERS}} + with: + retries: 5 + script: | + let rs = JSON.parse(process.env.REVIEWERS); + let users = []; + let teams = []; + for (const r of rs) { + if (r.indexOf("/") > 0) { + teams.push(r); + } else { + users.push(r); + } + } + if (teams.length > 0 || users.length > 0) { + core.info(`Adding user reviewers ${users}`); + core.info(`Adding team reviewers ${teams}`); + await github.pulls.requestReviewers({ + pr_number: process.env.PR_NUMBER, + owner: context.repo.owner, + repo: context.repo.repo, + reviewers: users, + team_reviewers: teams + }); + } + return; diff --git a/.github/workflows/PRSubmitTests.yml b/.github/workflows/PRSubmitTests.yml new file mode 100644 index 0000000000..bcf6e79b94 --- /dev/null +++ b/.github/workflows/PRSubmitTests.yml @@ -0,0 +1,113 @@ +name: PRSubmitTests +run-name: "PR ${{github.event.number}} ${{github.event.action}} by ${{ github.actor }}" +on: + pull_request: + types: [opened, reopened, synchronize] + +concurrency: + group: ${{github.workflow}}-${{github.event.number}} + cancel-in-progress: true + +env: + ASTERISK_REPO: ${{github.repository}} + PR_NUMBER: ${{github.event.number}} + PR_COMMIT: ${{github.event.pull_request.head.sha}} + BRANCH: ${{github.event.pull_request.base.ref}} + +jobs: +# +# Pull requests created from forked respositories don't have access to +# the "Action Variables" ('vars' context) so we need to retrieve control +# data from an action. +# + PRSGetControlData: + runs-on: ubuntu-latest + outputs: + control_data: ${{ steps.setvars.outputs.control_data }} + steps: + - id: setvars + uses: asterisk/asterisk-ci-actions/GetRepoControlData@main + with: + repo: ${{ github.event.repository.name}} + - name: DumpEnvironment + uses: asterisk/asterisk-ci-actions/DumpEnvironmentAction@main + with: + action-inputs: ${{toJSON(inputs)}} + action-vars: ${{ toJSON(steps.setvars.outputs) }} + + PRSUnitTests: + needs: PRSGetControlData + runs-on: ubuntu-latest + env: + UNITTEST_COMMAND: ${{ fromJSON(needs.PRSGetControlData.outputs.control_data).UNITTEST_COMMAND }} + steps: + - name: Run Unit Tests + uses: asterisk/asterisk-ci-actions/AsteriskUnitComposite@main + with: + asterisk_repo: ${{env.ASTERISK_REPO}} + pr_number: ${{env.PR_NUMBER}} + base_branch: ${{env.BRANCH}} + unittest_command: ${{env.UNITTEST_COMMAND}} + + PRSGateTestMatrix: + needs: PRSGetControlData + env: + TESTSUITE_REPO: "${{ fromJSON(needs.PRSGetControlData.outputs.control_data).TESTSUITE_REPO }}" + GATETEST_COMMANDS: "${{ fromJSON(needs.PRSGetControlData.outputs.control_data).GATETEST_COMMANDS }}" + continue-on-error: false + strategy: + fail-fast: false + matrix: + group: ${{ fromJSON(fromJSON(needs.PRSGetControlData.outputs.control_data).GATETEST_LIST) }} + runs-on: ubuntu-latest + steps: + - id: runtest + name: Run Gate Tests for ${{ matrix.group }} + uses: asterisk/asterisk-ci-actions/AsteriskGateComposite@main + with: + test_type: Gate + asterisk_repo: ${{env.ASTERISK_REPO}} + pr_number: ${{env.PR_NUMBER}} + base_branch: ${{env.BRANCH}} + testsuite_repo: ${{env.TESTSUITE_REPO}} + gatetest_group: ${{matrix.group}} + gatetest_commands: ${{env.GATETEST_COMMANDS}} + + PRSTestResults: + if: always() + runs-on: ubuntu-latest + needs: [PRSUnitTests,PRSGateTestMatrix] + steps: + - name: Check test matrix status + env: + RESULT_UNIT: ${{ needs.PRSUnitTests.result }} + RESULT_GATE: ${{ needs.PRSGateTestMatrix.result }} + run: | + declare -i rc=0 + echo "all results: ${{ toJSON(needs.*.result) }}" + case $RESULT_UNIT in + success) + echo "::notice::Unit tests passed" + ;; + skipped) + echo "::error::Unit tests were skipped because of an earlier failure" + rc+=1 + ;; + *) + echo "::error::One or more unit tests failed ($RESULT_UNIT)" + rc+=1 + esac + case $RESULT_GATE in + success) + echo "::notice::Gate tests passed" + ;; + skipped) + echo "::error::Gate tests were skipped because of an earlier failure" + rc+=1 + ;; + *) + echo "::error::One or more gate tests failed ($RESULT_GATE)" + rc+=1 + esac + echo "::notice::Final result code: $rc" + exit $rc