Skip to content

Implement latest tag for image matrix builds#501

Merged
ianpittwood merged 14 commits into
mainfrom
feature/matrix-latest-tag
May 11, 2026
Merged

Implement latest tag for image matrix builds#501
ianpittwood merged 14 commits into
mainfrom
feature/matrix-latest-tag

Conversation

@ianpittwood
Copy link
Copy Markdown
Contributor

@ianpittwood ianpittwood commented Apr 29, 2026

Closes #498.

Summary

  • Adds ImageMatrix.latest_combination that resolves the cartesian-product row at the maximum version of every dependency and list-typed value, returning None (with a warning) for non-version-parseable axes.
  • ImageMatrix.to_image_versions() now sets latest=True on the single matching row via a new _matches_latest static helper.
  • default_matrix_tag_patterns() gains the four LATEST-filtered patterns from default_tag_patterns(), so the existing ImageTarget.tag_patterns filter machinery emits latest, <os>, <variant>, and <os>-<variant> on the right rows.

No changes to ImageTarget, README push, CI workflows, or other consumers — they already handle latest=True correctly.

This unblocks #484 (push-order in CI) by giving matrix images a meaningful latest signal.

Test Plan

  • Unit tests cover happy path, None-on-unparseable, short-circuit, scalar/list value distinction, original-string preservation, latest=True propagation, default-pattern parity (1439 tests pass)
  • Integration test asserts ImageTarget.tag_suffixes emits the bare latest tag for the latest matrix row + primary OS + primary variant
  • Empirical validation against images-connect/connect-content:
    • Latest combination (R4.6.0/python3.14.4/base/ubuntu-24.04) → emits latest, base, ubuntu-24.04, ubuntu-24.04-base (+ existing matrix tags)
    • Latest deps + non-primary variant (pro) → emits pro, ubuntu-24.04-pro only
    • Latest deps + non-primary OS (22.04) → emits ubuntu-22.04, ubuntu-22.04-base only
    • Older deps (R4.3.3/python3.11.15) → no `latest`-family tags
  • Documentation updated (posit-bakery/docs/configuration.qmd ImageMatrix section)

🤖 Generated with Claude Code

@ianpittwood ianpittwood force-pushed the feature/matrix-latest-tag branch from dcdd8b9 to 01c5884 Compare April 29, 2026 00:07
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 29, 2026

Test Results

1 521 tests  +17   1 521 ✅ +17   8m 14s ⏱️ -28s
    1 suites ± 0       0 💤 ± 0 
    1 files   ± 0       0 ❌ ± 0 

Results for commit 03b1acd. ± Comparison against base commit 3ce066a.

♻️ This comment has been updated with latest results.

@ianpittwood ianpittwood marked this pull request as ready for review April 29, 2026 14:52
@ianpittwood ianpittwood requested a review from bschwedler as a code owner April 29, 2026 14:52
@ianpittwood ianpittwood force-pushed the feature/matrix-latest-tag branch from 01c5884 to 4b22aa8 Compare May 7, 2026 16:58
Comment thread posit-bakery/posit_bakery/config/image/matrix.py Outdated
Comment thread posit-bakery/posit_bakery/config/image/matrix.py Outdated
Comment thread posit-bakery/posit_bakery/config/image/matrix.py
Comment thread posit-bakery/posit_bakery/config/tag.py Outdated
ianpittwood and others added 9 commits May 8, 2026 13:04
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pin which axis/candidate fires the warning so tests catch regressions
in iteration order and short-circuit semantics.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Per CLAUDE.md, prefer file-level imports unless there's a circular-import
or perf reason. The integration test for matrix latest tags doesn't have
either.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add a "Latest Tag Selection" subsection to the ImageMatrix docs covering
auto-selection semantics, the unparseable-axis warning path, and scalar
vs list value handling.

Mirror latest_combination's str() coercion in _matches_latest so YAML-
typed scalars (int/float) in list-typed values compare correctly against
the stringified picks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ianpittwood ianpittwood force-pushed the feature/matrix-latest-tag branch from 4b22aa8 to 8235454 Compare May 8, 2026 19:04
ianpittwood and others added 5 commits May 8, 2026 13:04
Refactors ImageMatrix.to_image_versions to call resolved_dependencies a
single time and pass the result to both _cartesian_product and a new
_compute_latest_combination helper. The previous code invoked the
network-bound, deepcopying resolved_dependencies property twice — once
via latest_combination and again for the cartesian product — and a
non-deterministic upstream could in principle have produced divergent
version sets between the two calls.

Also returns None from latest_combination when the matrix has no
version-bearing axes (no dependencies and no list-typed values), so a
matrix with only scalar values does not silently mark every row as
latest.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous broad except Exception path emitted a "has unparseable
version" warning for every error, including ones unrelated to version
parsing. Split into:

- except InvalidVersion: keep the parsing-specific message
- except Exception: new "unexpected error" message that includes the
  exception type so operators can triage without being misled

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
A list-typed value with no entries (e.g., values: {flavor: []}) used to
crash latest_combination with `ValueError: max() iterable argument is
empty`. The function now detects empty axes up front and follows the
same return-None-with-warning convention as the other failure paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dc.resolve_versions() can hit the network (the Python constraint reads
upstream version metadata), and a single build commonly reads
resolved_dependencies more than once via latest_combination,
to_image_versions, and external callers. Switch the property to
cached_property so each matrix only resolves its constraints once per
instance.

Field assignment is gated by validate_assignment=True, so the same
update path (e.g., Image.create_matrix(update_if_exists=True)) that
mutates dependencies/dependencyConstraints would have left a stale
cache. Add a model_validator(mode="after") that pops the cache on every
re-validation so subsequent reads re-resolve.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both default_tag_patterns and default_matrix_tag_patterns returned the
same four LATEST-filtered TagPatterns. Extract them into a private
_shared_latest_tag_patterns helper that each function splats into its
return list so the LATEST set has a single definition site.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ianpittwood ianpittwood requested a review from bschwedler May 8, 2026 19:37
@ianpittwood ianpittwood added this pull request to the merge queue May 11, 2026
Merged via the queue into main with commit b0e9cb6 May 11, 2026
23 checks passed
@ianpittwood ianpittwood deleted the feature/matrix-latest-tag branch May 11, 2026 15:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement a latest tag behavior for image matrix builds

2 participants