From 3dcf3078d0cf2b6f1ee6e1e084202625f991944c Mon Sep 17 00:00:00 2001 From: Timefold Release Bot Date: Mon, 8 Jun 2026 12:37:39 -0300 Subject: [PATCH 1/4] chore: readd 1.x release workflow --- .github/workflows/release.yml | 107 ++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000000..88fff236943 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,107 @@ +# 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? (true or false)' + default: true + required: true +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 + pull-requests: write # IMPORTANT: so release PR can be created + 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 source branch and 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 + run: | + ./mvnw -Dfull versions:set -DnewVersion=${{ github.event.inputs.version }} + ./mvnw -Dfull deploy -DskipTests=${{ github.event.inputs.dryRun }} -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 From c3f75ebe30ef44f514283db6c74ad424f78d4802 Mon Sep 17 00:00:00 2001 From: Timefold Release Bot Date: Tue, 9 Jun 2026 08:24:49 -0300 Subject: [PATCH 2/4] chore: address comments --- .github/workflows/release.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 88fff236943..3cd7b24197c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -32,14 +32,13 @@ jobs: runs-on: self-hosted permissions: contents: write # IMPORTANT: required for action to create release branch - pull-requests: write # IMPORTANT: so release PR can be created 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 source branch and the version + - name: Validate the version shell: bash env: VERSION: ${{ github.event.inputs.version }} From 0d00615d76d561ac4a9d548afc1fe4eb32c4d658 Mon Sep 17 00:00:00 2001 From: Timefold Release Bot Date: Wed, 10 Jun 2026 08:41:52 -0300 Subject: [PATCH 3/4] chore: address comments --- .github/workflows/{release.yml => release-1.x.yml} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename .github/workflows/{release.yml => release-1.x.yml} (98%) diff --git a/.github/workflows/release.yml b/.github/workflows/release-1.x.yml similarity index 98% rename from .github/workflows/release.yml rename to .github/workflows/release-1.x.yml index 3cd7b24197c..7ac9020fbf2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release-1.x.yml @@ -21,9 +21,10 @@ on: default: 1.x required: true dryRun: - description: 'Do a dry run? (true or false)' + description: 'Do a dry run?' default: true required: true + type: boolean jobs: build: env: From 1b7279bf359ff92520070d3b493110fe9c267212 Mon Sep 17 00:00:00 2001 From: Timefold Release Bot Date: Wed, 10 Jun 2026 08:52:08 -0300 Subject: [PATCH 4/4] chore: address comments --- .github/workflows/release-1.x.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release-1.x.yml b/.github/workflows/release-1.x.yml index 7ac9020fbf2..c4ce6c0e2e9 100644 --- a/.github/workflows/release-1.x.yml +++ b/.github/workflows/release-1.x.yml @@ -76,9 +76,12 @@ jobs: # 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=${{ github.event.inputs.version }} - ./mvnw -Dfull deploy -DskipTests=${{ github.event.inputs.dryRun }} -DaltDeploymentRepository=local::default::file://`pwd`/target/staging-deploy + ./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