diff --git a/.github/actions/last_workflow_run/action.yml b/.github/actions/last_workflow_run/action.yml
new file mode 100644
index 00000000000000..c59bebbe2ed5b6
--- /dev/null
+++ b/.github/actions/last_workflow_run/action.yml
@@ -0,0 +1,65 @@
+# 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: "Finds the most recent run of a workflow on a branch"
+description: "Queries the GitHub Actions API for the most recent run of a given workflow on a given branch, optionally filtered by status, and exposes its head SHA and conclusion."
+inputs:
+ workflow_id:
+ description: "Workflow file name, e.g. ci.yml"
+ required: true
+ branch:
+ description: "Branch name to query"
+ required: true
+ status:
+ description: "Optional run status filter, e.g. success. Leave empty to match any status."
+ required: false
+ default: ""
+outputs:
+ sha:
+ description: "Head SHA of the matched run, or empty string if none found"
+ value: ${{ steps.resolve.outputs.sha }}
+ conclusion:
+ description: "Conclusion of the matched run, or empty string if none found"
+ value: ${{ steps.resolve.outputs.conclusion }}
+runs:
+ using: "composite"
+ steps:
+ - name: "Query workflow runs"
+ id: resolve
+ uses: actions/github-script@v7
+ with:
+ script: |
+ const workflowId = "${{ inputs.workflow_id }}";
+ const branch = "${{ inputs.branch }}";
+ const status = "${{ inputs.status }}";
+
+ const params = {
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ workflow_id: workflowId,
+ branch: branch,
+ per_page: 1
+ };
+ if (status) {
+ params.status = status;
+ }
+
+ const { data } = await github.rest.actions.listWorkflowRuns(params);
+ const run = data.workflow_runs[0];
+
+ core.setOutput('sha', run?.head_sha ?? '');
+ core.setOutput('conclusion', run?.conclusion ?? '');
diff --git a/.github/workflows/nightly-trigger.yml b/.github/workflows/nightly-trigger.yml
index 3605cf8bb67bd8..914d67ee01e22d 100644
--- a/.github/workflows/nightly-trigger.yml
+++ b/.github/workflows/nightly-trigger.yml
@@ -39,6 +39,13 @@ jobs:
- release-1.20
runs-on: ubuntu-latest
steps:
+ - name: "Resolve last nightly run"
+ id: last-nightly
+ uses: "./.github/actions/last_workflow_run"
+ with:
+ workflow_id: "nightly.yml"
+ branch: ${{ matrix.branch }}
+
- name: Trigger Workflow
uses: actions/github-script@v7
with:
@@ -55,17 +62,8 @@ jobs:
// Compare SHA from last nightly against current
// if it is same, then no need to run nightly for the same SHA again.
- const { data: runsData } = await github.rest.actions.listWorkflowRuns({
- owner: context.repo.owner,
- repo: context.repo.repo,
- workflow_id: 'nightly.yml',
- branch: branch,
- per_page: 1
- });
-
- const lastRun = runsData.workflow_runs[0];
- const lastBuiltSha = lastRun?.head_sha;
- const lastConclusion = lastRun?.conclusion;
+ const lastBuiltSha = '${{ steps.last-nightly.outputs.sha }}' || undefined;
+ const lastConclusion = '${{ steps.last-nightly.outputs.conclusion }}' || undefined;
// Skip the scheduled run only if there are no new commits AND the
// previous nightly was green. If the last run failed/was cancelled,
diff --git a/.github/workflows/template.pre-compile-checks.yml b/.github/workflows/template.pre-compile-checks.yml
index faf37dad246f16..a01802d77bec9a 100644
--- a/.github/workflows/template.pre-compile-checks.yml
+++ b/.github/workflows/template.pre-compile-checks.yml
@@ -59,16 +59,33 @@ jobs:
with:
jdk_version: ${{ inputs.jdk_version }}
- - name: "Checkstyle"
- uses: "./.github/actions/run_mvn"
+ - name: "Resolve last green commit for spotless ratchet"
+ id: last-green
+ uses: "./.github/actions/last_workflow_run"
with:
- maven-parameters: "checkstyle:check -T1C"
+ workflow_id: "ci.yml"
+ branch: ${{ github.ref_name }}
+ status: "success"
- - name: "Spotless"
- if: (success() || failure())
+ - name: "Fetch last green commit"
+ if: steps.last-green.outputs.sha != ''
+ shell: bash
+ run: |
+ sha="${{ steps.last-green.outputs.sha }}"
+ if git -c safe.directory='*' fetch --depth=1 origin "${sha}" \
+ && git -c safe.directory='*' cat-file -e "${sha}^{commit}"; then
+ echo "RATCHET_SHA=${sha}" >> "${GITHUB_ENV}"
+ echo "Ratcheting spotless from ${sha}"
+ else
+ echo "Could not fetch ${sha}; running full spotless check."
+ fi
+
+ - name: "Checkstyle & Spotless"
uses: "./.github/actions/run_mvn"
with:
- maven-parameters: "spotless:check -T1C"
+ maven-parameters: >-
+ checkstyle:check spotless:check -T1C -fae
+ ${{ env.RATCHET_SHA && format('-Dspotless.ratchetFrom={0}', env.RATCHET_SHA) || '' }}
- name: "License Headers"
if: (success() || failure())
diff --git a/pom.xml b/pom.xml
index 0a38cfe7c056af..670753e010bcb6 100644
--- a/pom.xml
+++ b/pom.xml
@@ -973,6 +973,27 @@ under the License.
false
+
+ spotless-ratchet
+
+
+ spotless.ratchetFrom
+
+
+
+
+
+
+ com.diffplug.spotless
+ spotless-maven-plugin
+
+ ${spotless.ratchetFrom}
+
+
+
+
+
+
scala-2.12