Skip to content

Move common build plugin #6003

Move common build plugin

Move common build plugin #6003

Workflow file for this run

name: github-workflow
permissions:
actions: write
contents: read
on:
pull_request:
branches: [ main, 3.2.x, 3.3.x ]
# Manual trigger with optional branch override
workflow_dispatch:
inputs:
branch:
description: "Which branch should be built"
required: true
default: 'main'
type: string
jdk-version:
description: "Java version to use for build"
required: false
default: '17'
type: string
should-deploy:
description: "Whether to run deployment after tests pass"
required: false
default: 'false'
type: string
runs-on:
description: "Runner label for the jobs that run Maven"
required: false
default: 'ubuntu-latest'
type: string
build-docs:
description: "Whether the deploy build includes the docs profile"
required: false
default: true
type: boolean
# Allow calls from ci.yaml
workflow_call:
inputs:
branch:
description: "Which branch should be built"
required: true
type: string
jdk-version:
description: "Java version to use for build"
required: true
type: string
should-deploy:
description: "Whether to run deployment after tests pass"
required: true
type: boolean
runs-on:
description: >
Runner label for the jobs that run Maven. Defaults to ubuntu-latest, which is
correct for open source builds. Commercial branches must pass a runner from the
spring-enterprise-builds group, because commercial Artifactory only accepts
requests from those runners and answers anything else with a 403 no matter what
credentials are supplied. Also used for the deploy job.
required: false
default: 'ubuntu-latest'
type: string
build-docs:
description: >
Whether the deploy build includes the docs profile.
required: false
default: true
type: boolean
jobs:
build:
name: Build (${{ inputs.branch || github.ref_name }} with JDK ${{ inputs.jdk-version || '17' }})
runs-on: ${{ inputs.runs-on || 'ubuntu-latest' }}
env:
# this might get set to true if there is an existing cache of test times
# this happens in 'matrix-bounds-on-test-times-cache-hit'
TEST_TIMES_CACHE_PRESENT: false
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 30
JDK_VERSION: ${{ inputs.jdk-version || '17' }}
BRANCH: ${{ inputs.branch || github.ref_name }}
# this job ('build') outputs a value from step 'test_times_cache_present_init', that has the name of:
# 'test_times_cache_present'. This can later be used by other jobs. For example, we use this one
# to skip the job responsible for running the tests, if a previous cache that has the test times is not present.
# Same for other two variables 'number_of_matrix_instances' and 'matrix_array'.
outputs:
branch_safe: ${{ steps.sanitize_branch.outputs.branch_safe }} # this is the branch name with / removed so it can be used in cache names safely
test_times_cache_present: ${{ steps.test_times_cache_present_init.outputs.test_times_cache_present }}
number_of_matrix_instances: ${{ steps.test_times_cache_present_init.outputs.number_of_matrix_instances }}
matrix_array: ${{ steps.test_times_cache_present_init.outputs.matrix_array }}
average_time_per_instance: ${{ steps.test_times_cache_present_init.outputs.average_time_per_instance }}
steps:
- name: checkout project
uses: actions/checkout@v7.0.1
with:
ref: ${{ inputs.branch || github.ref }}
- name: Sanitize branch name for artifacts
id: sanitize_branch
shell: bash
run: |
SANITIZED_BRANCH=$(echo "${{ env.BRANCH }}" | sed 's/\//-/g')
echo "BRANCH_SAFE=${SANITIZED_BRANCH}" >> $GITHUB_ENV
echo "branch_safe=${SANITIZED_BRANCH}" >> $GITHUB_OUTPUT
- name: set env variables
env:
# Read-write commercial credentials, deliberately blank on pull requests so that
# forked PRs fall back to the read-only secrets. The composite picks whichever
# pair is populated and exports COMMERCIAL_ARTIFACTORY_USERNAME/PASSWORD, which
# release-ci-settings.xml interpolates to reach commercial Artifactory.
PASSWORD: ${{ github.event_name != 'pull_request' && secrets.COMMERCIAL_ARTIFACTORY_PASSWORD || '' }}
USERNAME: ${{ github.event_name != 'pull_request' && secrets.COMMERCIAL_ARTIFACTORY_USERNAME || '' }}
RO_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD || secrets.ARTIFACTORY_RO_PASSWORD }}
RO_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME || secrets.ARTIFACTORY_RO_USERNAME }}
uses: ./.github/workflows/composites/env-variables
- name: setup project jdk
uses: ./.github/workflows/composites/setup-jdk
with:
jdk-version: ${{ env.JDK_VERSION }}
- name: cache local maven repository
uses: ./.github/workflows/composites/cache
with:
jdk-version: ${{ env.JDK_VERSION }}
- name: Show caches
uses: actions/github-script@v9
with:
script: |
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
console.log(caches.data)
- name: maven build with dry-run for tests
uses: ./.github/workflows/composites/maven-build-with-dry-run-for-tests
with:
jdk-version: ${{ env.JDK_VERSION }}
branch: ${{ env.BRANCH_SAFE }}
- name: restore test times cache if it exists
id: restore_test_times_cache
uses: actions/cache/restore@v6
with:
path: /tmp/sorted.txt
key: ${{ runner.os }}-spring-cloud-k8s-jdk${{ env.JDK_VERSION }}-test-times-cache-${{ github.run_id }}
restore-keys: ${{ runner.os }}-spring-cloud-k8s-jdk${{ env.JDK_VERSION }}-test-times-cache-
- name: check test times cache exists
id: check_files
uses: andstor/file-existence-action@v3
with:
files: /tmp/sorted.txt
- name: show existing cache of test times
if: steps.check_files.outputs.files_exists == 'true'
shell: bash
run: cat /tmp/sorted.txt
- name: compute matrix related fields when cache is present
if: steps.check_files.outputs.files_exists == 'true'
uses: ./.github/workflows/composites/matrix-bounds-on-test-times-cache-hit
with:
jdk-version: ${{ env.JDK_VERSION }}
branch: ${{ env.BRANCH_SAFE }}
- name: matrix related variables when cache is present
id: test_times_cache_present_init
run: |
echo "test_times_cache_present=${{ env.TEST_TIMES_CACHE_PRESENT }}" >> $GITHUB_OUTPUT
echo "number_of_matrix_instances=${{ env.NUMBER_OF_MATRIX_INSTANCES }}" >> $GITHUB_OUTPUT
echo "matrix_array=${{ env.MATRIX_ARRAY }}" >> $GITHUB_OUTPUT
echo "average_time_per_instance=${{ env.AVERAGE_TIME_PER_INSTANCE }}" >> $GITHUB_OUTPUT
test_when_cache_present:
name: Test with cache (runner ${{ matrix.current_index }})
needs: [ build ]
runs-on: ${{ inputs.runs-on || 'ubuntu-latest' }}
env:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 30
JDK_VERSION: ${{ inputs.jdk-version || '17' }}
BRANCH: ${{ inputs.branch || github.ref_name }}
BRANCH_SAFE: ${{ needs.build.outputs.branch_safe }}
# only run this one if there is a previous cache of test times
if: needs.build.outputs.test_times_cache_present == 'true'
timeout-minutes: 120
strategy:
# let every shard finish so a single failing shard does not hide failures
# (or successes) in the others
fail-fast: false
matrix:
current_index: [ "${{ fromJSON(needs.build.outputs.matrix_array) }}" ]
number_of_jobs: [ "${{ fromJSON(needs.build.outputs.number_of_matrix_instances) }}" ]
average_time_per_instance: [ "${{ fromJSON(needs.build.outputs.average_time_per_instance) }}" ]
steps:
- name: checkout project
uses: actions/checkout@v7.0.1
with:
ref: ${{ inputs.branch || github.ref }}
- name: clean space
uses: ./.github/workflows/composites/clean-space
- name: set env variables
env:
# Read-write commercial credentials, deliberately blank on pull requests so that
# forked PRs fall back to the read-only secrets. The composite picks whichever
# pair is populated and exports COMMERCIAL_ARTIFACTORY_USERNAME/PASSWORD, which
# release-ci-settings.xml interpolates to reach commercial Artifactory.
PASSWORD: ${{ github.event_name != 'pull_request' && secrets.COMMERCIAL_ARTIFACTORY_PASSWORD || '' }}
USERNAME: ${{ github.event_name != 'pull_request' && secrets.COMMERCIAL_ARTIFACTORY_USERNAME || '' }}
RO_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD || secrets.ARTIFACTORY_RO_PASSWORD }}
RO_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME || secrets.ARTIFACTORY_RO_USERNAME }}
uses: ./.github/workflows/composites/env-variables
- name: setup project jdk
uses: ./.github/workflows/composites/setup-jdk
with:
jdk-version: ${{ env.JDK_VERSION }}
- name: pre-test-actions
uses: ./.github/workflows/composites/pre-test-actions
with:
jdk-version: ${{ env.JDK_VERSION }}
branch: ${{ env.BRANCH_SAFE }}
- name: testcontainers reuse support
shell: bash
run: echo "testcontainers.reuse.enable=true" > ~/.testcontainers.properties
- name: run and save test times when cache is present
uses: ./.github/workflows/composites/run-and-save-test-times-when-cache-present
with:
jdk-version: ${{ env.JDK_VERSION }}
branch: ${{ env.BRANCH_SAFE }}
env:
CURRENT_INDEX: ${{ matrix.current_index }}
NUMBER_OF_JOBS: ${{ matrix.number_of_jobs }}
AVERAGE_TIME_PER_INSTANCE: ${{ matrix.average_time_per_instance }}
# how many extra times a shard re-runs the test classes that failed.
# 0 disables retries, 2 means up to three maven runs, and so on.
TEST_RETRY_COUNT: 1
test_when_cache_missing:
name: Test without cache (runner ${{ matrix.current_index }})
needs: [ build ]
runs-on: ${{ inputs.runs-on || 'ubuntu-latest' }}
env:
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 30
JDK_VERSION: ${{ inputs.jdk-version || '17' }}
BRANCH: ${{ inputs.branch || github.ref_name }}
BRANCH_SAFE: ${{ needs.build.outputs.branch_safe }}
timeout-minutes: 120
# only run this one if there is no previous cache of test times
if: needs.build.outputs.test_times_cache_present == 'false'
strategy:
# let every shard finish so a single failing shard does not hide failures
# (or successes) in the others
fail-fast: false
matrix:
current_index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31]
number_of_jobs: [32]
steps:
- name: checkout project
uses: actions/checkout@v7.0.1
with:
ref: ${{ inputs.branch || github.ref }}
- name: clean space
uses: ./.github/workflows/composites/clean-space
- name: set env variables
env:
# Read-write commercial credentials, deliberately blank on pull requests so that
# forked PRs fall back to the read-only secrets. The composite picks whichever
# pair is populated and exports COMMERCIAL_ARTIFACTORY_USERNAME/PASSWORD, which
# release-ci-settings.xml interpolates to reach commercial Artifactory.
PASSWORD: ${{ github.event_name != 'pull_request' && secrets.COMMERCIAL_ARTIFACTORY_PASSWORD || '' }}
USERNAME: ${{ github.event_name != 'pull_request' && secrets.COMMERCIAL_ARTIFACTORY_USERNAME || '' }}
RO_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD || secrets.ARTIFACTORY_RO_PASSWORD }}
RO_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME || secrets.ARTIFACTORY_RO_USERNAME }}
uses: ./.github/workflows/composites/env-variables
- name: setup project jdk
uses: ./.github/workflows/composites/setup-jdk
with:
jdk-version: ${{ env.JDK_VERSION }}
- name: pre-test-actions
uses: ./.github/workflows/composites/pre-test-actions
with:
jdk-version: ${{ env.JDK_VERSION }}
branch: ${{ env.BRANCH_SAFE }}
- name: compute single step test bounds
uses: ./.github/workflows/composites/test-bounds
env:
CURRENT_INDEX: ${{ matrix.current_index }}
NUMBER_OF_JOBS: ${{ matrix.number_of_jobs }}
- name: testcontainers reuse support
shell: bash
run: echo "testcontainers.reuse.enable=true" > ~/.testcontainers.properties
- name: run and save individual test times
uses: ./.github/workflows/composites/run-and-save-test-times-when-cache-missing
with:
jdk-version: ${{ env.JDK_VERSION }}
branch: ${{ env.BRANCH_SAFE }}
env:
CURRENT_INDEX: ${{ matrix.current_index }}
# how many extra times a shard re-runs the test classes that failed.
# 0 disables retries, 2 means up to three maven runs, and so on.
TEST_RETRY_COUNT: 1
save_test_times_when_cache_missing:
name: Save test times
runs-on: ubuntu-latest
needs: [build, test_when_cache_missing ]
env:
JDK_VERSION: ${{ inputs.jdk-version || '17' }}
BRANCH: ${{ inputs.branch || github.ref_name }}
BRANCH_SAFE: ${{ needs.build.outputs.branch_safe }}
steps:
- name: checkout project
uses: actions/checkout@v7.0.1
with:
ref: ${{ inputs.branch || github.ref }}
- name: compute and save running time of tests
uses: ./.github/workflows/composites/test-times
with:
jdk-version: ${{ env.JDK_VERSION }}
branch: ${{ env.BRANCH_SAFE }}
save_test_times_when_cache_present:
name: Save test times
runs-on: ubuntu-latest
needs: [ build, test_when_cache_present ]
env:
JDK_VERSION: ${{ inputs.jdk-version || '17' }}
BRANCH: ${{ inputs.branch || github.ref_name }}
BRANCH_SAFE: ${{ needs.build.outputs.branch_safe }}
steps:
- name: checkout project
uses: actions/checkout@v7.0.1
with:
ref: ${{ inputs.branch || github.ref }}
- name: compute and save running time of tests
uses: ./.github/workflows/composites/test-times
with:
jdk-version: ${{ env.JDK_VERSION }}
branch: ${{ env.BRANCH_SAFE }}
# Gate job to handle mutually exclusive test jobs
# Either test_when_cache_present OR test_when_cache_missing runs (not both)
# This job succeeds only if the appropriate test jobs succeeded
all-tests-passed:
if: always()
needs: [test_when_cache_present, test_when_cache_missing, save_test_times_when_cache_missing, save_test_times_when_cache_present]
runs-on: ubuntu-latest
steps:
- name: Check test results
run: |
echo "test_when_cache_present: ${{ needs.test_when_cache_present.result }}"
echo "test_when_cache_missing: ${{ needs.test_when_cache_missing.result }}"
if [ "${{ needs.test_when_cache_present.result }}" == "success" ] || \
[ "${{ needs.test_when_cache_missing.result }}" == "success" ]; then
echo "Tests passed"
exit 0
else
echo "No test job succeeded (see the results above). A result of 'cancelled'"
echo "means a test job timed out or was cancelled, not that a test assertion"
echo "failed - check the test job logs to tell them apart."
exit 1
fi
# Deploy job that runs after all tests pass
# Only runs when should-deploy input is 'true'
deploy:
if: always() && inputs.should-deploy && needs.all-tests-passed.result == 'success'
needs: [all-tests-passed]
uses: spring-cloud/spring-cloud-github-actions/.github/workflows/deploy.yml@b6a6b1963b8762420526591c3d363bd7d09e7d4b # v1.1.1
with:
trigger_ci_on_non_default_branches: false
branches: ${{ inputs.branch }}
# Commercial branches must deploy from a spring-enterprise-builds runner, the same as
# the jobs above; commercial Artifactory rejects anything else with a 403.
runs_on: ${{ inputs.runs-on }}
# MAVEN_SETTINGS and MAVEN_DEPLOY_FLAGS are set by deploy.yml.
custom_build_command: |
if [[ "$SHOULD_DEPLOY" == "true" ]]; then
./mvnw $MAVEN_SETTINGS clean deploy -Pspring${{ inputs.build-docs && ',docs' || '' }} -DskipTests -DskipITs -Dspring-boot.build-image.skip=true -B -U $MAVEN_DEPLOY_FLAGS
else
echo "Will not deploy artifacts"
fi
secrets:
ARTIFACTORY_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
ARTIFACTORY_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
COMMERCIAL_ARTIFACTORY_USERNAME: ${{ secrets.COMMERCIAL_ARTIFACTORY_USERNAME }}
COMMERCIAL_ARTIFACTORY_PASSWORD: ${{ secrets.COMMERCIAL_ARTIFACTORY_PASSWORD }}
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}