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