Skip to content

Commit 9d3be95

Browse files
ElePTHuangJunye
andauthored
Add new release preparation workflow (#82)
* Add github workflow that automatically generates a release prep. PR. The workflow is expected to be triggered manually with no inputs. It will read the latest qiskit-serverless version in PyPI and open a release preparation PR if the detected major or minor is higher than the current requirement pin. The PR will also bump the qiskit_ibm_catalog major or minor version accordingly. Patch releases of qiskit-serverless don't require a catalog release, hence they are ignored. The release preparation PR shows instructions to facilitate the release process. Only maintainers are allowed to push tags to GitHub. * Apply suggestions from Junye's code review Co-authored-by: Junye Huang <h.jun.ye@gmail.com> * Move UPDATE_TYPE * Use dash in requirements for consistency with requirements-dev --------- Co-authored-by: Junye Huang <h.jun.ye@gmail.com>
1 parent c1969fc commit 9d3be95

File tree

2 files changed

+152
-2
lines changed

2 files changed

+152
-2
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
name: Generate release preparation PR
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
override_version:
7+
description: "Manually override the latest qiskit-serverless version. Leave empty to use PyPI."
8+
required: false
9+
default: ""
10+
11+
permissions:
12+
contents: write
13+
pull-requests: write
14+
15+
jobs:
16+
prepare-release-pr:
17+
runs-on: ubuntu-latest
18+
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v6
22+
23+
- name: Read current pin from requirements.txt
24+
id: current
25+
run: |
26+
LINE=$(grep -E '^qiskit-serverless~=' requirements.txt | head -n1 || true)
27+
CURR_VER="${LINE#*~=}"
28+
echo "Current pin version: $CURR_VER"
29+
IFS='.' read -r CURR_MAJ CURR_MIN CURR_PAT <<< "$CURR_VER"
30+
echo "curr_major=$CURR_MAJ" >> "$GITHUB_OUTPUT"
31+
echo "curr_minor=$CURR_MIN" >> "$GITHUB_OUTPUT"
32+
echo "curr_patch=$CURR_PAT" >> "$GITHUB_OUTPUT"
33+
34+
- name: Determine latest qiskit-serverless version
35+
id: pypi
36+
run: |
37+
# workflow_dispatch override
38+
OVERRIDE="${{ inputs.override_version }}"
39+
40+
if [ -n "$OVERRIDE" ]; then
41+
echo "Using workflow_dispatch override version: $OVERRIDE"
42+
LATEST="$OVERRIDE"
43+
else
44+
echo "Fetching latest version from PyPI..."
45+
JSON=$(curl -fsSL https://pypi.org/pypi/qiskit-serverless/json)
46+
LATEST=$(echo "$JSON" \
47+
| jq -r '.releases | keys[]' \
48+
| grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \
49+
| sort -V | tail -n1)
50+
if [ -z "$LATEST" ]; then
51+
echo "Failed to determine latest stable version from PyPI." >&2
52+
exit 1
53+
fi
54+
fi
55+
56+
echo "Using latest version: $LATEST"
57+
IFS='.' read -r L_MAJ L_MIN L_PAT <<< "$LATEST"
58+
echo "latest=$LATEST" >> "$GITHUB_OUTPUT"
59+
echo "latest_major=$L_MAJ" >> "$GITHUB_OUTPUT"
60+
echo "latest_minor=$L_MIN" >> "$GITHUB_OUTPUT"
61+
echo "latest_patch=$L_PAT" >> "$GITHUB_OUTPUT"
62+
63+
- name: Decide if update needed (ignore patch-only updates)
64+
id: decision
65+
run: |
66+
CM=${{ steps.current.outputs.curr_major }}
67+
Cn=${{ steps.current.outputs.curr_minor }}
68+
LM=${{ steps.pypi.outputs.latest_major }}
69+
Ln=${{ steps.pypi.outputs.latest_minor }}
70+
71+
if [ "$LM" -gt "$CM" ]; then
72+
echo "Upstream major bump detected"
73+
echo "update=true" >> "$GITHUB_OUTPUT"
74+
echo "update_type=major" >> "$GITHUB_OUTPUT"
75+
elif [ "$LM" -eq "$CM" ] && [ "$Ln" -gt "$Cn" ]; then
76+
echo "Upstream minor bump detected"
77+
echo "update=true" >> "$GITHUB_OUTPUT"
78+
echo "update_type=minor" >> "$GITHUB_OUTPUT"
79+
else
80+
echo "No update needed (patch-only or older)"
81+
echo "update=false" >> "$GITHUB_OUTPUT"
82+
echo "update_type=none" >> "$GITHUB_OUTPUT"
83+
fi
84+
85+
- name: Stop if no update needed
86+
if: steps.decision.outputs.update == 'false'
87+
run: echo "Nothing to do."
88+
89+
- name: Apply updates
90+
if: steps.decision.outputs.update == 'true'
91+
id: apply
92+
run: |
93+
UPDATE_TYPE="${{ steps.decision.outputs.update_type }}"
94+
95+
# Compute new catalog version
96+
OLD_VER=$(tr -d '[:space:]' < qiskit_ibm_catalog/VERSION.txt)
97+
IFS='.' read -r A B C <<< "$OLD_VER"
98+
if [ "$UPDATE_TYPE" = "major" ]; then
99+
NEW_VER="$((A + 1)).0.0"
100+
else
101+
NEW_VER="${A}.$((B + 1)).0"
102+
fi
103+
BRANCH="prepare-${NEW_VER}-release"
104+
105+
# Compute new serverless pin
106+
LM=${{ steps.pypi.outputs.latest_major }}
107+
Ln=${{ steps.pypi.outputs.latest_minor }}
108+
if [ "$UPDATE_TYPE" = "major" ]; then
109+
NEW_PIN_VER="${LM}.0.0"
110+
else
111+
NEW_PIN_VER="${LM}.${Ln}.0"
112+
fi
113+
114+
# Apply updates
115+
echo "Updating pin to qiskit-serverless~=${NEW_PIN_VER}"
116+
sed -i -E "s/^qiskit-serverless~=[0-9]+\.[0-9]+\.[0-9]+/qiskit-serverless~=${NEW_PIN_VER}/" requirements.txt
117+
echo "$NEW_VER" > qiskit_ibm_catalog/VERSION.txt
118+
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
119+
echo "new_pkg_version=$NEW_VER" >> "$GITHUB_OUTPUT"
120+
echo "new_pin_version=$NEW_PIN_VER" >> "$GITHUB_OUTPUT"
121+
122+
- name: Create Pull Request
123+
if: steps.decision.outputs.update == 'true'
124+
uses: peter-evans/create-pull-request@v8
125+
with:
126+
token: ${{ secrets.GITHUB_TOKEN }}
127+
branch: ${{ steps.apply.outputs.branch }}
128+
base: main
129+
title: >
130+
Prepare ${{ steps.apply.outputs.new_pkg_version }} release
131+
body: |
132+
This PR prepares a new release of **qiskit-ibm-catalog**:
133+
134+
- Bump catalog version → `${{ steps.apply.outputs.new_pkg_version }}`
135+
- Update qiskit-serverless requirement → `qiskit-serverless~=${{ steps.apply.outputs.new_pin_version }}`
136+
- Patch-only updates of `qiskit-serverless` are ignored
137+
138+
To release the package:
139+
140+
- Merge this PR
141+
- Ensure you're up to date: `git pull origin main`
142+
- Tag with `v${{ steps.apply.outputs.new_pkg_version }}`: `git tag -a v${{ steps.apply.outputs.new_pkg_version }} -m "Release Qiskit IBM Catalog v${{ steps.apply.outputs.new_pkg_version }}"`
143+
- Push the tag to GitHub: `git push origin v${{ steps.apply.outputs.new_pkg_version }}`
144+
145+
Pushing the tag will trigger the following [GitHub workflow](https://github.com/Qiskit/qiskit-ibm-catalog/blob/main/.github/workflows/client-pypi-release.yaml) to release the package on PyPI.
146+
147+
labels: |
148+
release
149+
automation
150+
delete-branch: true

requirements.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
certifi>=2021.5.30
2-
importlib_metadata>=4.8.1
3-
qiskit_serverless~=0.28.0
2+
importlib-metadata>=4.8.1
3+
qiskit-serverless~=0.28.0

0 commit comments

Comments
 (0)