Skip to content
Open
Show file tree
Hide file tree
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
58 changes: 58 additions & 0 deletions .github/actions/run-semver-check/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

name: Run semver check
description: Run cargo-semver-checks, preserve logs, and expose success/failure without failing the job.
inputs:
baseline_ref:
description: Baseline git ref or tag for cargo-semver-checks.
required: true
packages:
description: Space-separated package names to check.
required: true
log_path:
description: Path where semver output should be copied.
required: true
outputs:
result:
description: "Semver check result: success or failure."
value: ${{ steps.check.outputs.result }}
runs:
using: composite
steps:
- name: Run cargo-semver-checks
id: check
shell: bash
env:
BASELINE_REF: ${{ inputs.baseline_ref }}
PACKAGES: ${{ inputs.packages }}
LOG_PATH: ${{ inputs.log_path }}
run: |
set +e
# `tee` lets cargo's output stream live into the Actions log
# while we also keep a copy for the PR comment.
ci/scripts/changed_crates.sh semver-check "$BASELINE_REF" $PACKAGES \
2>&1 | tee "$LOG_PATH"
EXIT_CODE=${PIPESTATUS[0]}
# Pass the result through an output instead of failing the job:
# semver breakage should surface as a comment/label signal while this
# CI job status stays green.
if [ "$EXIT_CODE" -eq 0 ]; then
echo "result=success" >> "$GITHUB_OUTPUT"
else
echo "result=failure" >> "$GITHUB_OUTPUT"
fi
69 changes: 69 additions & 0 deletions .github/actions/setup-semver-check/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

name: Setup semver check
description: Fetch PR base, determine changed crates, and install tools required by cargo-semver-checks.
inputs:
base_ref:
description: Pull request base branch ref.
required: true
repository:
description: Repository to fetch the base branch from.
required: true
outputs:
packages:
description: Space-separated changed publishable crate names.
value: ${{ steps.changed_crates.outputs.packages }}
runs:
using: composite
steps:
# `origin` may point at a fork (when a contributor runs this locally) or
# at a stale ref. Fetch the base branch from the PR's upstream repo into
# a dedicated `apache/<base>` ref so the baseline is unambiguous and the
# same ref name works locally (`git remote add apache ...`) and in CI.
- name: Fetch base branch
shell: bash
env:
BASE_REF: ${{ inputs.base_ref }}
REPO: ${{ inputs.repository }}
run: git fetch "https://github.com/${REPO}.git" "${BASE_REF}:refs/remotes/apache/${BASE_REF}"

- name: Determine changed crates
id: changed_crates
shell: bash
env:
BASE_REF: ${{ inputs.base_ref }}
run: |
PACKAGES=$(ci/scripts/changed_crates.sh changed-crates "apache/${BASE_REF}")
echo "packages=$PACKAGES" >> "$GITHUB_OUTPUT"
echo "Changed crates: $PACKAGES"

# `datafusion-substrait` (and crates that depend on it via sqllogictest)
# have a build script that calls protoc, which is not preinstalled on
# ubuntu-latest runners.
- name: Install Protobuf Compiler
if: steps.changed_crates.outputs.packages != ''
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y protobuf-compiler

- name: Install cargo-semver-checks
if: steps.changed_crates.outputs.packages != ''
uses: taiki-e/install-action@c070f87102a1c75b3183910f391c1cb887fe13c8 # v2.77.6
with:
tool: cargo-semver-checks
64 changes: 64 additions & 0 deletions .github/actions/stage-semver-artifact/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

name: Stage semver artifact
description: Stage semver result fields and sanitized logs for the comment workflow.
inputs:
artifact_dir:
description: Directory to write artifact files into.
required: true
pr_number:
description: Pull request number.
required: true
result:
description: "Semver result: success or failure."
required: true
baseline_ref:
description: Baseline git ref or tag used by the semver check.
required: true
log_path:
description: Path to raw semver output log.
required: true
latest_release_tag:
description: Latest release tag, for blocking release-baseline checks.
required: false
default: ""
runs:
using: composite
steps:
- name: Stage artifact files
shell: bash
env:
ARTIFACT_DIR: ${{ inputs.artifact_dir }}
PR_NUMBER: ${{ inputs.pr_number }}
RESULT: ${{ inputs.result }}
BASELINE_REF: ${{ inputs.baseline_ref }}
LOG_PATH: ${{ inputs.log_path }}
LATEST_RELEASE_TAG: ${{ inputs.latest_release_tag }}
run: |
mkdir -p "$ARTIFACT_DIR"
echo "$PR_NUMBER" > "$ARTIFACT_DIR/pr_number"
echo "$RESULT" > "$ARTIFACT_DIR/result"
echo "$BASELINE_REF" > "$ARTIFACT_DIR/baseline_ref"
if [ -n "$LATEST_RELEASE_TAG" ]; then
echo "$LATEST_RELEASE_TAG" > "$ARTIFACT_DIR/latest_release_tag"
fi
if [ -f "$LOG_PATH" ]; then
sed 's/\x1b\[[0-9;]*m//g' "$LOG_PATH" > "$ARTIFACT_DIR/logs"
else
: > "$ARTIFACT_DIR/logs"
fi
167 changes: 98 additions & 69 deletions .github/workflows/breaking_changes_detector.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,92 +50,121 @@ permissions:
contents: read

jobs:
check-semver:
name: Check semver
check-semver-advisory:
name: Check semver - advisory PR-local
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

# `origin` may point at a fork (when a contributor runs this locally) or
# at a stale ref. Fetch the base branch from the PR's upstream repo into
# a dedicated `apache/<base>` ref so the baseline is unambiguous and the
# same ref name works locally (`git remote add apache ...`) and in CI.
- name: Fetch base branch
env:
BASE_REF: ${{ github.base_ref }}
REPO: ${{ github.repository }}
run: git fetch "https://github.com/${REPO}.git" "${BASE_REF}:refs/remotes/apache/${BASE_REF}"

- name: Determine changed crates
id: changed_crates
env:
BASE_REF: ${{ github.base_ref }}
run: |
PACKAGES=$(ci/scripts/changed_crates.sh changed-crates "apache/${BASE_REF}")
echo "packages=$PACKAGES" >> "$GITHUB_OUTPUT"
echo "Changed crates: $PACKAGES"

# `datafusion-substrait` (and crates that depend on it via sqllogictest)
# have a build script that calls protoc, which is not preinstalled on
# ubuntu-latest runners.
- name: Install Protobuf Compiler
if: steps.changed_crates.outputs.packages != ''
run: |
sudo apt-get update
sudo apt-get install -y protobuf-compiler

- name: Install cargo-semver-checks
if: steps.changed_crates.outputs.packages != ''
uses: taiki-e/install-action@c070f87102a1c75b3183910f391c1cb887fe13c8 # v2.77.6
- name: Setup semver check
id: semver_setup
uses: ./.github/actions/setup-semver-check
with:
tool: cargo-semver-checks
base_ref: ${{ github.base_ref }}
repository: ${{ github.repository }}

- name: Run cargo-semver-checks
- name: Run cargo-semver-checks against PR base branch
id: check_semver
if: steps.changed_crates.outputs.packages != ''
env:
BASE_REF: ${{ github.base_ref }}
PACKAGES: ${{ steps.changed_crates.outputs.packages }}
run: |
set +e
# `tee` lets cargo's output stream live into the Actions log
# while we also keep a copy for the PR comment.
# Using `apache` remote here to point to the repository the pull request is against
ci/scripts/changed_crates.sh semver-check "apache/${BASE_REF}" $PACKAGES \
2>&1 | tee /tmp/semver-output.txt
EXIT_CODE=${PIPESTATUS[0]}
# Pass the result through an output instead of failing the job:
# a detected breaking change should surface as a PR comment, not a
# red check, so PR authors aren't confused by an intentional break.
if [ "$EXIT_CODE" -eq 0 ]; then
echo "result=success" >> "$GITHUB_OUTPUT"
else
echo "result=failure" >> "$GITHUB_OUTPUT"
fi
if: steps.semver_setup.outputs.packages != ''
uses: ./.github/actions/run-semver-check
with:
baseline_ref: apache/${{ github.base_ref }}
packages: ${{ steps.semver_setup.outputs.packages }}
log_path: /tmp/advisory-semver-output.txt

# Stage the data the companion comment workflow needs into a single
# directory. We default the result to "success" so the comment
# workflow clears any stale comment when the check step is skipped
# (e.g. no published crates changed).
- name: Stage artifact for comment workflow
- name: Stage advisory artifact for comment workflow
if: always()
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
CHECK_RESULT: ${{ steps.check_semver.outputs.result || 'success' }}
uses: ./.github/actions/stage-semver-artifact
with:
artifact_dir: semver-advisory-artifact
pr_number: ${{ github.event.pull_request.number }}
result: ${{ steps.check_semver.outputs.result || 'success' }}
baseline_ref: apache/${{ github.base_ref }}
log_path: /tmp/advisory-semver-output.txt

- name: Upload advisory artifact
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: semver-advisory-check-result
path: semver-advisory-artifact/
retention-days: 1

check-semver-blocking:
name: Check semver - blocking latest release
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0

- name: Setup semver check
id: semver_setup
uses: ./.github/actions/setup-semver-check
with:
base_ref: ${{ github.base_ref }}
repository: ${{ github.repository }}

- name: Determine latest stable release tag
id: latest_release
run: |
mkdir -p semver-artifact
echo "$PR_NUMBER" > semver-artifact/pr_number
echo "$CHECK_RESULT" > semver-artifact/result
if [ -f /tmp/semver-output.txt ]; then
sed 's/\x1b\[[0-9;]*m//g' /tmp/semver-output.txt > semver-artifact/logs
else
: > semver-artifact/logs
fi

- name: Upload artifact
git fetch --tags --force
LATEST_RELEASE_TAG=$(ci/scripts/changed_crates.sh latest-release-tag)
echo "tag=$LATEST_RELEASE_TAG" >> "$GITHUB_OUTPUT"
echo "Latest stable release tag: $LATEST_RELEASE_TAG"

- name: Run cargo-semver-checks against latest stable release
id: check_semver
if: steps.semver_setup.outputs.packages != ''
uses: ./.github/actions/run-semver-check
with:
baseline_ref: ${{ steps.latest_release.outputs.tag }}
packages: ${{ steps.semver_setup.outputs.packages }}
log_path: /tmp/blocking-semver-output.txt

- name: Stage blocking artifact for comment workflow
if: always()
uses: ./.github/actions/stage-semver-artifact
with:
artifact_dir: semver-blocking-artifact
pr_number: ${{ github.event.pull_request.number }}
result: ${{ steps.check_semver.outputs.result || 'success' }}
baseline_ref: ${{ steps.latest_release.outputs.tag }}
latest_release_tag: ${{ steps.latest_release.outputs.tag }}
log_path: /tmp/blocking-semver-output.txt

- name: Upload blocking artifact
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: semver-blocking-check-result
path: semver-blocking-artifact/
retention-days: 1

# workflow_run workflows execute from the default branch. While this PR is
# under review, the default-branch comment workflow still expects the old
# single-artifact contract. Upload a legacy-compatible copy sourced from
# the blocking latest-release signal so in-flight PR checks keep working.
- name: Stage legacy artifact for default-branch comment workflow
if: always()
uses: ./.github/actions/stage-semver-artifact
with:
artifact_dir: semver-artifact
pr_number: ${{ github.event.pull_request.number }}
result: ${{ steps.check_semver.outputs.result || 'success' }}
baseline_ref: ${{ steps.latest_release.outputs.tag }}
latest_release_tag: ${{ steps.latest_release.outputs.tag }}
log_path: /tmp/blocking-semver-output.txt

- name: Upload legacy artifact
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
Expand Down
Loading
Loading