Skip to content

Commit f233e40

Browse files
authored
Merge branch 'main' into release/libdd-data-pipeline/20260324-152000
2 parents 1235d7d + d75fe5e commit f233e40

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+8728
-1867
lines changed

.github/CODEOWNERS

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ libdd-crashtracker*/ @DataDog/libdatadog-profiling
4444
libdd-data-pipeline*/ @DataDog/libdatadog-apm
4545
libdd-ddsketch*/ @DataDog/libdatadog-apm @DataDog/apm-common-components-core
4646
libdd-dogstatsd-client @DataDog/apm-common-components-core
47-
libdd-library-config*/ @DataDog/apm-sdk-capabilities
47+
libdd-library-config*/ @DataDog/apm-sdk-capabilities-rust
4848
libdd-libunwind*/ @DataDog/libdatadog-profiling
4949
libdd-log*/ @DataDog/apm-common-components-core
5050
libdd-profiling*/ @DataDog/libdatadog-profiling
@@ -81,3 +81,6 @@ bin_tests/tests/test_the_tests.rs @DataDog/libdatadog-core
8181
bin_tests/src/bin/test_the_tests.rs @DataDog/libdatadog-core
8282
tools/cc_utils/ @DataDog/libdatadog-php
8383
tools/sidecar_mockgen/ @DataDog/libdatadog-php
84+
libdd-data-pipeline/src/otlp/ @DataDog/apm-sdk-capabilities
85+
libdd-data-pipeline/tests/test_trace_exporter_otlp_export.rs @DataDog/apm-sdk-capabilities
86+
libdd-trace-utils/src/otlp_encoder/ @DataDog/apm-sdk-capabilities

.github/actions/clippy-annotation-reporter/action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ runs:
2525
steps:
2626
- name: Set up Rust
2727
shell: bash
28-
run: rustup install stable && rustup default stable
28+
run: rustup set profile minimal && rustup install stable && rustup default stable
2929

3030
- name: Fetch all branches
3131
shell: bash

.github/workflows/all-checks.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ jobs:
1616
delay: '3'
1717
retries: '45'
1818
polling_interval: '1'
19-
checks_exclude: 'devflow/merge,dd-gitlab/default-pipeline'
19+
checks_exclude: 'devflow/merge,dd-gitlab/default-pipeline,Rustfmt Auto / rustfmt'

.github/workflows/clippy-annotation-reporter.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
with:
2929
fetch-depth: 0 # Full history
3030
- name: Install Rust
31-
run: rustup install stable
31+
run: rustup set profile minimal && rustup install stable
3232
- name: Run annotation reporter
3333
uses: ./.github/actions/clippy-annotation-reporter
3434
with:

.github/workflows/coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ jobs:
2929
with:
3030
submodules: recursive
3131
- name: Install Rust
32-
run: rustup install nightly-2026-02-08 && rustup default nightly-2026-02-08
32+
run: rustup set profile minimal && rustup install nightly-2026-02-08 && rustup default nightly-2026-02-08
3333
- name: Install cargo-llvm-cov
3434
uses: taiki-e/install-action@2c41309d51ede152b6f2ee6bf3b71e6dc9a8b7df # 2.49.27
3535
with:

.github/workflows/lint.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
with:
2828
submodules: recursive
2929
- name: Install nightly-2026-02-08 toolchain and rustfmt
30-
run: rustup install nightly-2026-02-08 && rustup default nightly-2026-02-08 && rustup component add rustfmt
30+
run: rustup set profile minimal && rustup install nightly-2026-02-08 && rustup default nightly-2026-02-08 && rustup component add rustfmt
3131
- name: Cache [rust]
3232
uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # 2.8.1
3333
with:
@@ -48,7 +48,7 @@ jobs:
4848
with:
4949
submodules: recursive
5050
- name: Install ${{ matrix.rust_version }} toolchain and clippy
51-
run: rustup install ${{ matrix.rust_version }} && rustup default ${{ matrix.rust_version }} && rustup component add clippy
51+
run: rustup set profile minimal && rustup install ${{ matrix.rust_version }} && rustup default ${{ matrix.rust_version }} && rustup component add clippy
5252
- name: Cache [rust]
5353
uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # 2.8.1
5454
with:

.github/workflows/pr-title-semver-check.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,9 @@ jobs:
9191

9292
- name: Install Rust ${{ env.RUST_VERSION }}
9393
run: |
94+
rustup set profile minimal
9495
rustup install ${{ env.RUST_VERSION }} && rustup default ${{ env.RUST_VERSION }}
95-
rustup toolchain install nightly-2026-02-08 --profile minimal
96+
rustup toolchain install nightly-2026-02-08
9697
# Link the dated nightly as 'nightly' for tools (like cargo-public-api) that expect it
9798
ln -sf ~/.rustup/toolchains/nightly-2026-02-08-x86_64-unknown-linux-gnu ~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu
9899

.github/workflows/release-proposal-dispatch.yml

Lines changed: 162 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,30 @@ on:
2323
- libdd-trace-protobuf
2424
- libdd-trace-stats
2525
- libdd-trace-utils
26+
main_start_ref:
27+
description: >
28+
Optional git ref to cut the release from: commit SHA (short or full), branch name,
29+
tag, or refs/... (e.g. main, v1.2.3, origin/main). Leave empty to use latest
30+
origin/main.
31+
required: false
32+
type: string
33+
default: ''
34+
bypass_standard_checks:
35+
description: >
36+
Skip ongoing-proposal checks. Proposal branches use prefix
37+
release-proposal-testing so they do not collide with normal release-proposal/* runs.
38+
required: false
39+
type: boolean
40+
default: false
2641

2742
concurrency:
2843
group: release-proposal-dispatch-group
2944
cancel-in-progress: false
3045

3146
env:
3247
MAIN_BRANCH: main
33-
PROPOSAL_BRANCH_PREFIX: release-proposal
34-
GIT_USER_NAME: "dd-octo-sts[bot]"
35-
GIT_USER_EMAIL: "200755185+dd-octo-sts[bot]@users.noreply.github.com"
48+
RELEASE_BRANCH_PREFIX: ${{ inputs.bypass_standard_checks && 'release-testing' || 'release' }}
49+
PROPOSAL_BRANCH_PREFIX: ${{ inputs.bypass_standard_checks && 'release-proposal-testing' || 'release-proposal' }}
3650

3751
jobs:
3852
check-proposal-ongoing:
@@ -44,15 +58,19 @@ jobs:
4458
fetch-tags: true
4559
- name: Check if a release proposal is ongoing
4660
run: |
47-
# Check if there are any proposal branches or ephemeral release branches (release/*/*)
48-
EXISTING_BRANCHES=$(git branch -r --list "origin/${{ env.PROPOSAL_BRANCH_PREFIX }}/*" "origin/release/*/*")
49-
if [ -n "$EXISTING_BRANCHES" ]; then
50-
echo "Error: A release proposal is ongoing. Please cancel it or wait for it to be merged." >&2
51-
echo "Existing branches:"
52-
echo "$EXISTING_BRANCHES"
53-
exit 1
61+
if [ "${{ inputs.bypass_standard_checks }}" = "true" ]; then
62+
echo "Skipping ongoing release proposal checks."
63+
else
64+
# Check if there are any proposal branches or ephemeral release branches (release/*/*)
65+
EXISTING_BRANCHES=$(git branch -r --list "origin/${{ env.PROPOSAL_BRANCH_PREFIX }}/*" "origin/${{ env.RELEASE_BRANCH_PREFIX }}/*/*")
66+
if [ -n "$EXISTING_BRANCHES" ]; then
67+
echo "Error: A release proposal is ongoing. Please cancel it or wait for it to be merged." >&2
68+
echo "Existing branches:"
69+
echo "$EXISTING_BRANCHES"
70+
exit 1
71+
fi
72+
echo "No release proposal is ongoing."
5473
fi
55-
echo "No release proposal is ongoing."
5674
5775
check-membership:
5876
permissions:
@@ -82,7 +100,7 @@ jobs:
82100
echo "User is not part of apm-common-components-core"
83101
exit 1
84102
fi
85-
103+
86104
cargo-release:
87105
permissions:
88106
id-token: write # Enable OIDC
@@ -120,19 +138,100 @@ jobs:
120138
with:
121139
122140

141+
- uses: DataDog/dd-octo-sts-action@acaa02eee7e3bb0839e4272dacb37b8f3b58ba80 # v1.0.3
142+
id: octo-sts
143+
with:
144+
scope: DataDog/libdatadog
145+
policy: self.write.pr
146+
123147
- name: Configure Git for signing
148+
env:
149+
GH_TOKEN: ${{ steps.octo-sts.outputs.token }}
150+
GITHUB_ACTOR: ${{ github.actor }}
124151
run: |
125-
git config --global user.name "${{ env.GIT_USER_NAME }}"
126-
git config --global user.email "${{ env.GIT_USER_EMAIL }}"
152+
# GET /user is not allowed with installation tokens; use GET /users/ACTOR (who triggered the workflow).
153+
GITHUB_USER_RESPONSE=$(curl -s -H "Authorization: token ${GH_TOKEN}" "https://api.github.com/users/${GITHUB_ACTOR}")
154+
GIT_USER_NAME=$(echo "${GITHUB_USER_RESPONSE}" | jq -r '.login // empty')
155+
GIT_USER_ID=$(echo "${GITHUB_USER_RESPONSE}" | jq -r '.id // empty')
156+
if [[ -z "$GIT_USER_NAME" ]]; then
157+
GIT_USER_NAME="${GITHUB_ACTOR}"
158+
GIT_USER_EMAIL="${GITHUB_ACTOR}@users.noreply.github.com"
159+
else
160+
GIT_USER_EMAIL="${GIT_USER_ID}+${GIT_USER_NAME}@users.noreply.github.com"
161+
fi
162+
echo "GIT_USER_NAME: $GIT_USER_NAME"
163+
echo "GIT_USER_EMAIL: $GIT_USER_EMAIL"
164+
git config --global user.name "$GIT_USER_NAME"
165+
git config --global user.email "$GIT_USER_EMAIL"
127166
167+
- name: Optionally checkout at a specific git ref
168+
env:
169+
MAIN_START_REF: ${{ inputs.main_start_ref }}
170+
run: |
171+
set -euo pipefail
172+
git fetch origin "${{ env.MAIN_BRANCH }}" --tags --prune
173+
174+
resolve_to_commit() {
175+
local r="$1"
176+
local c=""
177+
# Already a commit or resolvable locally
178+
c=$(git rev-parse -q --verify "${r}^{commit}" 2>/dev/null) || true
179+
if [ -n "$c" ]; then
180+
echo "$c"
181+
return 0
182+
fi
183+
# Remote branch: origin/<name>
184+
c=$(git rev-parse -q --verify "origin/${r}^{commit}" 2>/dev/null) || true
185+
if [ -n "$c" ]; then
186+
echo "$c"
187+
return 0
188+
fi
189+
# Tag
190+
c=$(git rev-parse -q --verify "refs/tags/${r}^{commit}" 2>/dev/null) || true
191+
if [ -n "$c" ]; then
192+
echo "$c"
193+
return 0
194+
fi
195+
return 1
196+
}
197+
198+
if [ -n "${MAIN_START_REF// }" ]; then
199+
REF=$(echo "$MAIN_START_REF" | tr -d '[:space:]')
200+
if [ -z "$REF" ]; then
201+
echo "Error: main_start_ref is whitespace-only." >&2
202+
exit 1
203+
fi
204+
# Try to fetch the ref from origin (branches, tags, and SHA objects)
205+
git fetch origin "$REF" 2>/dev/null || true
206+
207+
COMMIT=""
208+
COMMIT=$(resolve_to_commit "$REF") || true
209+
if [ -z "$COMMIT" ]; then
210+
# e.g. short SHA or ref only present after full fetch
211+
git fetch origin "$REF:$REF" 2>/dev/null || true
212+
COMMIT=$(resolve_to_commit "$REF") || true
213+
fi
214+
if [ -z "$COMMIT" ]; then
215+
echo "Error: could not resolve git ref to a commit: $REF" >&2
216+
echo "Try a full SHA, a branch/tag name on origin, or refs/heads/... / refs/tags/..." >&2
217+
exit 1
218+
fi
219+
git checkout "$COMMIT"
220+
echo "Release cut from ref '$REF' -> $COMMIT ($(git log -1 --oneline))"
221+
else
222+
git checkout "${{ env.MAIN_BRANCH }}"
223+
git reset --hard "origin/${{ env.MAIN_BRANCH }}"
224+
echo "Release cut from origin/${{ env.MAIN_BRANCH }} tip ($(git rev-parse --short HEAD))."
225+
fi
226+
128227
- name: Create ephemeral release branch
129228
id: ephemeral-branch
130229
run: |
131230
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
132-
EPHEMERAL_BRANCH="release/${{ inputs.crate }}/$TIMESTAMP"
231+
EPHEMERAL_BRANCH="${{ env.RELEASE_BRANCH_PREFIX }}/${{ inputs.crate }}/$TIMESTAMP"
133232
git checkout -b "$EPHEMERAL_BRANCH"
134233
git push origin "$EPHEMERAL_BRANCH"
135-
echo "Ephemeral release branch created: $EPHEMERAL_BRANCH from ${{ env.MAIN_BRANCH }} branch"
234+
echo "Ephemeral release branch created: $EPHEMERAL_BRANCH branch ($(git rev-parse --short HEAD))"
136235
echo "ephemeral_branch=$EPHEMERAL_BRANCH" >> "$GITHUB_OUTPUT"
137236
echo "timestamp=$TIMESTAMP" >> "$GITHUB_OUTPUT"
138237
@@ -146,6 +245,7 @@ jobs:
146245
cat /tmp/crates.json
147246
148247
- name: Get commits since last release for each crate
248+
id: commits-since-release
149249
run: |
150250
# Get commits since release for each crate and save to file
151251
./scripts/commits-since-release.sh "$(cat /tmp/crates.json)" > /tmp/commits-by-crate.json
@@ -154,7 +254,8 @@ jobs:
154254
# so tag/merge-base resolution uses the same ref the script used.
155255
git rev-parse HEAD > /tmp/release_head_sha
156256
echo "Release branch HEAD (saved for later): $(cat /tmp/release_head_sha)"
157-
257+
echo "release_head_sha=$(cat /tmp/release_head_sha)" >> "$GITHUB_OUTPUT"
258+
158259
# Display json output
159260
jq . /tmp/commits-by-crate.json
160261
@@ -264,8 +365,12 @@ jobs:
264365
LATEST_TAG=$(git tag -l "$TAG_PREFIX*" --sort=-v:refname | head -1)
265366
if [ "$LATEST_TAG" != "$TAG" ]; then
266367
echo "Tag $TAG is not the latest. Latest is: $LATEST_TAG. main branch has the latest release for $NAME"
267-
echo "Skipping release for $NAME"
268-
continue
368+
if [ "${{ inputs.bypass_standard_checks }}" = "false" ]; then
369+
echo "Skipping release for $NAME"
370+
continue
371+
else
372+
echo "Continuing with the release for $NAME because bypass_standard_checks is true"
373+
fi
269374
fi
270375
271376
echo "Executing semver-level.sh for $NAME since $RANGE (tag: $TAG)..."
@@ -360,13 +465,23 @@ jobs:
360465
exit 1
361466
fi
362467
363-
echo "Pushing branch $BRANCH_NAME to origin..."
364-
git push origin "$BRANCH_NAME"
468+
# Oldest → newest (chronological). Plain `git log` is newest-first; commit-headless should receive
469+
# parent→child order so replays/signing match git history. Space-separated SHAs for the action.
470+
COMMITS=$(git log --reverse "$ORIGINAL_HEAD".. --format='%H' | tr '\n' ' ' | xargs)
471+
echo "commits=$COMMITS" >> $GITHUB_OUTPUT
365472
366473
# Output the results
367474
echo "API changes summary:"
368475
jq . /tmp/api-changes.json
369476
477+
- name: Push commits
478+
uses: DataDog/commit-headless@action/v2.0.3
479+
with:
480+
branch: ${{ steps.proposal-branch.outputs.branch_name }}
481+
head-sha: ${{ steps.commits-since-release.outputs.release_head_sha }}
482+
command: push
483+
commits: "${{ steps.release-version-bumps.outputs.commits }}"
484+
370485
- name: Upload release data
371486
uses: actions/upload-artifact@v4
372487
with:
@@ -412,7 +527,6 @@ jobs:
412527
name: release-dispatch-data
413528
path: /tmp
414529

415-
416530
- uses: DataDog/dd-octo-sts-action@acaa02eee7e3bb0839e4272dacb37b8f3b58ba80 # v1.0.3
417531
id: octo-sts
418532
with:
@@ -422,9 +536,25 @@ jobs:
422536
- name: Create a PR
423537
env:
424538
GH_TOKEN: ${{ steps.octo-sts.outputs.token }}
539+
MAIN_START_REF: ${{ inputs.main_start_ref }}
540+
MAIN_BRANCH: ${{ env.MAIN_BRANCH }}
541+
BYPASS_STANDARD_CHECKS: ${{ inputs.bypass_standard_checks }}
542+
PROPOSAL_BRANCH_PREFIX: ${{ env.PROPOSAL_BRANCH_PREFIX }}
543+
RELEASE_BRANCH_PREFIX: ${{ env.RELEASE_BRANCH_PREFIX }}
425544
run: |
426545
BRANCH_NAME="${{ needs.cargo-release.outputs.branch_name }}"
427-
546+
547+
NON_DEFAULT=""
548+
if [ -n "$MAIN_START_REF" ]; then
549+
NON_DEFAULT="${NON_DEFAULT}"$'\n### Cut from non-default ref\n\n'"This proposal was generated from \`$MAIN_START_REF\` instead of the default latest \`origin/$MAIN_BRANCH\`."$'\n'
550+
fi
551+
if [ "$BYPASS_STANDARD_CHECKS" = "true" ]; then
552+
NON_DEFAULT="${NON_DEFAULT}"$'\n### Non-default workflow options\n\n'"**bypass_standard_checks** was enabled: the ongoing-proposal branch guard was skipped; branches use proposal prefix \`$PROPOSAL_BRANCH_PREFIX\` and release prefix \`$RELEASE_BRANCH_PREFIX\`. Crates whose resolved git tag is not the latest SemVer tag for that crate are still included (normally skipped)."$'\n'
553+
fi
554+
if [ -n "$NON_DEFAULT" ]; then
555+
NON_DEFAULT="${NON_DEFAULT}"$'\n\n'
556+
fi
557+
428558
# Generate the PR body by merging commits and API changes
429559
# Note: read returns 1 when it reaches EOF, which is expected for heredocs
430560
read -r -d '' JQ_FILTER << 'EOF' || true
@@ -436,7 +566,7 @@ jobs:
436566
[
437567
"## \($crate.name)",
438568
"",
439-
(if $api_info.version then "**Next version:** `\($api_info.version)`\n" else null end),
569+
(if $api_info.version then "**Next version:** `\($api_info.version)`" else null end),
440570
"**Semver bump:** `\($api_info.level)`",
441571
(if $api_info.tag then "**Tag:** `\($api_info.tag)`\n" else null end),
442572
(if $api_info.initial_release == "true" then
@@ -446,25 +576,27 @@ jobs:
446576
] | map(select(. != null and . != "")) | join("\n")
447577
EOF
448578
449-
PR_BODY=$(jq -r --slurpfile api /tmp/api-changes.json "$JQ_FILTER" /tmp/commits-by-crate.json)
450-
579+
COMMITS_AND_API_BODY=$(jq -r --slurpfile api /tmp/api-changes.json "$JQ_FILTER" /tmp/commits-by-crate.json)
580+
451581
PR_BODY="# Release proposal for ${{ inputs.crate }} and its dependencies
452582
453583
This PR contains version bumps based on public API changes and commits since last release.
454584
455-
${PR_BODY}"
585+
${NON_DEFAULT}${COMMITS_AND_API_BODY}"
456586
457-
echo "PR_BODY: $PR_BODY"
587+
echo "$PR_BODY" > /tmp/pr-body.md
588+
echo "PR body written to /tmp/pr-body.md (length: $(wc -c < /tmp/pr-body.md) bytes)"
458589
459590
# NOTE: the PR title is used to filter gitlab CI jobs. If you change it, you need to update the gitlab CI job filter.
460591
gh pr create \
461592
--head "$BRANCH_NAME" \
462593
--title "chore(release): proposal for ${{ inputs.crate }}" \
463-
--body "$PR_BODY" \
594+
--body-file /tmp/pr-body.md \
464595
--label "release-proposal" \
465596
--label "skip-metadata-check" \
466597
--label "skip-changelog-check" \
467-
--base "${{ needs.cargo-release.outputs.ephemeral_branch }}"
598+
--base "${{ needs.cargo-release.outputs.ephemeral_branch }}" \
599+
--draft
468600
469601
- name: Cleanup on failure
470602
if: failure() && (needs.cargo-release.outputs.branch_name != '' || needs.cargo-release.outputs.ephemeral_branch != '')

0 commit comments

Comments
 (0)