From ed36bbe80b0b610761c976bc397fd011a423bf42 Mon Sep 17 00:00:00 2001 From: bado Date: Mon, 7 Oct 2024 16:03:48 +0800 Subject: [PATCH] perf(github): add knob/flag to manually override CI skip Primary Changes ---------------- 1. Created a function to check if the commit message contains 'cacti-skip-ci' to skip the CI check. 2. Check if the request is from the maintainer or not. If he is a Maintainer, the CI-skip request will be granted, else not. Fixes #2679 Signed-off-by: bado --- .github/workflows/ci.yaml | 13 ++++ tools/ci-skip-for-maintainers.js | 103 +++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 tools/ci-skip-for-maintainers.js diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 248e9709e6..2afd0f5b83 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -16,9 +16,11 @@ env: RUN_CODE_COVERAGE: true jobs: ActionLint: + needs: check-ci-skip uses: ./.github/workflows/actionlint.yaml DCI-Lint: name: DCI-Lint + needs: check-ci-skip runs-on: ubuntu-22.04 steps: - id: lint-git-repo @@ -29,7 +31,15 @@ jobs: - name: Get the output response run: echo "${{ steps.lint-git-repo.outputs.lint-git-repo-response }}" + check-ci-skip: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4.1.7 + - name: Check CI Skip + run: node tools/ci-skip-for-maintainers.js ${{ github.event.pull_request.url }} ${{ github.event.pull_request.user.login }} + check-coverage: + needs: check-ci-skip outputs: run-coverage: ${{ steps.set-output.outputs.run-coverage }} runs-on: ubuntu-22.04 @@ -40,6 +50,7 @@ jobs: run: echo "run-coverage=${{ env.RUN_CODE_COVERAGE }}" >> "$GITHUB_OUTPUT" compute_changed_packages: + needs: check-ci-skip outputs: cmd-api-server-changed: ${{ steps.changes.outputs.cmd-api-server-changed }} plugin-ledger-connector-polkadot-changed: ${{ steps.changes.outputs.plugin-ledger-connector-polkadot-changed }} @@ -164,6 +175,7 @@ jobs: # - './.github/workflows/ci.yaml' build-dev: + needs: check-ci-skip continue-on-error: false env: DEV_BUILD_DISABLED: false @@ -2627,6 +2639,7 @@ jobs: ignore-unfixed: false vuln-type: 'os,library' severity: 'CRITICAL,HIGH' + name: Cactus_CI 'on': pull_request: diff --git a/tools/ci-skip-for-maintainers.js b/tools/ci-skip-for-maintainers.js new file mode 100644 index 0000000000..911c637ca4 --- /dev/null +++ b/tools/ci-skip-for-maintainers.js @@ -0,0 +1,103 @@ +import { readFileSync } from "fs"; + +//A new tag exclusively for MAINTAINERS that allows skipping the CI check +const SKIP_CACTI = "skip-cacti-ci"; +const MaintainersFile = "MAINTAINERS.md"; +//regular expression to get the maintainers in MAINTAINERS.md +const NAMES_REGEX = /\|\s*([A-Za-z\s]+)\s*/; +const LINKS_REGEX = /\|\s*\[([^\]]+)\]\[[^\]]+\]\s*/; +const TAGS_REGEX = /\|\s*([A-Za-z0-9_-]+|-)*\s*/; +const MAINTAINERS_REGEX = new RegExp( + NAMES_REGEX.source + LINKS_REGEX.source + TAGS_REGEX.source, + "g", +); + +const main = async () => { + const markdownContent = readFileSync(MaintainersFile, "utf-8"); + + const args = process.argv.slice(2); + const pullReqUrl = args[0]; + const committerLogin = args[1]; + + //Uncomment these lines and change it for local machine testing purposes: + //const pullReqUrl = "https://api.github.com/repos//cactus/pulls/"; + //const committerLogin = ""; + + const fetchJsonFromUrl = async (url) => { + const fetchResponse = await fetch(url); + return fetchResponse.json(); + }; + + let commitMessageList = []; + const commitMessagesMetadata = await fetchJsonFromUrl( + pullReqUrl + "/commits", + ); + + commitMessagesMetadata.forEach((commitMessageMetadata) => { + // get commit message body + commitMessageList.push(commitMessageMetadata["commit"]["message"]); + }); + + // Check if skip-ci is found in commit message + const checkSkipCI = () => { + for (let commitMessageListIndex in commitMessageList) { + let commitMessage = commitMessageList[commitMessageListIndex]; + if (commitMessage.includes(SKIP_CACTI)) { + console.log("Skip requested in commit message."); + return true; + } else { + console.log("No skip request found."); + } + return false; + } + }; + + // Function to extract active maintainers + const extractMaintainers = (maintainerMetaData) => { + let match; + const maintainers = []; + while ((match = MAINTAINERS_REGEX.exec(maintainerMetaData)) !== null) { + const github = match[2]; + maintainers.push(github); + } + return maintainers; + }; + // Get the maintainers + const activeMaintainers = extractMaintainers(markdownContent); + activeMaintainers.forEach((maintainers) => { + maintainers; + }); + + // Check if committer is a trusted maintainer + const checkCommitterIsMaintainer = () => { + if (activeMaintainers.includes(committerLogin)) { + console.log("The author of this PR is an active maintainer."); + return true; + } else { + console.log( + "CI will not be skipped. \nThe author of this PR is not an active maintainer.\nPlease refer to https://github.com/hyperledger/cacti/blob/main/MAINTAINERS.md for the list of active maintainers.", + ); + return false; + } + }; + + // Main logic + + const shouldSkipCI = checkSkipCI(); + + if (shouldSkipCI) { + const isMaintainer = checkCommitterIsMaintainer(); + if (isMaintainer) { + console.log( + "Exit with an error code so as to pause the dependent workflows. CI skipped as per request.", + ); + process.exit(1); // Exit successfully to skip CI + } + } else { + console.log("No skip requested. Proceeding with CI."); + process.exit(0); // Exit successfully to run CI + } +}; + +// Run the main function +main();