diff --git a/.github/workflows/release-1.x.yml b/.github/workflows/release-1.x.yml new file mode 100644 index 00000000000..c4ce6c0e2e9 --- /dev/null +++ b/.github/workflows/release-1.x.yml @@ -0,0 +1,110 @@ +# Axioms of the release pipeline: +# - Each release starts from timefold-solver by running this GitHub Action. +# - Each individual repository can only start its own release when its dependencies are fully released. +# timefold-solver-enterprise depends on timefold-solver +# timefold-quickstarts depends on timefold-solver +# timefold-website releases last +# - Each individual repository uses 999-SNAPSHOT as its development version, even on micro branches. +# +# Should any of these axioms change, the release pipeline will need to be (significantly) refactored. +# 0.8.x releases existed before this pipeline; they are done differently, similarities are coincidental. + +name: Release Community 1.x to Maven Central +on: + workflow_dispatch: + inputs: + version: + description: 'Release version (e.g. 1.31.0)' + required: true + sourceBranch: + description: 'Branch to cut the release from' + default: 1.x + required: true + dryRun: + description: 'Do a dry run?' + default: true + required: true + type: boolean +jobs: + build: + env: + MAVEN_ARGS: "--no-transfer-progress --batch-mode" + RELEASE_BRANCH_NAME: "__timefold_release_branch__" + runs-on: self-hosted + permissions: + contents: write # IMPORTANT: required for action to create release branch + id-token: write # IMPORTANT: mandatory for trusted publishing + attestations: write # IMPORTANT: mandatory for attestations + steps: + - name: Print inputs to the release workflow + run: echo "${{ toJSON(github.event.inputs) }}" + + - name: Validate the version + shell: bash + env: + VERSION: ${{ github.event.inputs.version }} + run: | + version="$VERSION" + if [[ "$version" != 1.* ]]; then + echo "The version input '$version' is invalid. This workflow only supports versions starting with '1.'." + exit 1 + fi + + - name: Checkout timefold-solver + uses: actions/checkout@v6 + with: + fetch-depth: 0 + ref: ${{ github.event.inputs.sourceBranch }} + + - name: Delete release branch (if exists) + continue-on-error: true + run: git push -d origin $RELEASE_BRANCH_NAME + + - name: Create release branch and switch to it + run: | + git config user.name "Timefold Release Bot" + git config user.email "release@timefold.ai" + git checkout -b $RELEASE_BRANCH_NAME + + - uses: actions/setup-java@v5 + with: + java-version: '17' + distribution: 'temurin' + cache: 'maven' + + # We skip tests in dry run, to make the process faster. + # Technically, this goes against the main reason for doing a dry run; to eliminate potential problems. + # But unless something catastrophic happened, PR checks on source branch already ensured that all tests pass. + - name: Set release version and build release + env: + NEW_VERSION: ${{ inputs.version }} + DRY_RUN: ${{ inputs.dryRun }} + run: | + ./mvnw -Dfull versions:set -DnewVersion="$NEW_VERSION" -DgenerateBackupPoms=false + ./mvnw -Dfull deploy -DskipTests=$DRY_RUN -DaltDeploymentRepository=local::default::file://`pwd`/target/staging-deploy + cp docs/target/antora.yml docs/src/antora.yml + git add docs/src/antora.yml + find . -name 'pom.xml' | xargs git add + git commit -m "build: release version ${{ github.event.inputs.version }}" + git push origin $RELEASE_BRANCH_NAME + + - name: Run JReleaser + uses: jreleaser/release-action@80ffb38fa759704eed4db5c7fcaae3ac1079473e # v2 + env: + JRELEASER_DRY_RUN: ${{ github.event.inputs.dryRun }} + JRELEASER_PROJECT_VERSION: ${{ github.event.inputs.version }} + JRELEASER_GITHUB_TOKEN: ${{ secrets.JRELEASER_GITHUB_TOKEN }} + JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }} + JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.JRELEASER_GPG_PUBLIC_KEY }} + JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }} + JRELEASER_MAVENCENTRAL_USERNAME: ${{ secrets.JRELEASER_MAVEN_CENTRAL_TOKEN_USER }} + JRELEASER_MAVENCENTRAL_PASSWORD: ${{ secrets.JRELEASER_MAVEN_CENTRAL_TOKEN }} + + - name: JReleaser release output + uses: actions/upload-artifact@v7 + if: always() + with: + name: jreleaser-release + path: | + out/jreleaser/trace.log + out/jreleaser/output.properties