diff --git a/.github/workflows/all-green.yml b/.github/workflows/all-green.yml index c13f45fe421..e8de0e51eb4 100644 --- a/.github/workflows/all-green.yml +++ b/.github/workflows/all-green.yml @@ -18,14 +18,23 @@ jobs: checks: read contents: read steps: - - uses: wechuli/allcheckspassed@1d00cf0c34c4b0805db8866d8913f22e7125301e # v2.3.0 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - delay: ${{ github.run_attempt == 1 && '7' || '0' }} # 7 minutes on first attempt, no delay on reruns - retries: 15 - polling_interval: 2 # Once every 2 minutes - checks_exclude: devflow.* - fail_fast: false - verbose: true # What checks are still waited for? + sparse-checkout-cone-mode: false + sparse-checkout: | + .github + scripts + - uses: ./.github/actions/node + with: + version: active + - run: yarn add @actions/core @actions/github octokit + - run: node scripts/all-green.mjs + env: + DELAY: ${{ github.run_attempt == 1 && '7' || '0' }} # 7 minutes on first attempt, no delay on reruns + GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_TOKEN: ${{ github.token }} + POLLING_INTERVAL: 1 + RETRIES: 15 - name: Require vendor validation when vendor/ changes if: github.event_name == 'pull_request' env: diff --git a/package.json b/package.json index ee6cb1857cb..c3373fd2511 100644 --- a/package.json +++ b/package.json @@ -147,6 +147,8 @@ "oxc-parser": "^0.115.0" }, "devDependencies": { + "@actions/core": "^3.0.0", + "@actions/github": "^9.0.0", "@babel/helpers": "^7.28.6", "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.39.2", diff --git a/scripts/all-green.mjs b/scripts/all-green.mjs new file mode 100644 index 00000000000..aae989cb8aa --- /dev/null +++ b/scripts/all-green.mjs @@ -0,0 +1,129 @@ +import { setTimeout } from 'timers/promises' +import { Octokit } from 'octokit' +import { summary } from '@actions/core' +import { context } from '@actions/github' + +/* eslint-disable no-console */ + +const { + DELAY, + GITHUB_SHA, + GITHUB_TOKEN, + POLLING_INTERVAL, + RETRIES, +} = process.env + +const octokit = new Octokit({ auth: GITHUB_TOKEN }) +const owner = 'DataDog' +const repo = 'dd-trace-js' +const ref = context.payload.pull_request?.head.sha || GITHUB_SHA +const params = { owner, repo, ref } +const checkConclusionEmojis = { + action_required: '🔶', + cancelled: '🚫', + failure: '❌', + neutral: '⚪', + success: '✅', + skipped: '⏭️', + stale: '🔄', + timed_out: '⌛', +} + +let retries = 0 + +async function hasCompleted () { + const { data: inProgressRuns } = await octokit.rest.checks.listForRef({ + ...params, + per_page: 1, // Minimum is 1 but we don't need any pages. + status: 'in_progress', + }) + + // If there are any in progress runs it means we're not ready to check + // statuses. We will always have minimum 1 for the All Green job. + if (inProgressRuns.total_count > 1) return false + + const { data: queuedRuns } = await octokit.rest.checks.listForRef({ + ...params, + per_page: 1, // Minimum is 1 but we don't need any pages. + status: 'queued', + }) + + // Same as above, but jobs that are queued are not even in progress yet. + if (queuedRuns.total_count > 0) return false + + return true +} + +async function checkCompleted () { + if (RETRIES && retries > RETRIES) { + throw new Error(`State is still pending after ${RETRIES} retries.`) + } + + if (!await hasCompleted()) { + console.log(`Status is still pending, waiting for ${POLLING_INTERVAL} minutes before retrying.`) + await setTimeout(POLLING_INTERVAL * 60_000) + console.log('Retrying.') + retries++ + await checkCompleted() + } +} + +async function checkAllGreen () { + let checkRuns + + try { + await checkCompleted() + } finally { + checkRuns = await octokit.paginate( + 'GET /repos/:owner/:repo/commits/:ref/check-runs', + { + ...params, + per_page: 100, + } + ) + + printSummary(checkRuns) + } + + const allGreen = !checkRuns.some(run => ( + run.conclusion === 'failure' || run.conclusion === 'timed_out' + )) + + if (allGreen) { + console.log('All jobs were successful.') + } else { + throw new Error('One or more jobs failed.') + } +} + +async function printSummary (checkRuns) { + const header = [ + { data: 'name', header: true }, + { data: 'status', header: true }, + { data: 'conclusion', header: true }, + { data: 'started_at', header: true }, + { data: 'completed_at', header: true }, + ] + + const body = checkRuns.map(run => [ + run.name, + run.status, + run.conclusion ? `${run.conclusion} ${checkConclusionEmojis[run.conclusion]}` : ' ', + run.started_at, + run.completed_at ?? ' ', + ]) + + await summary + .addHeading('Checks Summary') + .addTable([header, ...body]) + .write() +} + +console.log(`Polling status for ref: ${ref}.`) + +if (DELAY) { + console.log(`Waiting for ${DELAY} minutes before starting.`) + await setTimeout(DELAY * 60_000) +} + +await checkAllGreen() diff --git a/yarn.lock b/yarn.lock index c35fe209c5d..436f65cdf08 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,55 @@ # yarn lockfile v1 +"@actions/core@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@actions/core/-/core-3.0.0.tgz#89cb07c119e9b46a649ad5f355e77de9b3108cf8" + integrity sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg== + dependencies: + "@actions/exec" "^3.0.0" + "@actions/http-client" "^4.0.0" + +"@actions/exec@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@actions/exec/-/exec-3.0.0.tgz#8c3464d20f0aa4068707757021d7e3c01a7ee203" + integrity sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw== + dependencies: + "@actions/io" "^3.0.2" + +"@actions/github@^9.0.0": + version "9.0.0" + resolved "https://registry.yarnpkg.com/@actions/github/-/github-9.0.0.tgz#c86dae4128b2a6987271e2663bee9e766464840a" + integrity sha512-yJ0RoswsAaKcvkmpCE4XxBRiy/whH2SdTBHWzs0gi4wkqTDhXMChjSdqBz/F4AeiDlP28rQqL33iHb+kjAMX6w== + dependencies: + "@actions/http-client" "^3.0.2" + "@octokit/core" "^7.0.6" + "@octokit/plugin-paginate-rest" "^14.0.0" + "@octokit/plugin-rest-endpoint-methods" "^17.0.0" + "@octokit/request" "^10.0.7" + "@octokit/request-error" "^7.1.0" + undici "^6.23.0" + +"@actions/http-client@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-3.0.2.tgz#3db9c83af9d29d51ac8c30b45bc17f7014beb1b2" + integrity sha512-JP38FYYpyqvUsz+Igqlc/JG6YO9PaKuvqjM3iGvaLqFnJ7TFmcLyy2IDrY0bI0qCQug8E9K+elv5ZNfw62ZJzA== + dependencies: + tunnel "^0.0.6" + undici "^6.23.0" + +"@actions/http-client@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-4.0.0.tgz#f9754133c22802466482bf96321d42f2dba1fc82" + integrity sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g== + dependencies: + tunnel "^0.0.6" + undici "^6.23.0" + +"@actions/io@^3.0.2": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@actions/io/-/io-3.0.2.tgz#6f89b27a159d109836d983efa283997c23b92284" + integrity sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw== + "@babel/code-frame@^7.28.6", "@babel/code-frame@^7.29.0": version "7.29.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.0.tgz#7cd7a59f15b3cc0dcd803038f7792712a7d0b15c" @@ -585,14 +634,14 @@ "@octokit/types" "^16.0.0" bottleneck "^2.15.3" -"@octokit/request-error@^7.0.0", "@octokit/request-error@^7.0.2": +"@octokit/request-error@^7.0.0", "@octokit/request-error@^7.0.2", "@octokit/request-error@^7.1.0": version "7.1.0" resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-7.1.0.tgz#440fa3cae310466889778f5a222b47a580743638" integrity sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw== dependencies: "@octokit/types" "^16.0.0" -"@octokit/request@^10.0.6": +"@octokit/request@^10.0.6", "@octokit/request@^10.0.7": version "10.0.8" resolved "https://registry.yarnpkg.com/@octokit/request/-/request-10.0.8.tgz#6609a5a38ad6f8ee203d9eb8ac9361d906a4414e" integrity sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw== @@ -4047,16 +4096,7 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -"string-width-cjs@npm:string-width@^4.2.0": - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -4120,14 +4160,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -4239,6 +4272,11 @@ tslib@^2.4.0, tslib@^2.5.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== +tunnel@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" + integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -4355,6 +4393,11 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/undici/-/undici-6.23.0.tgz#7953087744d9095a96f115de3140ca3828aff3a4" + integrity sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g== + universal-github-app-jwt@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/universal-github-app-jwt/-/universal-github-app-jwt-2.2.2.tgz#38537e5a7d154085a35f97601a5e30e9e17717df" @@ -4480,7 +4523,7 @@ workerpool@^9.2.0: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-9.3.4.tgz#f6c92395b2141afd78e2a889e80cb338fe9fca41" integrity sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -4498,15 +4541,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214"