diff --git a/.github/workflows/block_if_release.yml.off b/.github/workflows/block_if_release.yml.off new file mode 100644 index 0000000000..9caed919c6 --- /dev/null +++ b/.github/workflows/block_if_release.yml.off @@ -0,0 +1,25 @@ +name: Block if there is an ongoing release +env: + RELEASE_BRANCH_PREFIX: release-v + +on: + pull_request: + push: + branches: + - main +jobs: + ongoing-release: + runs-on: ubuntu-latest + permissions: + checks: read + contents: read + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + - name: Fail if release branch exists + run: | + if git ls-remote --heads origin | grep -q "refs/heads/${RELEASE_BRANCH_PREFIX}"; then + echo "A release branch with prefix '${RELEASE_BRANCH_PREFIX}' exists. Failing workflow." + exit 1 + else + echo "No release branch found with prefix '${RELEASE_BRANCH_PREFIX}'. Continuing." + fi diff --git a/.github/workflows/block_if_release_rerun.yml.off b/.github/workflows/block_if_release_rerun.yml.off new file mode 100644 index 0000000000..ca737fe680 --- /dev/null +++ b/.github/workflows/block_if_release_rerun.yml.off @@ -0,0 +1,65 @@ +name: Rerun block_if_release when creating or deleting a release branch +env: + RELEASE_BRANCH_PREFIX: release-v + +on: [create, delete] + +permissions: + actions: write + contents: read + +jobs: + rerun-block-if-release: + runs-on: ubuntu-latest + steps: + - name: Check if ref is release branch + id: check_release_branch + run: | + echo "Event: name: ${{ github.event_name }}, ref: ${{ github.event.ref }}" + echo "Ref: ${{ github.ref }}" + echo "Ref type: ${{ github.event.ref_type }}" # branch or tag + if [[ "${{ github.event.ref_type }}" == "branch" && "${{ github.event.ref }}" == "${RELEASE_BRANCH_PREFIX}"* ]]; then + echo "is_release_branch=true" >> $GITHUB_OUTPUT + else + echo "is_release_branch=false" >> $GITHUB_OUTPUT + fi + + - name: Trigger block_if_release on open PRs + id: trigger + if: steps.check_release_branch.outputs.is_release_branch == 'true' + uses: actions/github-script@v7 + with: + script: | + // TODO: filter out inactive PRs checking last update (if possible) + const prs = await github.rest.pulls.list({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open' + }); + for (const pr of prs.data) { + console.log('Checking PR: ', pr.url) + + // Get workflow runs for the PR's branch + const runs = await github.rest.actions.listWorkflowRunsForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + branch: pr.head.ref, + event: "pull_request" + }); + + // Find the latest run for the desired workflow + const run = runs.data.workflow_runs.find( + r => r.name === "Block if there is an ongoing release" || r.path.endsWith('block_if_release.yml') + ); + if (run) { + console.log('Rerunning: ', run.id, run.html_url) + + await github.rest.actions.reRunWorkflow({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: run.id + }); + } else { + console.log('There is no run') + } + } diff --git a/.github/workflows/cargo_checks.yml b/.github/workflows/cargo_checks.yml new file mode 100644 index 0000000000..be9c67221e --- /dev/null +++ b/.github/workflows/cargo_checks.yml @@ -0,0 +1,167 @@ +name: Cargo checks +on: + pull_request: + push: + branches: [main] +jobs: + cargo-deny: + runs-on: ubuntu-latest + continue-on-error: true + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + - uses: EmbarkStudios/cargo-deny-action@f2ba7abc2abebaf185c833c3961145a3c275caad # 2.0.13 + with: + command: check advisories bans sources # licenses + + version-and-changelog: + runs-on: ubuntu-latest + strategy: + fail-fast: false + # max-parallel: 1 + matrix: + # crate: [ddcommon, ddtelemetry, ddsketch, Library-config, Datadog-crashtracker, cc_utils, data-pipeline, datadog-trace-protobuf, datadog-trace-normalization, datadog-trace-utils, dogstatsd-client, tinybytes, datadog-log] + crate: [ddcommon] + env: + CRATE: ${{ matrix.crate }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + with: + fetch-depth: 0 + fetch-tags: true + - uses: r7kamura/rust-problem-matchers@9fe7ca9f6550e5d6358e179d451cc25ea6b54f98 #v1.5.0 + + - uses: dtolnay/rust-toolchain@stable + + - uses: Swatinem/rust-cache@f13886b937689c021905a6b90929199931d60db1 # v2.8.1 + with: + shared-key: stable-cache + save-if: false + + - uses: taiki-e/cache-cargo-install-action@v2 + with: + tool: tomlq + + - name: Extract version from manifest + run: | + CRATE_VERSION=$(cargo metadata --format-version=1 --no-deps | jq -e -r '.packages[] | select(.name == "'"$CRATE"'") | .version') + + echo "CRATE_VERSION=$CRATE_VERSION" >> $GITHUB_ENV + + # this could be enabled when defining dependencies in Cargo.toml + # - name: Enforce version in `workspace.dependencies` matches the latest version + # run: | + # SPECIFIED_VERSION=$(tq "workspace.dependencies.$CRATE.version" -r --file ./Cargo.toml) + + # echo "Package version: $CRATE_VERSION"; + # echo "Specified version: $SPECIFIED_VERSION"; + + # test "$CRATE_VERSION" = "$SPECIFIED_VERSION" || test "=$CRATE_VERSION" = "$SPECIFIED_VERSION" + + - name: Enforce version in CHANGELOG.md matches the version in manifest + run: | + MANIFEST_PATH=$(cargo metadata --format-version=1 --no-deps | jq -e -r '.packages[] | select(.name == "'"$CRATE"'") | .manifest_path') + DIR_TO_CRATE=$(dirname "$MANIFEST_PATH") + VERSION_IN_CHANGELOG=$(awk -F' ' '/^## [0-9]+\.[0-9]+\.[0-9]+/{print $2; exit}' "$DIR_TO_CRATE/CHANGELOG.md") + + echo "Package version: $CRATE_VERSION"; + echo "Changelog version: $VERSION_IN_CHANGELOG"; + + test "$CRATE_VERSION" = "$VERSION_IN_CHANGELOG" + + - name: Ensure manifest and CHANGELOG are properly updated + if: > + github.event_name == 'pull_request' && + !startsWith(github.event.pull_request.title, 'chore') && + !startsWith(github.event.pull_request.title, 'refactor') && + !startsWith(github.event.pull_request.title, 'deps') && + !startsWith(github.event.pull_request.title, 'docs') && + !contains(github.event.pull_request.labels.*.name, 'internal-change') + run: | + git fetch origin main:main + git fetch origin ${{ github.event.pull_request.base.ref }}:${{ github.event.pull_request.base.ref }} + ./scripts/ensure-version-bump-and-changelog.sh + env: + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + PR_BASE: ${{ github.event.pull_request.base.ref }} + + + detect-changes: + runs-on: ubuntu-latest + outputs: + changed-packages: ${{ steps.detect.outputs.packages }} + has-changes: ${{ steps.detect.outputs.has-changes }} + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + with: + fetch-depth: 0 # Need full history for cargo release changes + + - name: Install cargo-release + uses: taiki-e/install-action@d6d752794628f1e1fffa3c4d3c8874e06f043d50 # 2.62.15 + with: + tool: cargo-release + + - id: detect + name: Detect changed packages and their baseline tags + run: | + # Get changed packages from cargo release changes + # Extract package names from lines like "Changes for {package} from" + packages_list=$(cargo release changes 2>&1 | grep "Changes for" | sed 's/.*Changes for \([^ ]*\) from.*/\1/' | sort -u) + + if [ -z "$packages_list" ]; then + echo "has-changes=false" >> $GITHUB_OUTPUT + echo "packages=[]" >> $GITHUB_OUTPUT + echo "No changed packages detected" + else + echo "has-changes=true" >> $GITHUB_OUTPUT + + # Build JSON array with package and baseline-rev for each package + packages_json="[]" + while IFS= read -r pkg; do + [ -z "$pkg" ] && continue + + # Find the latest tag for this package (format: {package}-v{version}) + latest_tag=$(git tag -l "${pkg}-v*" --sort=-version:refname | head -n 1) + + if [ -z "$latest_tag" ]; then + echo "Warning: No tag found for package $pkg, skipping baseline" + baseline="" + else + baseline="$latest_tag" + echo "Package $pkg -> baseline $baseline" + fi + + # Add to JSON array with compact output (-c flag) + packages_json=$(echo "$packages_json" | jq -c --arg pkg "$pkg" --arg baseline "$baseline" '. += [{"package": $pkg, "baseline-rev": $baseline}]') + done <<< "$packages_list" + + # Output as compact JSON (ensure no newlines) + echo "packages=$(echo "$packages_json" | jq -c .)" >> $GITHUB_OUTPUT + echo "Changed packages with baselines: $packages_json" + fi + + semver: + needs: detect-changes + if: needs.detect-changes.outputs.has-changes == 'true' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: ${{ fromJson(needs.detect-changes.outputs.changed-packages) }} + env: + # Unset the global `RUSTFLAGS` env to allow warnings. + # cargo-semver-checks intentionally re-locks dependency versions + # before checking, and we shouldn't fail here if a dep has a warning. + # + # More context: + # https://github.com/libp2p/rust-libp2p/pull/4932#issuecomment-1829014527 + # https://github.com/obi1kenobi/cargo-semver-checks/issues/589 + RUSTFLAGS: '' + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + with: + fetch-depth: 0 + fetch-tags: true + - uses: obi1kenobi/cargo-semver-checks-action@5b298c9520f7096a4683c0bd981a7ac5a7e249ae # v2.8 + with: + package: ${{ matrix.package }} + baseline-rev: ${{ matrix.baseline-rev }} diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml.off similarity index 100% rename from .github/workflows/coverage.yml rename to .github/workflows/coverage.yml.off diff --git a/.github/workflows/fuzz.yml b/.github/workflows/fuzz.yml.off similarity index 100% rename from .github/workflows/fuzz.yml rename to .github/workflows/fuzz.yml.off diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml.off similarity index 100% rename from .github/workflows/lint.yml rename to .github/workflows/lint.yml.off diff --git a/.github/workflows/miri.yml b/.github/workflows/miri.yml.off similarity index 100% rename from .github/workflows/miri.yml rename to .github/workflows/miri.yml.off diff --git a/.github/workflows/release-dispatch.yml b/.github/workflows/release-dispatch.yml new file mode 100644 index 0000000000..d062d49999 --- /dev/null +++ b/.github/workflows/release-dispatch.yml @@ -0,0 +1,63 @@ +name: Release - Open a release PR +on: + workflow_dispatch: + inputs: + crate: + description: Crate to release + required: true + type: choice + options: + - libdd-common + - libdd-telemetry + - libdd-ddsketch + - libdd-library-config + - libdd-crashtracker + - libdd-data-pipeline + - libdd-trace-protobuf + - libdd-trace-normalization + - libdd-trace-utils + - libdd-dogstatsd-client + - libdd-tinybytes + - libdd-log + version: + description: Version to release + required: true + type: string + +jobs: + make-release-pr: + permissions: + id-token: write # Enable OIDC + pull-requests: write + contents: write + runs-on: ubuntu-latest + steps: + - name: Display release information + run: | + echo "### Release Information :rocket:" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "- **Crate:** \`${{ inputs.crate }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Version:** \`${{ inputs.version }}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Creating release PR..." >> $GITHUB_STEP_SUMMARY + + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + - uses: chainguard-dev/actions/setup-gitsign@0cda751b114eb55c388e88f7479292668165602a # v1.0.2 + - name: Install cargo-release + uses: taiki-e/install-action@d6d752794628f1e1fffa3c4d3c8874e06f043d50 # 2.62.15 + with: + tool: cargo-release + + - name: Extract release notes + id: extract-release-notes + run: | + notes=$(./scripts/extract_changelog_vnext.sh ${{ inputs.crate }}/CHANGELOG.md) + echo "release-notes=$notes" >> $GITHUB_OUTPUT + + # TODO: add release notes to the PR description ${{ steps.extract-release-notes.outputs.release-notes }} + - uses: cargo-bins/release-pr@0c019c0e5a6b9f722578d231d43ba900cacc5ffa # 2.1.3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + version: ${{ inputs.version }} + crate-name: ${{ inputs.crate }} + # check-semver: "true" diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml new file mode 100644 index 0000000000..c79f7c2b59 --- /dev/null +++ b/.github/workflows/release-publish.yml @@ -0,0 +1,82 @@ +name: Release - Tag and publish to crates.io +on: + pull_request: + types: closed + branches: [main] + +env: + GIT_USER_NAME: github-actions + GIT_USER_EMAIL: github-actions@github.com + +jobs: + info: + if: github.event.pull_request.merged + outputs: + is-release: ${{ steps.check.outputs.is-release }} + crate: ${{ steps.parse.outputs.crate }} + version: ${{ steps.parse.outputs.version }} + + runs-on: ubuntu-latest + steps: + - id: check + name: Check if release branch + run: | + branch="${{ github.event.pull_request.head.ref }}" + if [[ "$branch" =~ ^release/.+/.+$ ]]; then + echo "is-release=true" >> $GITHUB_OUTPUT + else + echo "is-release=false" >> $GITHUB_OUTPUT + fi + + - id: parse + name: Parse crate and version from branch + if: steps.check.outputs.is-release == 'true' + run: | + branch="${{ github.event.pull_request.head.ref }}" + # Extract crate and version from release/{crate}/{version} + crate=$(echo "$branch" | cut -d'/' -f2) + version=$(echo "$branch" | cut -d'/' -f3) + echo "crate=$crate" >> $GITHUB_OUTPUT + echo "version=$version" >> $GITHUB_OUTPUT + + release: + permissions: + id-token: write # Enable OIDC + contents: write + + needs: info + if: needs.info.outputs.is-release == 'true' + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + + - name: Set up Rust + uses: taiki-e/install-action@d6d752794628f1e1fffa3c4d3c8874e06f043d50 # 2.62.15 + with: + tool: cargo-release + + - name: Publish crate to crates.io + id: publish + run: | + cargo publish --package ${{ needs.info.outputs.crate }} --token ${{ secrets.CARGO_REGISTRY_TOKEN || 'test_token' }} --dry-run + echo "✅ Successfully published ${{ needs.info.outputs.crate }} version ${{ needs.info.outputs.version }}" + + - uses: chainguard-dev/actions/setup-gitsign@0cda751b114eb55c388e88f7479292668165602a # v1.0.2 + if: steps.publish.outcome == 'success' + + - name: Tag and push release + if: steps.publish.outcome == 'success' + run: | + tag="${{ needs.info.outputs.crate }}-v${{ needs.info.outputs.version }}" + tag_message="${{ needs.info.outputs.crate }} v${{ needs.info.outputs.version }} release." + + echo "Setting git user name and email to ${{ env.GIT_USER_NAME }} and ${{ env.GIT_USER_EMAIL }}" + + git config user.name "${{ env.GIT_USER_NAME }}" + git config user.email "${{ env.GIT_USER_EMAIL }}" + + git tag -a "$tag" -m "$tag_message" + git push origin "$tag" + + echo "✅ Tagged and pushed $tag" diff --git a/.github/workflows/release_merge_check.yml b/.github/workflows/release_merge_check.yml new file mode 100644 index 0000000000..c14407722d --- /dev/null +++ b/.github/workflows/release_merge_check.yml @@ -0,0 +1,30 @@ +name: Release - Merge Check + +on: + pull_request: + types: [closed] + +jobs: + check-for-changes: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Fetch latest main branch + run: git fetch origin main + + - name: Check if main has changed since PR was opened + id: check_changes + run: | + if [ $(git rev-list --count HEAD ^origin/main) -ne 0 ]; then + echo "Main branch has changed since the PR was opened." + echo "has_changes=true" >> $GITHUB_ENV + else + echo "No changes in main since the PR was opened." + echo "has_changes=true" >> $GITHUB_ENV + fi + + - name: Block Merge if Changes Detected + if: env.has_changes == 'true' + run: exit 1 # This exits with an error code, which blocks the merge. diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml.off similarity index 100% rename from .github/workflows/test.yml rename to .github/workflows/test.yml.off diff --git a/.github/workflows/verify-proto-files.yml b/.github/workflows/verify-proto-files.yml.off similarity index 100% rename from .github/workflows/verify-proto-files.yml rename to .github/workflows/verify-proto-files.yml.off diff --git a/.github/workflows/version-and-changelog.yml b/.github/workflows/version-and-changelog.yml new file mode 100644 index 0000000000..9017c3f637 --- /dev/null +++ b/.github/workflows/version-and-changelog.yml @@ -0,0 +1,85 @@ +name: Cargo.toml version and CHANGELOG changes + +on: + # pull_request: + # types: [synchronize] # Triggered when new commits are pushed + workflow_dispatch: + +jobs: + version-and-changelog-checks: + if: github.event.pull_request.state == 'open' + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # 4.2.2 + with: + fetch-depth: 0 + + - name: Check if CHANGELOG.md was changed and extract crate info + id: check + run: | + # Get the changed files in the latest commit + changed_files=$(git diff --name-only ${{ github.event.before }} ${{ github.event.after }}) + + # Find CHANGELOG.md files that were changed + changed_changelogs=$(echo "$changed_files" | grep "CHANGELOG.md" || true) + + if [ -z "$changed_changelogs" ]; then + echo "changelog-changed=false" >> $GITHUB_OUTPUT + echo "crate-name=" >> $GITHUB_OUTPUT + echo "crate-version=" >> $GITHUB_OUTPUT + echo "No CHANGELOG.md was modified" + else + echo "changelog-changed=true" >> $GITHUB_OUTPUT + + # Get the first changed CHANGELOG.md + changelog_path=$(echo "$changed_changelogs" | head -n 1) + echo "CHANGELOG.md was modified: $changelog_path" + + # Get the directory containing the CHANGELOG + crate_dir=$(dirname "$changelog_path") + cargo_toml="$crate_dir/Cargo.toml" + + if [ -f "$cargo_toml" ]; then + # Extract name and version from Cargo.toml using grep and sed + crate_name=$(grep '^name = ' "$cargo_toml" | head -n 1 | sed 's/name = "\(.*\)"/\1/') + crate_version=$(cargo metadata --format-version=1 --no-deps | jq -e -r '.packages[] | select(.name == "'"$crate_name"'") | .version') + # crate_version=$(grep '^version' "$cargo_toml" | head -n 1 | sed 's/version.*= "\(.*\)"/\1/') + + echo "crate-name=$crate_name" >> $GITHUB_OUTPUT + echo "crate-version=$crate_version" >> $GITHUB_OUTPUT + echo "Detected crate: $crate_name version $crate_version" + else + echo "crate-name=" >> $GITHUB_OUTPUT + echo "crate-version=" >> $GITHUB_OUTPUT + echo "Warning: No Cargo.toml found in $crate_dir" + fi + fi + + - name: Dismiss reviews if CHANGELOG changed + if: steps.check.outputs.changelog-changed == 'true' + uses: actions/github-script@v7 + with: + script: | + const reviews = await github.rest.pulls.listReviews({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number + }); + + // Dismiss all approvals + for (const review of reviews.data) { + if (review.state === 'APPROVED') { + await github.rest.pulls.dismissReview({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.issue.number, + review_id: review.id, + message: '⚠️ Approval dismissed: CHANGELOG.md was modified after approval. Please review the changes.' + }); + console.log(`Dismissed review ${review.id} by ${review.user.login}`); + } + } diff --git a/.github/workflows/weekly-verify-proto-files.yml b/.github/workflows/weekly-verify-proto-files.yml.off similarity index 100% rename from .github/workflows/weekly-verify-proto-files.yml rename to .github/workflows/weekly-verify-proto-files.yml.off diff --git a/Cargo.lock b/Cargo.lock index 1b11271120..cff16bf847 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2943,7 +2943,6 @@ dependencies = [ "http-body-util", "httpmock", "hyper", - "hyper-http-proxy", "indexmap 2.12.0", "libdd-common", "libdd-tinybytes", diff --git a/libdd-common/CHANGELOG.md b/libdd-common/CHANGELOG.md new file mode 100644 index 0000000000..dc87d4332e --- /dev/null +++ b/libdd-common/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog + +## 0.1.0 (Nov 21, 2025) + +- Initial release \ No newline at end of file diff --git a/libdd-common/src/lib.rs b/libdd-common/src/lib.rs index 6b04d10dee..9366da56fa 100644 --- a/libdd-common/src/lib.rs +++ b/libdd-common/src/lib.rs @@ -301,6 +301,7 @@ impl Endpoint { } pub fn is_file_endpoint(&self) -> bool { + print!("epa"); self.url.scheme_str() == Some("file") } } diff --git a/scripts/ensure-version-bump-and-changelog.sh b/scripts/ensure-version-bump-and-changelog.sh new file mode 100755 index 0000000000..44a4978948 --- /dev/null +++ b/scripts/ensure-version-bump-and-changelog.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +set -ex; + +MANIFEST_PATH=$(cargo metadata --format-version=1 --no-deps | jq -e -r '.packages[] | select(.name == "'"$CRATE"'") | .manifest_path') +DIR_TO_CRATE=$(dirname "$MANIFEST_PATH") + +MERGE_BASE=$(git merge-base "$HEAD_SHA" "$PR_BASE") # Find the merge base. This ensures we only diff what was actually added in the PR. + +SRC_DIFF_TO_BASE=$(git diff "$HEAD_SHA".."$MERGE_BASE" --name-status -- "$DIR_TO_CRATE/src" "$DIR_TO_CRATE/Cargo.toml") +CHANGELOG_DIFF=$(git diff "$HEAD_SHA".."$MERGE_BASE" --name-only -- "$DIR_TO_CRATE/CHANGELOG.md") + +RELEASED_VERSION=$(curl -s -A "Github Action" https://crates.io/api/v1/crates/$CRATE | jq -r .crate.newest_version) + + +# If the source files of this crate weren't touched in this PR, exit early. +if [ -z "$SRC_DIFF_TO_BASE" ]; then + exit 0; +fi + +# Code was touched, ensure changelog is updated too. +if [ -z "$CHANGELOG_DIFF" ]; then + echo "Files in $DIR_TO_CRATE have changed, please write a changelog entry in $DIR_TO_CRATE/CHANGELOG.md" + exit 1 +fi + +IFS='.' read -r -a current <<< "$CRATE_VERSION" +IFS='.' read -r -a released <<< "$RELEASED_VERSION" + +for i in $(seq 0 2); +do + case $((current[i]-released[i])) in + 0) continue ;; + 1) if [[ -n $(printf "%s\n" "${current[@]:i+1}" | grep -vFx '0') ]]; then + echo "Patch version has been bumped even though minor isn't released yet". + exit 1 + fi + exit 0 ;; + *) echo "Version of '$CRATE' has been bumped more than once since last release v$RELEASED_VERSION." + exit 1 ;; + esac +done + +echo "v$CRATE_VERSION of '$CRATE' has already been released, please bump the version." +exit 1 diff --git a/scripts/extract_changelog_vnext.sh b/scripts/extract_changelog_vnext.sh new file mode 100755 index 0000000000..9dfcfb3070 --- /dev/null +++ b/scripts/extract_changelog_vnext.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +# Extract the vNext section from CHANGELOG.md +# Usage: ./extract_changelog_vnext.sh [CHANGELOG_FILE] + +set -euo pipefail + +CHANGELOG="${1:-CHANGELOG.md}" + +if [ ! -f "$CHANGELOG" ]; then + echo "Error: $CHANGELOG not found" >&2 + exit 1 +fi + +# Extract lines between "## vNext" and the next "##" header (or EOF) +awk ' + /^## vNext/ { in_vnext=1; next } + /^##/ && in_vnext { exit } + in_vnext { print } +' "$CHANGELOG" | sed 's/^[[:space:]]*$//' | sed '/./,$!d' | sed -e :a -e '/^\n*$/{$d;N;ba;}' + +# Explanation: +# - Start capturing when we see "## vNext" +# - Stop when we see another "##" header +# - Remove leading/trailing blank lines +