From e94c77369f446c9a55faec84536ad1a24a274d78 Mon Sep 17 00:00:00 2001 From: 9aoy Date: Mon, 14 Oct 2024 21:06:36 +0800 Subject: [PATCH] test: enhance Rsbuild ecosystem CI (#3712) --- .github/workflows/ecosystem-ci-trigger.yml | 103 +++++++++++++++++++++ .github/workflows/ecosystem-ci.yml | 60 ++++++++++++ .github/workflows/release.yml | 15 +++ .github/workflows/test.yml | 17 ---- scripts/alert/lark.js | 63 +++++++++++++ 5 files changed, 241 insertions(+), 17 deletions(-) create mode 100644 .github/workflows/ecosystem-ci-trigger.yml create mode 100644 .github/workflows/ecosystem-ci.yml create mode 100755 scripts/alert/lark.js diff --git a/.github/workflows/ecosystem-ci-trigger.yml b/.github/workflows/ecosystem-ci-trigger.yml new file mode 100644 index 000000000..200ca8c16 --- /dev/null +++ b/.github/workflows/ecosystem-ci-trigger.yml @@ -0,0 +1,103 @@ +name: ecosystem-ci trigger + +on: + issue_comment: + types: [created] + +jobs: + trigger: + runs-on: ubuntu-latest + if: github.repository == 'web-infra-dev/rsbuild' && github.event.issue.pull_request && startsWith(github.event.comment.body, '!eco-ci') + steps: + - uses: actions/github-script@v7 + with: + script: | + const user = context.payload.sender.login + console.log(`Validate user: ${user}`) + + let hasTriagePermission = false + try { + const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ + owner: context.repo.owner, + repo: context.repo.repo, + username: user, + }); + hasTriagePermission = data.user.permissions.triage + } catch (e) { + console.warn(e) + } + + if (hasTriagePermission) { + console.log('Allowed') + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: '+1', + }) + } else { + console.log('Not allowed') + await github.rest.reactions.createForIssueComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: context.payload.comment.id, + content: '-1', + }) + throw new Error('not allowed') + } + - uses: actions/github-script@v7 + id: get-pr-data + with: + script: | + console.log(`Get PR info: ${context.repo.owner}/${context.repo.repo}#${context.issue.number}`) + const { data: pr } = await github.rest.pulls.get({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }) + return { + num: context.issue.number, + branchName: pr.head.ref, + repo: pr.head.repo.full_name + } + - uses: actions/github-script@v7 + id: trigger + env: + COMMENT: ${{ github.event.comment.body }} + with: + github-token: ${{ secrets.RSPACK_ACCESS_TOKEN }} + result-encoding: string + script: | + const comment = process.env.COMMENT.trim() + const command = comment.split('\n')[0] + const prData = ${{ steps.get-pr-data.outputs.result }} + + const [suite, suiteRefType, suiteRef] = command.replace(/^!eco-ci/, '').trim().split(' ') + const allSuites = suite === '' || suite === '-' + + function normalizeSuiteRefType(suiteRefType) { + const prefix = '--suite-' + if (allSuites || suiteRefType === undefined || !suiteRefType.startsWith(prefix)) { + return 'precoded' + } + return suiteRefType.slice(prefix.length) + } + + function normalizeSuiteRef(suiteRef) { + return (allSuites || suiteRef === undefined) ? 'precoded' : suiteRef + } + + await github.rest.actions.createWorkflowDispatch({ + owner: 'rspack-contrib', + repo: 'rsbuild-ecosystem-ci', + workflow_id: 'ecosystem-ci-from-pr.yml', + ref: 'main', + inputs: { + prNumber: '' + prData.num, + branchName: prData.branchName, + repo: prData.repo, + suite: allSuites ? '-' : suite, + suiteRefType: normalizeSuiteRefType(suiteRefType), + suiteRef: normalizeSuiteRef(suiteRef), + } + }) diff --git a/.github/workflows/ecosystem-ci.yml b/.github/workflows/ecosystem-ci.yml new file mode 100644 index 000000000..8947cefcd --- /dev/null +++ b/.github/workflows/ecosystem-ci.yml @@ -0,0 +1,60 @@ +name: Ecosystem CI + +on: + push: + branches: [main] + + merge_group: + + workflow_dispatch: + +jobs: + ecosystem_ci_notify: + name: Run Ecosystem CI With Notify + runs-on: ubuntu-latest + if: github.repository == 'web-infra-dev/rsbuild' && github.event_name != 'workflow_dispatch' + steps: + - name: Run Ecosystem CI with notify + id: eco_ci + continue-on-error: true + uses: convictional/trigger-workflow-and-wait@v1.6.5 + with: + owner: "rspack-contrib" + repo: "rsbuild-ecosystem-ci" + workflow_file_name: "ecosystem-ci-from-commit.yml" + github_token: ${{ secrets.REPO_SCOPED_TOKEN }} + ref: "main" + client_payload: '{"commitSHA":"${{ github.sha }}","repo":"web-infra-dev/rsbuild","suite":"-","suiteRefType":"precoded","suiteRef":"precoded"}' + + - if: steps.eco_ci.outcome == 'failure' + uses: actions/checkout@v4 + - if: steps.eco_ci.outcome == 'failure' + uses: actions/setup-node@v4 + with: + node-version: 20 + - name: Send Failure Notification + if: steps.eco_ci.outcome == 'failure' + shell: bash + run: ./scripts/alert/lark.js + env: + TITLE: Rsbuild Ecosystem CI failed + DESCRIPTION: | + commitID: [${{github.sha}}](${{github.server_url}}/${{github.repository}}/commit/${{github.sha}}) + URL: ${{github.server_url}}/${{github.repository}}/actions/runs/${{github.run_id}} + LARK_WEBHOOK_URL: ${{secrets.LARK_WEBHOOK_URL}} + + ecosystem_ci: + name: Run Ecosystem CI + runs-on: ubuntu-latest + if: github.repository == 'web-infra-dev/rsbuild' && github.event_name == 'workflow_dispatch' + steps: + - name: Run Ecosystem CI + id: eco_ci + uses: convictional/trigger-workflow-and-wait@v1.6.5 + with: + owner: "rspack-contrib" + repo: "rsbuild-ecosystem-ci" + workflow_file_name: "ecosystem-ci-selected.yml" + github_token: ${{ secrets.REPO_SCOPED_TOKEN }} + ref: ${{ github.event.inputs.branch }} + client_payload: '{"commitSHA":"${{ github.sha }}","repo":"web-infra-dev/rsbuild","suite":"-","suiteRefType":"precoded","suiteRef":"precoded"}' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3f179c3ec..efaf128f6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -17,6 +17,10 @@ on: description: 'Release Branch (confirm release branch)' required: true default: 'main' + run_eco_ci: + description: 'Run Rsbuild ecosystem CI before release' + required: false + default: true issue_comment: types: [created] @@ -29,6 +33,17 @@ jobs: if: github.repository == 'web-infra-dev/rsbuild' && github.event_name == 'workflow_dispatch' runs-on: ubuntu-latest steps: + - name: Run Ecosystem CI + if: github.event.inputs.run_eco_ci == true + uses: convictional/trigger-workflow-and-wait@v1.6.5 + with: + owner: "rspack-contrib" + repo: "rsbuild-ecosystem-ci" + workflow_file_name: "ecosystem-ci-selected.yml" + github_token: ${{ secrets.REPO_SCOPED_TOKEN }} + ref: ${{ github.event.inputs.branch }} + client_payload: '{"commitSHA":"${{ github.sha }}","repo":"web-infra-dev/rsbuild","suite":"-","suiteRefType":"precoded","suiteRef":"precoded"}' + - name: Checkout uses: actions/checkout@v4 with: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 6a06e0455..b6f2d7254 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -98,20 +98,3 @@ jobs: - name: E2E Test if: steps.changes.outputs.changed == 'true' run: pnpm run e2e - - # ======== ecosystem_ci ======== - ecosystem_ci: - name: Run Ecosystem CI - runs-on: ubuntu-latest - if: github.ref_name == 'main' && github.repository_owner == 'web-infra-dev' - steps: - - name: Run Ecosystem CI - id: eco_ci - uses: convictional/trigger-workflow-and-wait@v1.6.5 - with: - owner: "rspack-contrib" - repo: "rsbuild-ecosystem-ci" - workflow_file_name: "ecosystem-ci-from-commit.yml" - github_token: ${{ secrets.REPO_SCOPED_TOKEN }} - ref: "main" - client_payload: '{"commitSHA":"${{ github.sha }}","repo":"web-infra-dev/rsbuild","suite":"-","suiteRefType":"precoded","suiteRef":"precoded"}' diff --git a/scripts/alert/lark.js b/scripts/alert/lark.js new file mode 100755 index 000000000..14182ddce --- /dev/null +++ b/scripts/alert/lark.js @@ -0,0 +1,63 @@ +#!/bin/env node + +const TITLE = process.env.TITLE; +const DESCRIPTION = process.env.DESCRIPTION; +const URL = process.env.URL; +const LARK_WEBHOOK_URL = process.env.LARK_WEBHOOK_URL; +const TPL_COLOR = process.env.TPL_COLOR || 'red'; +const TPL_BTN_TYPE = process.env.TPL_BTN_TYPE || 'danger'; // default primary danger + +if (!TITLE || !DESCRIPTION) { + throw new Error('please input title and description'); +} + +if (!LARK_WEBHOOK_URL) { + console.log('missing LARK_WEBHOOK_URL, will exit'); + process.exit(0); +} + +(async function notify() { + const res = await fetch(LARK_WEBHOOK_URL, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + msg_type: 'interactive', + card: { + header: { + template: TPL_COLOR, + title: { + content: TITLE, + tag: 'plain_text', + }, + }, + elements: [ + { + tag: 'markdown', + content: DESCRIPTION, + }, + URL && { + tag: 'action', + actions: [ + { + tag: 'button', + text: { + content: 'Details', + tag: 'plain_text', + }, + url: URL, + type: TPL_BTN_TYPE, + }, + ], + }, + ].filter(Boolean), + }, + }), + }); + + if (!res.ok) { + const data = await res.text(); + throw new Error(`send alert failed with ${data}`); + } +})();