Skip to content

Commit 82c0854

Browse files
authored
build: pin every dependency to an exact version, including runtime tool installs (#77)
* build(renovate): pin every dependency to an exact version Org-wide policy: no ranges, in any repo, in any ecosystem. A range means the version you get depends on when you install -- CI, a laptop and a release build can each resolve differently -- and a bad upstream release lands without a PR anyone reviewed. Renovate now raises a "Pin dependencies" PR for anything that regresses to a range, and every upgrade arrives as a reviewable PR that CI has to pass. That is the point rather than the cost: the same number of upgrades, each one visible. A survey found the repos were already almost entirely pinned -- Maven and Gradle had no ranges at all, and only four dependencies across two repos needed changing (reqstool-vscode#103, reqstool-client#440). This keeps them that way. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * build(ci): pin the tools the workflows install at runtime The earlier survey only looked at package manifests, and missed a whole class of dependency: tools installed inside a workflow. They execute in CI and some of them feed a publish, so an unpinned one is exactly the risk pinning exists to remove. Worst of them was `docker run renovate/renovate` with no tag at all -- :latest on every run, so that job's behaviour could change with no commit anywhere. Now 44.32.5. Also pinned: zizmor 1.29.0, yamllint 1.38.0, PyYAML 6.0.3, hatch 1.18.0, twine 7.0.0, @fission-ai/openspec 1.9.0. Each carries a `# renovate:` comment, so they are tracked rather than merely frozen -- the distinction the four earlier pins were about. The custom manager gains one matchString for the inline `tool==1.2.3` and `pkg@1.2.3` forms. The docker image reuses the existing `VERSION="..."` form via a variable, rather than a third pattern: an inline comment there would have needed backticks, which bash would have run as command substitution. install-reqstool stays unpinned on purpose, and now says so. The build matrix runs it with reqstool-source: [pypi, main] precisely to test against whatever reqstool currently releases; pinning it would defeat the check it exists for. Verified all ten annotations are discovered by the manager's regexes. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> --------- Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
1 parent 0a0152b commit 82c0854

7 files changed

Lines changed: 28 additions & 7 deletions

File tree

.github/actions/install-reqstool/action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,5 +27,8 @@ runs:
2727
if [ "$REQSTOOL_SOURCE" = "main" ]; then
2828
pip install "reqstool @ git+https://github.com/reqstool/reqstool-client.git@main"
2929
else
30+
# Deliberately unpinned. The build matrix runs this with
31+
# reqstool-source: [pypi, main] precisely to test against whatever
32+
# reqstool currently releases; pinning would defeat the check.
3033
pip install reqstool
3134
fi

.github/renovate.json5

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,15 @@
66
":semanticCommits",
77
],
88

9+
// Every dependency is pinned to an exact version, in every repo. A range means
10+
// the version you get depends on when you install: CI, a laptop and a release
11+
// build can each resolve differently, and a bad upstream release lands without
12+
// a PR anyone reviewed. Pinning turns each upgrade into a reviewable PR that CI
13+
// has to pass -- which is the point, not extra noise.
14+
//
15+
// Renovate raises "Pin dependencies" PRs for anything that regresses to a range.
16+
rangeStrategy: "pin",
17+
918
semanticCommits: "enabled",
1019
semanticCommitType: "chore",
1120
semanticCommitScope: "{{datasource}}",
@@ -61,6 +70,7 @@
6170
matchStrings: [
6271
"# renovate: datasource=(?<datasource>[a-z-]+?) depName=(?<depName>\\S+)\\s+default: \"(?<currentValue>[^\"]+)\"",
6372
"# renovate: datasource=(?<datasource>[a-z-]+?) depName=(?<depName>\\S+)\\s+VERSION=\"(?<currentValue>[^\"]+)\"",
73+
"# renovate: datasource=(?<datasource>[a-z-]+?) depName=(?<depName>\\S+)\\s+[^\\n]*?(?:==|@)(?<currentValue>[0-9][^\\s\"']*)",
6474
],
6575
},
6676
],

.github/workflows/ci.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,12 @@ jobs:
3434
sudo mv actionlint /usr/local/bin/
3535
3636
- name: Install zizmor
37-
run: pip install zizmor
37+
# renovate: datasource=pypi depName=zizmor
38+
run: pip install zizmor==1.29.0
3839

3940
- name: Install yamllint
40-
run: pip install yamllint
41+
# renovate: datasource=pypi depName=yamllint
42+
run: pip install yamllint==1.38.0
4143

4244
# The ignore covers exactly one thing: actionlint does not yet know the
4345
# `$/` self-repository syntax GitHub shipped on 2026-07-30, and rejects it
@@ -89,7 +91,8 @@ jobs:
8991
# script for why this specific shape is worth a test.
9092
- name: Check reusable workflow permissions
9193
run: |
92-
pip install --quiet pyyaml
94+
# renovate: datasource=pypi depName=PyYAML
95+
pip install --quiet PyYAML==6.0.3
9396
python3 tests/actions/check-permissions.py
9497
9598
# Proves the `$/` self-repository syntax actually resolves on a runner, rather

.github/workflows/common-validate-openspec.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,6 @@ jobs:
3535

3636
- name: Validate OpenSpec specs
3737
run: |
38-
npm install -g @fission-ai/openspec
38+
# renovate: datasource=npm depName=@fission-ai/openspec
39+
npm install -g @fission-ai/openspec@1.9.0
3940
openspec validate --specs --strict

.github/workflows/common-validate-renovate.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@ jobs:
2525
env:
2626
CONFIG_PATH: ${{ inputs.config-path }}
2727
run: |
28+
# renovate: datasource=docker depName=renovate/renovate
29+
VERSION="44.32.5"
2830
docker run --rm \
2931
-v "$GITHUB_WORKSPACE:/repo" \
30-
renovate/renovate \
32+
"renovate/renovate:$VERSION" \
3133
renovate-config-validator "/repo/$CONFIG_PATH"

.github/workflows/python-build-hatch.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ jobs:
5555
with:
5656
python-version: ${{ inputs.python-version }}
5757

58-
- run: pip install hatch
58+
# renovate: datasource=pypi depName=hatch
59+
- run: pip install hatch==1.18.0
5960

6061
- name: Run tests (with coverage)
6162
if: ${{ inputs.coverage-source != '' }}

.github/workflows/python-publish-to-pypi.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ jobs:
6464
- name: Dry-run — validate artifacts
6565
if: ${{ inputs.dry-run }}
6666
run: |
67-
pip install --quiet twine
67+
# renovate: datasource=pypi depName=twine
68+
pip install --quiet twine==7.0.0
6869
twine check --strict dist/*
6970
7071
- name: Publish to Test PyPI

0 commit comments

Comments
 (0)