Skip to content

Commit 3b51d06

Browse files
committed
build: migrate to uv and ruff, vendor the bump workflow
Replace Poetry with uv (PEP 621 + hatchling, committed uv.lock) and make ruff the sole linter and formatter (drop black, blackdoc, pylint and bandit configs). Vendor the version-bump process (uv version --bump + towncrier) from climate-resource/github-actions as local composite actions under .github/actions, and migrate the CI/release/deploy/docs workflows, the Makefile and pre-commit to uv. Also fix ScmRun.from_nc under pandas >= 2.1 (including pandas 3): stack() no longer drops all-NaN entries, so the densified netCDF grid left spurious timeseries and could fail to reshape when an _id dimension was present. Empty dimension combinations and timeseries are now dropped explicitly.
1 parent d1552df commit 3b51d06

69 files changed

Lines changed: 6891 additions & 1699 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.bandit.yml

Lines changed: 0 additions & 2 deletions
This file was deleted.

.coveragerc

Lines changed: 0 additions & 14 deletions
This file was deleted.
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
name: "Bump version"
2+
description: >
3+
Bump a Python project's version using `uv version --bump`,
4+
update the CHANGELOG via towncrier, commit, tag, push,
5+
and optionally land a second commit bumping main onto a pre-release version.
6+
7+
# Vendored from climate-resource/github-actions bump-version so this public repo
8+
# does not depend on a private actions repo. Keep behaviour in sync with the
9+
# upstream action when updating.
10+
11+
inputs:
12+
bump-rule:
13+
description: >
14+
Whitespace-separated list of segments passed to `uv version --bump`.
15+
Each segment becomes a separate `--bump <segment>` argument,
16+
so values like `patch`, `minor`, `major`, `stable`, `minor alpha`, `patch rc`, or `major beta` are all valid.
17+
uv requires a release component (patch, minor, major, stable) alongside any prerelease segment (alpha, beta, rc, dev) when the current version is a stable release.
18+
required: true
19+
pre-release-bump:
20+
description: >
21+
Pre-release segment to bump main to after tagging, so future commits do not share the tagged version.
22+
23+
One of: dev, alpha, beta, rc, none.
24+
25+
Use 'none' to skip the second commit.
26+
required: false
27+
default: "dev"
28+
pre-release-base:
29+
description: >
30+
Bump rule applied to the base version before adding the pre-release
31+
segment in the second commit. Defaults to 'patch'.
32+
33+
Use 'none' to skip bumping the base (only add the pre-release segment).
34+
required: false
35+
default: "patch"
36+
update-changelog:
37+
description: "If 'true', run towncrier to build the CHANGELOG before tagging."
38+
required: false
39+
default: "true"
40+
commit-email:
41+
description: "Email for the CI commit author."
42+
required: false
43+
default: "ci-runner@climate-resource.invalid"
44+
workspace-packages:
45+
description: >
46+
Optional newline-separated list of uv workspace package names to mirror
47+
the bumped version onto (in addition to the root project).
48+
required: false
49+
default: ""
50+
lock:
51+
description: "If 'true', run `uv lock` after each version change."
52+
required: false
53+
default: "true"
54+
pre-commit-command:
55+
description: >
56+
Optional shell command run after the changelog build and before each bump commit.
57+
58+
Use it to regenerate version-derived files (e.g. an OpenAPI schema) so they stay in sync in the tagged commit.
59+
The commit uses `git commit -a`, so any files the command regenerates are picked up automatically.
60+
The command must succeed; a non-zero exit aborts the bump.
61+
required: false
62+
default: ""
63+
pre-commit-skip:
64+
description: "If 'true', pass -n to git commit to skip pre-commit hooks."
65+
required: false
66+
default: "false"
67+
push:
68+
description: "If 'true', push the bump commit, tag, and pre-release commit."
69+
required: false
70+
default: "true"
71+
72+
outputs:
73+
base-version:
74+
description: "The version before bumping."
75+
value: ${{ steps.bump.outputs.base-version }}
76+
new-version:
77+
description: "The new tagged version (no 'v' prefix)."
78+
value: ${{ steps.bump.outputs.new-version }}
79+
tag:
80+
description: "The new git tag (with 'v' prefix)."
81+
value: ${{ steps.bump.outputs.tag }}
82+
dev-version:
83+
description: "The pre-release version landed on main after tagging (if any)."
84+
value: ${{ steps.bump.outputs.dev-version }}
85+
is-prerelease:
86+
description: "'true' when the tagged version is a pre-release (a|b|rc|dev)."
87+
value: ${{ steps.bump.outputs.is-prerelease }}
88+
89+
runs:
90+
using: "composite"
91+
steps:
92+
- name: Configure git identity
93+
shell: bash
94+
run: |
95+
git config --global user.name "${GITHUB_ACTOR}"
96+
git config --global user.email "${{ inputs.commit-email }}"
97+
98+
- name: Bump, changelog, commit, tag
99+
id: bump
100+
shell: bash
101+
env:
102+
BUMP_RULE: ${{ inputs.bump-rule }}
103+
PRE_RELEASE_BUMP: ${{ inputs.pre-release-bump }}
104+
PRE_RELEASE_BASE: ${{ inputs.pre-release-base }}
105+
UPDATE_CHANGELOG: ${{ inputs.update-changelog }}
106+
WORKSPACE_PACKAGES: ${{ inputs.workspace-packages }}
107+
RUN_LOCK: ${{ inputs.lock }}
108+
PRE_COMMIT_COMMAND: ${{ inputs.pre-commit-command }}
109+
COMMIT_SKIP_HOOKS: ${{ inputs.pre-commit-skip }}
110+
DO_PUSH: ${{ inputs.push }}
111+
run: |
112+
set -euo pipefail
113+
114+
commit_args=()
115+
if [[ "${COMMIT_SKIP_HOOKS}" == "true" ]]; then
116+
commit_args+=(-n)
117+
fi
118+
119+
mirror_workspace() {
120+
local version="$1"
121+
if [[ -z "${WORKSPACE_PACKAGES//[[:space:]]/}" ]]; then
122+
return 0
123+
fi
124+
while IFS= read -r pkg; do
125+
pkg="${pkg// /}"
126+
[[ -z "${pkg}" ]] && continue
127+
echo "Mirroring version ${version} onto workspace package ${pkg}"
128+
uv version --frozen --package "${pkg}" "${version}"
129+
done <<< "${WORKSPACE_PACKAGES}"
130+
}
131+
132+
maybe_lock() {
133+
if [[ "${RUN_LOCK}" == "true" ]]; then
134+
uv lock
135+
fi
136+
}
137+
138+
run_pre_commit_command() {
139+
if [[ -n "${PRE_COMMIT_COMMAND}" ]]; then
140+
echo "Running pre-commit command"
141+
bash -c "${PRE_COMMIT_COMMAND}"
142+
fi
143+
}
144+
145+
BASE_VERSION="$(uv version --short)"
146+
echo "Bumping from version ${BASE_VERSION}"
147+
148+
read -r -a bump_segments <<< "${BUMP_RULE}"
149+
if [[ ${#bump_segments[@]} -eq 0 ]]; then
150+
echo "bump-rule must not be empty" >&2
151+
exit 1
152+
fi
153+
bump_cli_args=()
154+
for seg in "${bump_segments[@]}"; do
155+
bump_cli_args+=(--bump "${seg}")
156+
done
157+
158+
uv version --frozen "${bump_cli_args[@]}"
159+
NEW_VERSION="$(uv version --short)"
160+
echo "Bumped to version ${NEW_VERSION}"
161+
162+
mirror_workspace "${NEW_VERSION}"
163+
maybe_lock
164+
165+
if [[ "${UPDATE_CHANGELOG}" == "true" ]]; then
166+
uv run towncrier build --yes --version "v${NEW_VERSION}"
167+
else
168+
echo "Skipping changelog update"
169+
fi
170+
171+
run_pre_commit_command
172+
173+
git commit "${commit_args[@]}" -a -m "bump: version ${BASE_VERSION} -> ${NEW_VERSION}"
174+
git tag "v${NEW_VERSION}"
175+
176+
if [[ "${DO_PUSH}" == "true" ]]; then
177+
git push
178+
git push --tags
179+
fi
180+
181+
if [[ "${NEW_VERSION}" =~ (a|b|rc|dev) ]]; then
182+
IS_PRERELEASE="true"
183+
else
184+
IS_PRERELEASE="false"
185+
fi
186+
187+
echo "base-version=${BASE_VERSION}" >> "${GITHUB_OUTPUT}"
188+
echo "new-version=${NEW_VERSION}" >> "${GITHUB_OUTPUT}"
189+
echo "tag=v${NEW_VERSION}" >> "${GITHUB_OUTPUT}"
190+
echo "is-prerelease=${IS_PRERELEASE}" >> "${GITHUB_OUTPUT}"
191+
192+
# Skip the dev bump if the tagged version is already a pre-release or
193+
# the caller opted out.
194+
if [[ "${PRE_RELEASE_BUMP}" == "none" ]]; then
195+
echo "Skipping pre-release bump (pre-release-bump=none)"
196+
exit 0
197+
fi
198+
if [[ "${IS_PRERELEASE}" == "true" ]]; then
199+
echo "Skipping pre-release bump; tagged version is already a pre-release"
200+
exit 0
201+
fi
202+
203+
PREV_VERSION="${NEW_VERSION}"
204+
bump_args=()
205+
if [[ "${PRE_RELEASE_BASE}" != "none" ]]; then
206+
bump_args+=(--bump "${PRE_RELEASE_BASE}")
207+
fi
208+
bump_args+=(--bump "${PRE_RELEASE_BUMP}")
209+
uv version --frozen "${bump_args[@]}"
210+
211+
DEV_VERSION="$(uv version --short)"
212+
echo "Bumping main onto pre-release ${PREV_VERSION} > ${DEV_VERSION}"
213+
214+
mirror_workspace "${DEV_VERSION}"
215+
maybe_lock
216+
run_pre_commit_command
217+
218+
git commit "${commit_args[@]}" -a -m "bump(${PRE_RELEASE_BUMP}): version ${PREV_VERSION} > ${DEV_VERSION}"
219+
220+
if [[ "${DO_PUSH}" == "true" ]]; then
221+
git push
222+
fi
223+
224+
echo "dev-version=${DEV_VERSION}" >> "${GITHUB_OUTPUT}"
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: "Setup uv"
2+
description: "Install uv (and optionally a Python version) with caching enabled"
3+
4+
inputs:
5+
python-version:
6+
description: "Python version to install"
7+
required: false
8+
uv-version:
9+
description: "Version of uv to install (defaults to the latest release)"
10+
required: false
11+
working-directory:
12+
description: "Working directory for uv commands"
13+
required: false
14+
default: "."
15+
16+
# Cache configuration
17+
enable-cache:
18+
description: "Enable caching of the uv cache"
19+
required: false
20+
default: "auto"
21+
cache-dependency-glob:
22+
description: "Glob pattern for cache dependency files"
23+
required: false
24+
default: "**/uv.lock"
25+
cache-suffix:
26+
description: "Suffix for the cache key"
27+
required: false
28+
cache-local-path:
29+
description: "Path to a local cache directory"
30+
required: false
31+
32+
runs:
33+
using: "composite"
34+
steps:
35+
- name: Setup uv
36+
uses: astral-sh/setup-uv@v8.1.0
37+
with:
38+
version: ${{ inputs.uv-version }}
39+
python-version: ${{ inputs.python-version }}
40+
working-directory: ${{ inputs.working-directory }}
41+
enable-cache: ${{ inputs.enable-cache }}
42+
cache-dependency-glob: ${{ inputs.cache-dependency-glob }}
43+
cache-suffix: ${{ inputs.cache-suffix }}
44+
cache-local-path: ${{ inputs.cache-local-path }}

.github/actions/setup/action.yml

Lines changed: 0 additions & 57 deletions
This file was deleted.

0 commit comments

Comments
 (0)