Skip to content

Commit 05be13c

Browse files
ci: run the suite weekly against re-resolved dependencies (#116)
* ci: run the suite weekly against re-resolved dependencies Every trigger on this workflow was caused by someone pushing, so the suite only ever ran against the versions `uv.lock` pins. That is the right thing for a pull request and the wrong thing as the only signal: a `langgraph` minor that breaks the runtime is invisible here until a user on a fresh install hits it. Issue #103 is the standing form of the complaint -- the extras are unbounded and the lockfile hides what the next major would do. Adds a Monday cron and one job that re-resolves every range from scratch (`uv lock --upgrade`) and runs the suite against the newest versions pyproject.toml's constraints allow. The job is gated to `schedule` and `workflow_dispatch`: on pull requests it would turn someone's branch red for an upstream release that branch did not cause. The re-resolved lockfile diff is printed whether or not the suite passes, because a green run against moved dependencies is the evidence needed to widen a range or drop a pin. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * ci: a failing drift run reports to the issue tracker, not the Actions tab The job as first written had the flaw it was built to fix, one level up: it would detect upstream breakage and then tell nobody. A scheduled run has no pull request to turn red and no author to notify, and this repository has already paid for exactly that -- `pages.yml` failed on two consecutive pushes and sat unnoticed for the better part of two months, while the published site served a version six releases behind. A weekly job in a repository that goes quiet for weeks is the same shape. So a failure now opens an issue, or comments on the open one if there is already one. Reused rather than re-opened: an unattended weekly job that files a fresh issue every Monday is a second way of being ignored. Matched on title rather than a label, so it needs no label to exist first. The body says what a reader needs and not more: that this is not any branch's fault, that every other job resolves against `uv.lock` while this one does not, that the remedy is an upstream fix or a narrower range in pyproject.toml (#103), and that the run log's lockfile diff names what moved. `issues: write` is added at the job level, which replaces rather than extends the workflow's permissions, so `contents: read` is repeated there. Verified by extracting the step's script from the parsed YAML and running it against a stubbed `gh`: the heredoc dedents correctly out of the block scalar, the escaped backticks survive as literals, `$RUN_URL` expands, and the two paths do what they claim -- create when no issue is open, comment when one is, with no duplicate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 92a12ed commit 05be13c

1 file changed

Lines changed: 86 additions & 0 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ on:
44
push:
55
branches: [main]
66
pull_request:
7+
# Mondays, 06:00 UTC. Every other trigger here is caused by someone pushing,
8+
# so without this the suite is only ever run against the dependency versions
9+
# `uv.lock` pins -- see the `upstream-drift` job for what that hides. Note
10+
# GitHub disables a scheduled workflow after 60 days with no repository
11+
# activity, so a long quiet spell stops these runs rather than failing them.
12+
schedule:
13+
- cron: "0 6 * * 1"
714
workflow_dispatch:
815

916
permissions:
@@ -190,6 +197,85 @@ jobs:
190197
# `addopts` in pyproject.toml supplies `-m 'not live'`.
191198
run: uv run pytest
192199

200+
upstream-drift:
201+
# `uv.lock` is what every other job resolves against, so nothing in this
202+
# workflow would notice a new `langgraph` minor breaking the runtime until a
203+
# user on a fresh `pip install grapharc` hit it. Issue #103 is the standing
204+
# form of that complaint: the extras are unbounded and the lockfile hides
205+
# what the next major would do. This job re-resolves every range from
206+
# scratch and runs the suite against the newest versions the constraints in
207+
# pyproject.toml actually allow.
208+
#
209+
# Scheduled and manual only, deliberately. A pull request has to be judged
210+
# against the lockfile it ships; if this ran on PRs, an upstream release on
211+
# the morning of a review would turn someone else's branch red for a reason
212+
# that branch did not cause.
213+
name: upstream drift (unlocked deps)
214+
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
215+
runs-on: ubuntu-latest
216+
# `issues: write` is for the reporting step below; a job's permissions
217+
# replace the workflow's rather than adding to them, so `contents: read`
218+
# is repeated here.
219+
permissions:
220+
contents: read
221+
issues: write
222+
steps:
223+
- uses: actions/checkout@v4
224+
- uses: astral-sh/setup-uv@v5
225+
with:
226+
python-version: "3.12"
227+
enable-cache: true
228+
- name: Re-resolve every dependency to the newest allowed version
229+
run: uv lock --upgrade
230+
- name: Report what moved
231+
# Printed whether or not the suite then passes: a green run against
232+
# moved dependencies is the useful half of this job, because it is the
233+
# evidence that a range can be widened or a pin dropped.
234+
run: git --no-pager diff --stat -- uv.lock
235+
- name: Sync and test against the re-resolved versions
236+
run: |
237+
uv sync --all-extras --group dev
238+
uv run pytest
239+
- name: Say so where someone will see it
240+
# A scheduled run reports to nobody. This repository has already paid
241+
# for that: `pages.yml` failed on two consecutive pushes and the
242+
# failures sat unnoticed for the better part of two months, while the
243+
# published site served a version six releases behind. A weekly job in
244+
# a repository that goes quiet for weeks at a time is the same shape,
245+
# so the failure comes to the issue tracker instead of the Actions tab.
246+
#
247+
# One issue, reused: an unattended weekly job that opens a fresh issue
248+
# every Monday is a second way of being ignored. Matched on title
249+
# rather than a label, so this needs no label to exist first.
250+
if: failure()
251+
env:
252+
GH_TOKEN: ${{ github.token }}
253+
TITLE: "upstream drift: the suite fails against re-resolved dependencies"
254+
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
255+
run: |
256+
body=$(cat <<EOF
257+
The weekly \`upstream-drift\` job failed: the suite does not pass against the
258+
newest dependency versions \`pyproject.toml\` allows.
259+
260+
Run: $RUN_URL
261+
262+
**This is not a failure of any branch.** Every other job resolves against
263+
\`uv.lock\`; this one re-resolves from scratch. So either an upstream release
264+
broke something, or a range in \`pyproject.toml\` needs narrowing — which is
265+
what #103 asks for. The job prints the re-resolved lockfile diff, so the run
266+
log says which dependencies moved.
267+
EOF
268+
)
269+
existing=$(gh issue list --state open --search "$TITLE in:title" \
270+
--json number --jq '.[0].number // empty')
271+
if [ -n "$existing" ]; then
272+
echo "commenting on existing issue #$existing"
273+
gh issue comment "$existing" --body "$body"
274+
else
275+
echo "opening a new issue"
276+
gh issue create --title "$TITLE" --body "$body"
277+
fi
278+
193279
build:
194280
name: build and check the distribution
195281
runs-on: ubuntu-latest

0 commit comments

Comments
 (0)