diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 4ed27ca2ee..7dca23dfad 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,10 +17,12 @@ env: jobs: ActionLint: needs: check-ci-skip + if: needs.check-ci-skip.outputs.should_skip == 'false' uses: ./.github/workflows/actionlint.yaml DCI-Lint: name: DCI-Lint needs: check-ci-skip + if: needs.check-ci-skip.outputs.should_skip == 'false' runs-on: ubuntu-22.04 steps: - id: lint-git-repo @@ -33,13 +35,16 @@ jobs: check-ci-skip: runs-on: ubuntu-22.04 + outputs: + should_skip: ${{ steps.check.outputs.should_skip }} 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 }} + run: node tools/ci-skip-for-maintainers.js check-coverage: needs: check-ci-skip + if: needs.check-ci-skip.outputs.should_skip == 'false' outputs: run-coverage: ${{ steps.set-output.outputs.run-coverage }} runs-on: ubuntu-22.04 @@ -51,6 +56,7 @@ jobs: compute_changed_packages: needs: check-ci-skip + if: needs.check-ci-skip.outputs.should_skip == 'false' 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 }} @@ -187,6 +193,7 @@ jobs: build-dev: needs: check-ci-skip + if: needs.check-ci-skip.outputs.should_skip == 'false' continue-on-error: false env: DEV_BUILD_DISABLED: false diff --git a/tools/ci-skip-for-maintainers.js b/tools/ci-skip-for-maintainers.js index 911c637ca4..595557d388 100644 --- a/tools/ci-skip-for-maintainers.js +++ b/tools/ci-skip-for-maintainers.js @@ -1,9 +1,9 @@ import { readFileSync } from "fs"; +import { execSync } from "child_process"; -//A new tag exclusively for MAINTAINERS that allows skipping the CI check +// Constants 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*/; @@ -12,90 +12,86 @@ const MAINTAINERS_REGEX = new RegExp( "g", ); -const main = async () => { - const markdownContent = readFileSync(MaintainersFile, "utf-8"); +const getMaintainersFileContent = () => readFileSync(MaintainersFile, "utf-8"); - const args = process.argv.slice(2); - const pullReqUrl = args[0]; - const committerLogin = args[1]; +// Function to get the latest commit message author +const getCommitterLogin = () => { + const authorBuffer = execSync("git log -1 | grep Author | cut -d' ' -f2"); + const authorString = authorBuffer.toString(); + const authorStringTrim = authorString.trim(); + return authorStringTrim; +}; - //Uncomment these lines and change it for local machine testing purposes: - //const pullReqUrl = "https://api.github.com/repos//cactus/pulls/"; - //const committerLogin = ""; +// Function to get the latest commit message +const getLatestCommitMessage = () => { + const commitMsgBuffer = execSync("git log -1 --pretty=%B"); + const commitMsgString = commitMsgBuffer.toString(); + const commitMsgTrim = commitMsgString.trim(); + return commitMsgTrim; +}; + +// Function to check if SKIP_CACTI tag is in the commit message +const checkSkipCI = (commitMessage) => { + if (commitMessage.includes(SKIP_CACTI)) { + console.log("Skip requested in commit message."); + return true; + } + console.log("No skip request found."); + return false; +}; - const fetchJsonFromUrl = async (url) => { - const fetchResponse = await fetch(url); - return fetchResponse.json(); - }; +// Function to extract maintainers from the MAINTAINERS.md file content +const extractMaintainers = (maintainerMetaData) => { + let match; + const maintainers = []; + while ((match = MAINTAINERS_REGEX.exec(maintainerMetaData)) !== null) { + const github = match[2]; + maintainers.push(github); + } + return maintainers; +}; - let commitMessageList = []; - const commitMessagesMetadata = await fetchJsonFromUrl( - pullReqUrl + "/commits", +// Function to check if committer is an active maintainer +const checkCommitterIsMaintainer = (committerLogin, activeMaintainers) => { + if (activeMaintainers.includes(committerLogin)) { + console.log("The author of this PR is an active maintainer."); + return true; + } + 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; +}; - 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; - } - }; +// Main function to determine whether to skip CI or proceed +const main = async () => { + const markdownContent = getMaintainersFileContent(); + const committerLogin = getCommitterLogin(); + const commitMessage = getLatestCommitMessage(); + const outputPath = process.env.GITHUB_OUTPUT; + fs.appendFileSync(outputPath, `should_skip=${isMaintainer}\n`); + const shouldSkipCI = checkSkipCI(commitMessage); + if (!shouldSkipCI) { + console.log("No skip requested. Proceeding with CI."); + console.log(`Skip CI set to: ${shouldSkipCI}`); + process.exit(0); + } - // 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(); + const isMaintainer = checkCommitterIsMaintainer( + committerLogin, + activeMaintainers, + ); - 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 - } + if (isMaintainer) { + console.log( + "CI skipped as per request. Exit with an error to PAUSE dependent workflows.", + ); + console.log(`Skip CI set to: ${isMaintainer}`); + process.exit(0); } else { - console.log("No skip requested. Proceeding with CI."); - process.exit(0); // Exit successfully to run CI + console.log(`Skip CI set to: ${isMaintainer}`); + process.exit(0); } };