diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 2ac4264de6..1baeef0a1f 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/packages/cactus-test-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-validator-besu/v21-get-past-logs-endpoint.test.ts b/packages/cactus-test-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-validator-besu/v21-get-past-logs-endpoint.test.ts index 5bb2408476..d1dd532619 100644 --- a/packages/cactus-test-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-validator-besu/v21-get-past-logs-endpoint.test.ts +++ b/packages/cactus-test-plugin-ledger-connector-besu/src/test/typescript/integration/plugin-validator-besu/v21-get-past-logs-endpoint.test.ts @@ -42,9 +42,9 @@ const logLevel: LogLevelDesc = "TRACE"; describe("PluginLedgerBesu-v21GetPastLogs", () => { const log = LoggerProvider.getOrCreate({ - label: "v21-get-past-logs-endpoint.test.ts", - level: logLevel, - }); + label: "v21-get-past-logs-endpoint.test.ts", + level: logLevel, + }); const containerImageVersion = "2021-08-24--feat-1244"; const containerImageName = @@ -95,13 +95,12 @@ describe("PluginLedgerBesu-v21GetPastLogs", () => { node1Host = `http://${addressInfo1.address}:${addressInfo1.port}`; log.debug(`Cactus Node 1 Host: ${node1Host}`); - const testAccount = await besuTestLedger.createEthTestAccount(); const rpcApiHttpHost = await besuTestLedger.getRpcApiHttpHost(); const rpcApiWsHost = await besuTestLedger.getRpcApiWsHost(); const pluginRegistry = new PluginRegistry({ plugins: [keychain] }); - const options: IPluginLedgerConnectorBesuOptions= { + const options: IPluginLedgerConnectorBesuOptions = { instanceId: uuidv4(), rpcApiHttpHost, rpcApiWsHost, @@ -118,7 +117,8 @@ describe("PluginLedgerBesu-v21GetPastLogs", () => { apiServerOptions.apiPort = addressInfo1.port; apiServerOptions.cockpitPort = 0; apiServerOptions.apiTlsEnabled = false; - const config = await configService.newExampleConfigConvict(apiServerOptions); + const config = + await configService.newExampleConfigConvict(apiServerOptions); pluginRegistry.add(pluginValidatorBesu); @@ -128,7 +128,7 @@ describe("PluginLedgerBesu-v21GetPastLogs", () => { pluginRegistry, }); - await apiServer.start(); + await apiServer.start(); const web3Provider = new Web3.providers.HttpProvider(rpcApiHttpHost); web3 = new Web3(web3Provider); @@ -187,4 +187,4 @@ describe("PluginLedgerBesu-v21GetPastLogs", () => { expect(res.data.logs).toBeArray(); expect(res.data.logs).toBeTruthy(); }); -}); \ No newline at end of file +}); 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();