Skip to content

Commit d5d0f42

Browse files
chore: Create release workflow (#46)
1 parent 35932ad commit d5d0f42

File tree

6 files changed

+230
-5
lines changed

6 files changed

+230
-5
lines changed

.github/scripts/change_versions.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#!/bin/bash
2+
3+
# Expects the following environment variables to be set:
4+
# $NEW_VERSION (Example: "1.2.0")
5+
# $NEW_VERSION_PYTHON (Example: "1.2.0a0")
6+
7+
# This will fail the Maven build if the version is not available.
8+
# Thankfully, this is not the case (yet) in this project.
9+
# If/when it happens, this needs to be replaced by a manually provided version,
10+
# as scanning the text of the POM would be unreliable.
11+
echo " New version: $NEW_VERSION"
12+
echo " New Python Version: $NEW_VERSION_PYTHON"
13+
mvn versions:update-parent "-DparentVersion=[$NEW_VERSION,$NEW_VERSION]" -DallowSnapshots=true -DgenerateBackupPoms=false
14+
(
15+
cd jpyinterpreter ||
16+
mvn versions:update-parent "-DparentVersion=[$NEW_VERSION,$NEW_VERSION]" -DallowSnapshots=true -DgenerateBackupPoms=false
17+
)
18+
(
19+
cd timefold-solver-python-code ||
20+
mvn versions:update-parent "-DparentVersion=[$NEW_VERSION,$NEW_VERSION]" -DallowSnapshots=true -DgenerateBackupPoms=false
21+
)
22+
sed -i "s/^timefold_solver_python_version.*=.*/timefold_solver_python_version = '$NEW_VERSION_PYTHON'/" setup.py
23+
git commit -am "build: switch to version $NEW_VERSION_PYTHON"
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
**!!! REMOVE THIS !!!**
2+
3+
**!!! SUMMARIZE THE RELEASE HERE !!!**
4+
5+
**!!! REMOVE THIS !!!**
6+
7+
# Changelog
8+
9+
{{changelogChanges}}
10+
{{changelogContributors}}
11+
12+
_Timefold Solver Community Edition_ is an open source project, and you are more than welcome to contribute as well!
13+
For more, see [Contributing](https://github.com/TimefoldAI/timefold-solver/blob/main/CONTRIBUTING.adoc).
14+
15+
Should your business need to scale to truly massive data sets or require enterprise-grade support,
16+
check out [_Timefold Solver Enterprise Edition_](https://timefold.ai/pricing).
17+
18+
# How to use Timefold Solver in Python
19+
20+
To see Timefold Solver in action, check out [the quickstarts](https://github.com/TimefoldAI/timefold-quickstarts).
21+
22+
Add `timefold-solver=={{projectVersion}}` to your `requirements.txt` or `pip install timefold-solver=={{projectVersion}}` file to get started.
23+
24+
# Additional notes
25+
26+
The changelog and the list of contributors above are automatically generated.
27+
It excludes contributions to certain areas of the repository, such as CI and build automation.
28+
This is done for the sake of brevity and to make the user-facing changes stand out more.

.github/workflows/release-pr-body.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
At this point, the release of _Timefold Solver Community Edition_ for Python is ready to be published.
2+
Artifacts have been uploaded to PyPI.
3+
Release branch has been created.
4+
5+
To finish the release of _Timefold Solver Community Edition_ for Python,
6+
please follow the steps below in the given order:
7+
8+
1. [ ] [Undraft the release](https://github.com/TimefoldAI/timefold-solver-python/releases) on Github.
9+
2. [ ] Merge this PR.
10+
3. [ ] Delete the branch that this PR is based on. (Typically a button appears on this page once the PR is merged.)
11+
12+
Note: If this is a dry run,
13+
none of the above applies and this PR should not be merged.

.github/workflows/release.yml

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
name: Release
2+
on:
3+
workflow_dispatch:
4+
inputs:
5+
version:
6+
description: 'Community Edition version (e.g. 1.0.0)'
7+
required: true
8+
pythonVersionSuffix:
9+
description: 'What suffix to append to the Python version (ex: a0 for alpha release)'
10+
required: true
11+
default: a0
12+
sourceBranch:
13+
description: 'Branch to cut the release from'
14+
default: main
15+
required: true
16+
releaseBranch:
17+
description: 'Release branch to create (e.g. 1.0.x for version 1.0.0; once created, branch protection rules apply)'
18+
default: dry_run
19+
required: true
20+
dryRun:
21+
description: 'Do a dry run? (true or false)'
22+
default: true
23+
required: true
24+
jobs:
25+
build:
26+
env:
27+
MAVEN_ARGS: "--no-transfer-progress --batch-mode"
28+
runs-on: ubuntu-latest
29+
steps:
30+
- name: Print inputs to the release workflow
31+
run: echo "${{ toJSON(github.event.inputs) }}"
32+
- name: Checkout the relevant timefold-solver tag
33+
uses: actions/checkout@v4
34+
with:
35+
repository: "TimefoldAI/timefold-solver"
36+
path: "./timefold-solver"
37+
fetch-depth: 0
38+
ref: v${{ github.event.inputs.version }}
39+
40+
- uses: actions/setup-java@v4
41+
with:
42+
java-version: '17'
43+
distribution: 'temurin'
44+
cache: 'maven'
45+
46+
- name: Set up Maven
47+
uses: stCarolas/setup-maven@v5
48+
with:
49+
maven-version: 3.9.3
50+
51+
- name: Python 3.12 Setup
52+
uses: actions/setup-python@v4
53+
with:
54+
python-version: 3.12
55+
56+
- name: Install Pip and build
57+
run:
58+
python -m pip install --upgrade pip
59+
pip install build
60+
61+
- name: Checkout timefold-solver-python
62+
uses: actions/checkout@v4
63+
with:
64+
fetch-depth: 0
65+
ref: ${{ github.event.inputs.sourceBranch }}
66+
67+
- name: Create release branch and switch to it
68+
run: |
69+
git config user.name "Timefold Release Bot"
70+
git config user.email "release@timefold.ai"
71+
git checkout -b ${{ github.event.inputs.releaseBranch }}
72+
73+
# We skip tests in dry run, to make the process faster.
74+
# Technically, this goes against the main reason for doing a dry run; to eliminate potential problems.
75+
# But unless something catastrophic happened, PR checks on source branch already ensured that all tests pass.
76+
# We also do not use versions:set, because we'd have to have the SNAPSHOT version built from somewhere,
77+
# and at this point in the release, there is no upstream branch anywhere that would have this version anymore.
78+
- name: Set release version and build release
79+
run: |
80+
export NEW_VERSION=${{ github.event.inputs.version }}
81+
export NEW_VERSION_PYTHON=${{ github.event.inputs.version }}${{ github.event.inputs.pythonVersionSuffix }}
82+
.github/scripts/change_versions.sh
83+
python -m build
84+
85+
# JReleaser requires the release branch to exist, so we need to push it before releasing.
86+
# Once this is pushed, branch protection rules apply.
87+
# So if any of the subsequent steps should fail, the release branch is there to stay; cannot be deleted.
88+
# To minimize that chance, do a dry run first, with a branch named in a way that the protection rules don't apply.
89+
- name: Push release branch to Git
90+
run: |
91+
git push origin ${{ github.event.inputs.releaseBranch }}
92+
93+
- name: Run JReleaser
94+
uses: jreleaser/release-action@v2
95+
env:
96+
JRELEASER_DRY_RUN: ${{ github.event.inputs.dryRun }}
97+
JRELEASER_PROJECT_VERSION: ${{ github.event.inputs.version }}${{ github.event.inputs.pythonVersionSuffix }}
98+
JRELEASER_GITHUB_TOKEN: ${{ secrets.JRELEASER_GITHUB_TOKEN }}
99+
JRELEASER_GPG_PASSPHRASE: ${{ secrets.JRELEASER_GPG_PASSPHRASE }}
100+
JRELEASER_GPG_PUBLIC_KEY: ${{ secrets.JRELEASER_GPG_PUBLIC_KEY }}
101+
JRELEASER_GPG_SECRET_KEY: ${{ secrets.JRELEASER_GPG_SECRET_KEY }}
102+
103+
- name: JReleaser release output
104+
uses: actions/upload-artifact@v4
105+
if: always()
106+
with:
107+
name: jreleaser-release
108+
path: |
109+
out/jreleaser/trace.log
110+
out/jreleaser/output.properties
111+
112+
# TODO: Use https://github.com/marketplace/actions/pypi-publish to publish to PyPI here
113+
114+
# Pull Request will be created with the changes and a summary of next steps.
115+
- name: Put back the 999-SNAPSHOT version on the release branch
116+
run: |
117+
git checkout -B ${{ github.event.inputs.releaseBranch }}-put-back-999-snapshot
118+
export NEW_VERSION="999-SNAPSHOT"
119+
export NEW_VERSION_PYTHON="999-dev0"
120+
.github/scripts/change_versions.sh
121+
git push origin ${{ github.event.inputs.releaseBranch }}-put-back-999-snapshot
122+
gh pr create --reviewer triceo,Christopher-Chianelli --base ${{ github.event.inputs.releaseBranch }} --head ${{ github.event.inputs.releaseBranch }}-put-back-999-snapshot --title "build: move back to 999-SNAPSHOT" --body-file .github/workflows/release-pr-body.md
123+
env:
124+
GITHUB_TOKEN: ${{ secrets.JRELEASER_GITHUB_TOKEN }}

jreleaser.yml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
project:
2+
name: timefold-solver-python
3+
4+
signing:
5+
active: ALWAYS
6+
armored: true
7+
8+
release:
9+
github:
10+
commitAuthor:
11+
name: "Timefold Release Bot"
12+
email: "release@timefold.ai"
13+
releaseName: "Timefold Solver Community Edition for Python {{projectVersion}}"
14+
draft: true
15+
overwrite: false
16+
sign: true
17+
milestone:
18+
close: true
19+
name: "v{{projectVersion}}"
20+
changelog:
21+
formatted: ALWAYS
22+
preset: "conventional-commits"
23+
contentTemplate: ".github/workflows/release-changelog-template.md"
24+
contributors:
25+
format: "- {{contributorName}}{{#contributorUsernameAsLink}} ({{.}}){{/contributorUsernameAsLink}}"
26+
hide:
27+
uncategorized: true
28+
categories:
29+
- build
30+
- ci
31+
contributors:
32+
- "Timefold Release Bot"
33+
34+
files:
35+
globs:
36+
- pattern: "dist/**/*.whl"
37+
- pattern: "dist/**/*.tar.gz"

setup.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ def run(self):
4444
command = 'mvnw'
4545
if platform.system() == 'Windows':
4646
command = 'mvnw.cmd'
47-
self.create_stubs(project_root, command)
48-
subprocess.run([str((project_root / command).absolute()), 'clean', 'install', '-Dasciidoctor.skip',
49-
'-Dassembly.skipAssembly'],
47+
48+
subprocess.run([str((project_root / command).absolute()), 'clean', 'install'],
5049
cwd=project_root, check=True)
50+
self.create_stubs(project_root, command)
5151
classpath_jars = []
5252
# Add the main artifact
5353
classpath_jars.extend(glob.glob(os.path.join(project_root, 'timefold-solver-python-core', 'target', '*.jar')))
@@ -75,11 +75,11 @@ def find_stub_files(stub_root: str):
7575

7676
this_directory = Path(__file__).parent
7777
long_description = (this_directory / "README.md").read_text()
78-
version = '999-dev0'
78+
timefold_solver_python_version = '999-dev0'
7979

8080
setup(
8181
name='timefold-solver',
82-
version=version,
82+
version=timefold_solver_python_version,
8383
license='Apache License Version 2.0',
8484
license_file='LICENSE',
8585
description='An AI constraint solver that optimizes planning and scheduling problems',

0 commit comments

Comments
 (0)