Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 102 additions & 40 deletions .github/workflows/release-proposal-dispatch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,14 @@ name: Release - Open a release proposal PR
on:
workflow_dispatch:
inputs:
crate:
description: Crate to release
crates:
description: >
Crate(s) to release. Names separated by commas or whitespace (e.g. "libdd-common" or "libdd-common, libdd-telemetry").
Each selected crate is released along with its workspace dependencies (other libdd-* crates it depends on).
Hotfix releases (main_start_ref matching hotfix/<crate>/<N>.x.x) accept a single crate only.
required: true
type: choice
options:
- libdd-alloc
- libdd-capabilities
- libdd-capabilities-impl
- libdd-common
- libdd-crashtracker
- libdd-data-pipeline
- libdd-ddsketch
- libdd-dogstatsd-client
- libdd-http-client
- libdd-library-config
- libdd-log
- libdd-otel-thread-ctx
- libdd-profiling
- libdd-profiling-protobuf
- libdd-sampling
- libdd-shared-runtime
- libdd-telemetry
- libdd-tinybytes
- libdd-trace-normalization
- libdd-trace-obfuscation
- libdd-trace-protobuf
- libdd-trace-stats
- libdd-trace-utils
- libdd-tracer-flare
type: string
default: ''
main_start_ref:
description: >
Optional git ref to cut the release from: commit SHA (short or full), branch name,
Expand All @@ -57,8 +36,81 @@ env:
PROPOSAL_BRANCH_PREFIX: ${{ inputs.bypass_standard_checks && 'release-proposal-testing' || 'release-proposal' }}

jobs:
validate-inputs:
runs-on: ubuntu-latest
outputs:
crates: ${{ steps.normalize.outputs.crates }}
crates_display: ${{ steps.normalize.outputs.crates_display }}
crates_branch: ${{ steps.normalize.outputs.crates_branch }}
count: ${{ steps.normalize.outputs.count }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
- name: Normalize and validate crate list
id: normalize
env:
RAW_CRATES: ${{ inputs.crates }}
RAW_MAIN_START_REF: ${{ inputs.main_start_ref }}
run: |
set -euo pipefail

# Split on commas/whitespace, drop empties, dedupe, sort for stable downstream order.
mapfile -t CRATES < <(printf '%s\n' "$RAW_CRATES" | tr ',' ' ' | tr -s '[:space:]' '\n' | sed '/^$/d' | sort -u)

if [ "${#CRATES[@]}" -eq 0 ]; then
echo "Error: 'crates' input is empty after normalization." >&2
exit 1
fi

mapfile -t AVAILABLE < <(cargo metadata --no-deps --format-version=1 | jq -r '
.packages[]
| select(.publish == null or (.publish | type == "array" and length > 0))
| .name
' | sort -u)

UNKNOWN=()
for c in "${CRATES[@]}"; do
if ! printf '%s\n' "${AVAILABLE[@]}" | grep -qxF "$c"; then
UNKNOWN+=("$c")
fi
done
if [ "${#UNKNOWN[@]}" -gt 0 ]; then
echo "Error: unknown or unpublishable crate(s): ${UNKNOWN[*]}" >&2
echo "Available crates:" >&2
printf ' - %s\n' "${AVAILABLE[@]}" >&2
exit 1
fi

REF="$(echo "$RAW_MAIN_START_REF" | tr -d '[:space:]')"
if [[ -n "$REF" && "$REF" =~ ^hotfix/[^/]+/[0-9]+\.x\.x$ ]] && [ "${#CRATES[@]}" -gt 1 ]; then
echo "Error: hotfix releases (main_start_ref=$REF) accept only a single crate; got ${#CRATES[@]}: ${CRATES[*]}" >&2
exit 1
fi

CRATES_SPACE="${CRATES[*]}"
CRATES_DISPLAY=$(IFS=,; echo "${CRATES[*]}")
CRATES_DISPLAY=${CRATES_DISPLAY//,/, }
# Branch segment: keep the path concise when many crates are bundled.
if [ "${#CRATES[@]}" -eq 1 ]; then
CRATES_BRANCH="${CRATES[0]}"
else
CRATES_BRANCH="${CRATES[0]}+$(( ${#CRATES[@]} - 1 ))-more"
fi

echo "Normalized crates: $CRATES_SPACE"
echo "Display: $CRATES_DISPLAY"
echo "Branch segment: $CRATES_BRANCH"
echo "Count: ${#CRATES[@]}"

{
echo "crates=$CRATES_SPACE"
echo "crates_display=$CRATES_DISPLAY"
echo "crates_branch=$CRATES_BRANCH"
echo "count=${#CRATES[@]}"
} >> "$GITHUB_OUTPUT"

check-proposal-ongoing:
runs-on: ubuntu-latest
needs: validate-inputs
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
with:
Expand Down Expand Up @@ -114,7 +166,7 @@ jobs:
id-token: write # Enable OIDC
pull-requests: write
contents: write
needs: check-membership
needs: [check-membership, validate-inputs]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2
Expand Down Expand Up @@ -276,7 +328,7 @@ jobs:
echo "ephemeral_branch=$EPHEMERAL_BRANCH" >> "$GITHUB_OUTPUT"
echo "is_hotfix=true" >> "$GITHUB_OUTPUT"
else
EPHEMERAL_BRANCH="${{ env.RELEASE_BRANCH_PREFIX }}/${{ inputs.crate }}/$TIMESTAMP"
EPHEMERAL_BRANCH="${{ env.RELEASE_BRANCH_PREFIX }}/${{ needs.validate-inputs.outputs.crates_branch }}/$TIMESTAMP"
git checkout -b "$EPHEMERAL_BRANCH"
git push origin "$EPHEMERAL_BRANCH"
echo "Ephemeral release branch created: $EPHEMERAL_BRANCH branch ($(git rev-parse --short HEAD))"
Expand All @@ -286,11 +338,14 @@ jobs:
echo "timestamp=$TIMESTAMP" >> "$GITHUB_OUTPUT"

- name: Get publication order for crate and dependencies
env:
CRATES: ${{ needs.validate-inputs.outputs.crates }}
run: |
echo "Getting publication order for ${{ inputs.crate }}..."

# Get the publication order as JSON and save to file
"${WORKFLOW_SCRIPTS_ROOT}/publication-order.sh" --format=json "${{ inputs.crate }}" > /tmp/crates.json
echo "Getting publication order for ${{ needs.validate-inputs.outputs.crates_display }}..."

# CRATES is a space-separated list validated upstream; word-splitting is intentional.
# shellcheck disable=SC2086
"${WORKFLOW_SCRIPTS_ROOT}/publication-order.sh" --format=json $CRATES > /tmp/crates.json
echo "Publication order:"
cat /tmp/crates.json

Expand Down Expand Up @@ -325,7 +380,7 @@ jobs:

git checkout "${{ steps.ephemeral-branch.outputs.ephemeral_branch }}"
TIMESTAMP="${{ steps.ephemeral-branch.outputs.timestamp }}"
BRANCH_NAME="${{ env.PROPOSAL_BRANCH_PREFIX }}/${{ inputs.crate }}/$TIMESTAMP"
BRANCH_NAME="${{ env.PROPOSAL_BRANCH_PREFIX }}/${{ needs.validate-inputs.outputs.crates_branch }}/$TIMESTAMP"
git checkout -b "$BRANCH_NAME"
git push origin "$BRANCH_NAME" --tags
echo "Branch created: $BRANCH_NAME from ${{ steps.ephemeral-branch.outputs.ephemeral_branch }} branch"
Expand Down Expand Up @@ -687,7 +742,7 @@ jobs:
is_hotfix: ${{ steps.ephemeral-branch.outputs.is_hotfix }}

create-pr:
needs: cargo-release
needs: [cargo-release, validate-inputs]
runs-on: ubuntu-latest
permissions:
id-token: write # Enable OIDC
Expand Down Expand Up @@ -718,6 +773,7 @@ jobs:
BYPASS_STANDARD_CHECKS: ${{ inputs.bypass_standard_checks }}
PROPOSAL_BRANCH_PREFIX: ${{ env.PROPOSAL_BRANCH_PREFIX }}
RELEASE_BRANCH_PREFIX: ${{ env.RELEASE_BRANCH_PREFIX }}
CRATES_COUNT: ${{ needs.validate-inputs.outputs.count }}
run: |
BRANCH_NAME="${{ needs.cargo-release.outputs.branch_name }}"
EPHEMERAL_BRANCH="${{ needs.cargo-release.outputs.ephemeral_branch }}"
Expand Down Expand Up @@ -766,19 +822,25 @@ jobs:

COMMITS_AND_API_BODY=$(jq -nr --slurpfile api /tmp/api-changes-with-major-bumps.json "$JQ_FILTER")

PR_BODY="# Release proposal for ${{ inputs.crate }} and its dependencies
if [ "$CRATES_COUNT" -gt 1 ]; then
POSSESSIVE="their"
else
POSSESSIVE="its"
fi

PR_BODY="# Release proposal for ${{ needs.validate-inputs.outputs.crates_display }} and $POSSESSIVE dependencies

This PR contains version bumps based on public API changes and commits since last release.

${HOTFIX_NOTE}${NON_DEFAULT}${COMMITS_AND_API_BODY}"

echo "$PR_BODY" > /tmp/pr-body.md
echo "PR body written to /tmp/pr-body.md (length: $(wc -c < /tmp/pr-body.md) bytes)"

# NOTE: the PR title is used to filter gitlab CI jobs. If you change it, you need to update the gitlab CI job filter.
# NOTE: the PR title must start with 'chore(release): proposal for'. Downstream tooling matches on that prefix.
gh pr create \
--head "$BRANCH_NAME" \
--title "chore(release): proposal for ${{ inputs.crate }}" \
--title "chore(release): proposal for ${{ needs.validate-inputs.outputs.crates_display }}" \
--body-file /tmp/pr-body.md \
--label "release-proposal" \
--label "skip-metadata-check" \
Expand Down
Loading