From e0e9c6347c177eb56cc3209206a5d5b108395195 Mon Sep 17 00:00:00 2001 From: Roch Devost Date: Fri, 26 Jun 2026 16:41:31 -0400 Subject: [PATCH 01/51] ci(release): fix publish by dropping dist-tag add (#9100) The OIDC-exchanged token from the npm registry is only valid for the publish operation; using it for npm dist-tag add produced E401. Remove the multi-tag logic and the OIDC exchange entirely: each branch now publishes with a single tag (latest for the current release line, latest-nodeXX for older lines), which is all npm's trusted publishing model supports without a stored token. Co-authored-by: Claude Sonnet 4.6 (1M context) --- .github/workflows/release.yml | 48 ++++++++++------------------------- 1 file changed, 13 insertions(+), 35 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b826335d65..414ef18549 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,16 +16,16 @@ jobs: setup: if: github.event_name == 'push' runs-on: ubuntu-latest - # Space-separated npm dist-tags for each release line. - # The latest branch always gets "latest" prepended automatically. + # npm dist-tag for each release line. + # The latest branch always gets "latest" automatically. # Add a line here when creating a new release branch. env: DIST_TAGS: | v3.x latest-node14 v4.x latest-node16 - v5.x latest-node18 latest-node20 + v5.x latest-node18 outputs: - npm_tags: ${{ steps.compute.outputs.npm_tags }} + npm_tag: ${{ steps.compute.outputs.npm_tag }} is_latest: ${{ steps.compute.outputs.is_latest }} steps: - id: compute @@ -47,18 +47,18 @@ jobs: | sort -V \ | tail -1) - # Collect the tags defined for this branch (everything after the branch name) - branch_tags=$(echo "$DIST_TAGS" | awk -v b="$branch" '$1==b{$1=""; sub(/^ /,""); print}') + # Collect the tag defined for this branch (field after the branch name) + branch_tag=$(echo "$DIST_TAGS" | awk -v b="$branch" '$1==b{print $2}') if [ "$branch" = "$latest" ]; then - npm_tags="latest ${branch_tags:-latest-${branch%.x}}" + npm_tag="latest" is_latest="true" else - npm_tags="${branch_tags:-latest-${branch%.x}}" + npm_tag="${branch_tag:-latest-${branch%.x}}" is_latest="false" fi - echo "npm_tags=$npm_tags" >> "$GITHUB_OUTPUT" + echo "npm_tag=$npm_tag" >> "$GITHUB_OUTPUT" echo "is_latest=$is_latest" >> "$GITHUB_OUTPUT" publish: @@ -88,28 +88,11 @@ jobs: - name: Publish run: | version="${{ fromJson(steps.pkg.outputs.json).version }}" - tags=(${{ needs.setup.outputs.npm_tags }}) - - # Exchange the GitHub OIDC token for an npm registry token so - # that npm publish and npm dist-tag add share the same auth. - # npm only runs this exchange internally for publish (oidc.js:141) - # and does not persist the token, so dist-tag add would fail - # without doing it explicitly here. - # Audience format and exchange endpoint from npm/lib/utils/oidc.js. - oidc_token=$(curl -sS -fH \ - "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ - "${ACTIONS_ID_TOKEN_REQUEST_URL}&audience=npm:registry.npmjs.org" \ - | jq -r '.value') - npm_token=$(curl -sS -fX POST \ - -H "Authorization: Bearer $oidc_token" \ - -H "Content-Type: application/json" \ - "https://registry.npmjs.org/-/npm/v1/oidc/token/exchange/package/dd-trace" \ - | jq -r '.token') - export NODE_AUTH_TOKEN="$npm_token" + tag="${{ needs.setup.outputs.npm_tag }}" # Idempotent: skip publish if this version already exists so - # that a rerun after a partial failure can still repair dist-tags, - # git tags, release notes, and docs. + # that a rerun after a partial failure can still repair the git + # tag and release notes. if npm view "dd-trace@$version" version 2>/dev/null | grep -qF "$version"; then local_integrity=$(npm pack --dry-run --json 2>/dev/null | jq -r '.[0].integrity') published_integrity=$(npm view "dd-trace@$version" dist.integrity 2>/dev/null) @@ -121,13 +104,8 @@ jobs: fi echo "Version $version already published with identical content, skipping npm publish" else - npm publish --tag "${tags[0]}" + npm publish --tag "$tag" fi - - # Always reconcile all expected dist-tags. - for tag in "${tags[@]:1}"; do - npm dist-tag add "dd-trace@$version" "$tag" - done - name: Tag release run: | version="${{ fromJson(steps.pkg.outputs.json).version }}" From 9144415a6e943c2252d16a1f1be03ca9a35dd8b1 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Fri, 26 Jun 2026 22:59:55 +0200 Subject: [PATCH 02/51] ci(coverage): merge per-integration coverage in All Green before upload (#9086) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each test cell uploaded its own report to Codecov, so a commit sent ~430 uploads. Codecov silently parks uploads past its ~150-per-commit ceiling in `started` and never merges them, so roughly 40 reports' worth of coverage was dropped from every commit. The Datadog coverage upload was separately broken: `upload-coverage-artifact` probed for files with `find -maxdepth 1`, but the report lives one level deeper at `coverage/node-/`, so the check found nothing, no `coverage-*` artifact was produced, and `datadog-ci coverage upload` reported nothing while passing green. All Green already downloads every `coverage-*` artifact to drive the Datadog upload, so it is the one place that sees a whole commit's coverage. It now groups the per-cell reports by integration and uploads ~100 groups to both backends instead of ~430 per-cell reports: 1. `upload-coverage-artifact` recurses for the report files and names each artifact `coverage-__-` so matrix cells that share a flag (cypress varies `spec` outside its flag) stop clobbering each other. 2. `scripts/group-coverage.mjs` sorts each cell's report into its integration's directory, stripping Node.js and library versions, which are noise for "which integration regressed". Reports are not merged locally — both backends merge same-flag uploads server-side — so each report passes through byte-for-byte and the harness needs no istanbul dependency in All Green's sparse checkout. ~430 cells collapse to ~100 groups. 3. Each cell emits both lcov and istanbul JSON: Codecov reads branch and function coverage from the JSON (its lcov parser ingests only line hits), Datadog reads the lcov and does not ingest the JSON. All Green uploads each format to the backend that reads it, one group per integration, flagged with the integration name. `master-coverage` still rides every Codecov upload on PRs targeting master so the `codecov/patch` gate fires; reruns de-duplicate to the newest run so a stale rerun's counters are not double-counted. --- .github/actions/coverage/action.yml | 26 +- .github/actions/coverage/upload/action.yml | 51 ---- .../upload-coverage-artifact/action.yml | 36 ++- .github/workflows/all-green.yml | 55 +++- nyc.config.js | 4 + package.json | 2 +- scripts/group-coverage.mjs | 244 ++++++++++++++++++ scripts/group-coverage.spec.mjs | 169 ++++++++++++ 8 files changed, 508 insertions(+), 79 deletions(-) delete mode 100644 .github/actions/coverage/upload/action.yml create mode 100644 scripts/group-coverage.mjs create mode 100644 scripts/group-coverage.spec.mjs diff --git a/.github/actions/coverage/action.yml b/.github/actions/coverage/action.yml index d01ceef7cd..3f481b05b4 100644 --- a/.github/actions/coverage/action.yml +++ b/.github/actions/coverage/action.yml @@ -1,9 +1,13 @@ name: coverage -description: Verify coverage output and upload it to Codecov and Datadog. +description: >- + Verify a job's coverage output and stash it as an artifact. All Green collects every + `coverage-*` artifact, merges them per integration, and uploads the groups to Codecov and + Datadog — so a commit sends ~100 grouped reports instead of one per matrix cell, which kept + Codecov from silently dropping uploads past its per-commit ceiling. inputs: flags: - description: "Codecov flags value" + description: "Coverage flags — the grouping key All Green folds matrix cells by" required: false report-dir: description: "Coverage report directory (defaults to 'coverage')" @@ -12,19 +16,13 @@ inputs: runs: using: composite steps: - # Retry once on failure to work around transient issues (e.g. flaky - # Codecov upload network calls). - - id: attempt - uses: ./.github/actions/coverage/upload - continue-on-error: true - with: - flags: ${{ inputs.flags }} - report-dir: ${{ inputs.report-dir }} - - if: steps.attempt.outcome == 'failure' + - name: Verify coverage output shell: bash - run: sleep 60 - - if: steps.attempt.outcome == 'failure' - uses: ./.github/actions/coverage/upload + run: node scripts/verify-coverage.js --flags "${{ inputs.flags }}" + + - name: Upload coverage artifact + if: always() + uses: ./.github/actions/upload-coverage-artifact with: flags: ${{ inputs.flags }} report-dir: ${{ inputs.report-dir }} diff --git a/.github/actions/coverage/upload/action.yml b/.github/actions/coverage/upload/action.yml deleted file mode 100644 index f74f03241d..0000000000 --- a/.github/actions/coverage/upload/action.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Coverage Upload -description: Internal implementation; verify and upload coverage. Use `./.github/actions/coverage` instead. - -inputs: - flags: - description: "Codecov flags value" - required: false - report-dir: - description: "Coverage report directory (defaults to 'coverage')" - required: false - default: coverage - -runs: - using: composite - steps: - - name: Verify coverage output - shell: bash - run: node scripts/verify-coverage.js --flags "${{ inputs.flags }}" - - # `master-coverage` is the flag .codecov.yml gates codecov/patch on. Attach - # it only on PRs targeting master so release-branch PRs auto-pass. - - name: Compute Codecov flags - id: codecov-flags - shell: bash - env: - JOB_FLAGS: ${{ inputs.flags }} - EVENT_NAME: ${{ github.event_name }} - BASE_REF: ${{ github.base_ref }} - run: | - flags="$JOB_FLAGS" - if [ "$EVENT_NAME" = "pull_request" ] && [ "$BASE_REF" = "master" ]; then - flags="${flags:+$flags,}master-coverage" - fi - echo "value=$flags" >> "$GITHUB_OUTPUT" - - - name: Install gpg for Codecov validation - if: runner.os == 'Linux' - shell: bash - run: command -v gpg || sudo apt-get install -y gpg - - - name: Upload coverage to Codecov - uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 - with: - flags: ${{ steps.codecov-flags.outputs.value }} - - - name: Upload coverage artifact - if: always() - uses: ./.github/actions/upload-coverage-artifact - with: - flags: ${{ inputs.flags }} - report-dir: ${{ inputs.report-dir }} diff --git a/.github/actions/upload-coverage-artifact/action.yml b/.github/actions/upload-coverage-artifact/action.yml index b29903dc8e..cbb4b9ed47 100644 --- a/.github/actions/upload-coverage-artifact/action.yml +++ b/.github/actions/upload-coverage-artifact/action.yml @@ -1,9 +1,9 @@ name: Upload Coverage Artifact -description: Upload coverage report as a GitHub Actions artifact for later collection +description: Upload a job's LCOV report as a GitHub Actions artifact for All Green to collect and group. inputs: flags: - description: Coverage flags — used as artifact identifier and passed to Datadog on upload + description: Coverage flags — the grouping key All Green folds matrix cells by required: true report-dir: description: Coverage report directory @@ -13,26 +13,38 @@ inputs: runs: using: composite steps: + # The reports live at `/node--