Skip to content

[feat] auto-discover recent Docker Hub dev tags in update center#495

Merged
cita-777 merged 3 commits intomainfrom
release/feat-update-center-recent-docker-tags-20260418
May 8, 2026
Merged

[feat] auto-discover recent Docker Hub dev tags in update center#495
cita-777 merged 3 commits intomainfrom
release/feat-update-center-recent-docker-tags-20260418

Conversation

@cita-777
Copy link
Copy Markdown
Owner

@cita-777 cita-777 commented Apr 18, 2026

Summary

This PR upgrades the update center's Docker Hub discovery path so operators do not need to manually look up recent dev / branch / sha tags before deploying.

What changed

  • keep the existing stable Docker Hub candidate (latest / main / stable SemVer) as the primary candidate
  • auto-discover and expose the most recent non-stable Docker Hub tags with digest metadata
  • show those recent non-stable tags in the Settings -> Update Center UI for one-click deploys
  • persist the recent-tag snapshot in update-center runtime state so cached status stays consistent
  • document the new stable-plus-recent discovery behavior

Verification

Passed on dev and again on the clean release branch:

  • focused vitest:
    • src/server/services/updateCenterVersionService.test.ts
    • src/server/services/updateCenterRuntimeStateService.test.ts
    • src/server/services/updateCenterPollingService.test.ts
    • src/server/routes/api/updateCenter.test.ts
    • src/web/pages/settings/UpdateCenterSection.test.tsx
  • npm run typecheck
  • npm run repo:drift-check
  • npm run build:web
  • npm run docs:build
  • git diff --check

Notes

  • Stable Docker Hub discovery remains the primary path; recent non-stable tags are additive.
  • npm test is still red in this repo snapshot because unrelated tmp/sub2api/frontend/** suites are broken/missing dependencies; this PR does not change that baseline.

Summary by CodeRabbit

  • Bug Fixes

    • Improved validation and filtering of Docker Hub recent tags to exclude malformed candidates lacking required tag information.
  • New Features

    • Extended update center to display recent Docker Hub tag candidates with associated digest information when available, providing better visibility into available updates.

This release branch snapshots the latest dev work onto current main so the
update center can surface recent non-stable Docker tags without operators
looking them up manually. The branch keeps stable Docker discovery as the
primary path while carrying the new recent-tag auto-discovery, UI affordances,
and regression coverage through the repo's release flow.

Constraint: Publication must start from latest origin/main and merge origin/dev on a clean release branch
Constraint: Stable Docker Hub discovery semantics must remain intact while adding recent non-stable discovery
Rejected: Re-open or reuse the already-merged PR #494 branch | it has already been absorbed by main and deleted remotely
Rejected: Publish directly from dev | repo workflow requires a clean release branch to main
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep future dev-tag publication work on fresh release branches cut from origin/main; do not revive merged release branches
Tested: Focused update-center vitest suite, npm run typecheck, npm run repo:drift-check, npm run build:web, npm run docs:build, git diff --check (release branch)
Not-tested: Full npm test remains red because tmp/sub2api frontend suites are still broken in this repo snapshot
@github-actions github-actions Bot added area: server Server-side API and backend changes area: docs Docs and README changes area: web Web UI changes size: L 500 to 999 lines changed labels Apr 18, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 18, 2026

Review Change Stack
No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e96e082a-23bd-4c3b-add2-2b4a3f50b78e

📥 Commits

Reviewing files that changed from the base of the PR and between fa6edec and 93bc42a.

📒 Files selected for processing (2)
  • src/web/pages/settings/UpdateCenterSection.test.tsx
  • src/web/pages/settings/UpdateCenterSection.tsx
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/web/pages/settings/UpdateCenterSection.tsx
  • src/web/pages/settings/UpdateCenterSection.test.tsx

📝 Walkthrough

Walkthrough

UpdateCenterStatus is extended with optional dockerHubRecentTags, and normalization logic filters candidates to require non-empty tagName. UI rendering uses the normalized tagName and conditionally displays digest information. Test fixtures and assertions verify valid candidates render correctly and invalid candidates are excluded.

Changes

Docker Hub Recent Tags Normalization & Filtering

Layer / File(s) Summary
Type Extension & Normalization Logic
src/web/pages/settings/UpdateCenterSection.tsx
UpdateCenterStatus is extended with optional dockerHubRecentTags array. New normalizeRecentDockerCandidates() function filters candidates to only those with non-empty tagName, introducing RecentDockerCandidate helper type.
UI Rendering with Digest Display
src/web/pages/settings/UpdateCenterSection.tsx
Candidate tag display uses the normalized tagName instead of fallback version fields. Candidate digest information is conditionally rendered when present, with formatting and tooltip.
Test Fixtures & Assertions
src/web/pages/settings/UpdateCenterSection.test.tsx
Mock getUpdateCenterStatus fixture is extended with a candidate lacking tagName. Test assertions verify UI renders the valid candidate dev-20260417-f67ade2 with digest text and does not render the invalid feature-without-raw-tag candidate.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • cita-777/metapi#533: Overlaps directly with this PR's dockerHubRecentTags feature addition, normalization, and UI rendering.
  • cita-777/metapi#318: Modifies UpdateCenterSection component and tests for Docker Hub tag metadata, candidate filtering, and digest-aware deployment rendering.
  • cita-777/metapi#349: Expands UpdateCenter status payload handling in UpdateCenterSection and its tests.

Poem

🐰 Recent tags now dance with grace,
Filtered clean by tagName's space,
Digests shown when present and true,
Invalid ones? Removed from view!
The Docker Hub flow's strong and bright,
Our normalization works just right! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: auto-discovery of recent Docker Hub dev tags in the update center, which is the primary feature described in the PR objectives.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/feat-update-center-recent-docker-tags-20260418

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/server/routes/api/updateCenter.test.ts (1)

265-275: Consider an explicit empty-recentNonStable assertion.

This scenario returns recentNonStable: [], but the response toMatchObject on Line 294-303 doesn't assert the absence/emptiness of dockerHubRecentTags in the API response. Adding dockerHubRecentTags: [] to the expectation would lock in that an empty list is faithfully returned (vs. omitted or replaced with null), which matters for the UI that iterates this field unconditionally.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/server/routes/api/updateCenter.test.ts` around lines 265 - 275, In the
"returns partial status when a single version source lookup fails" test, update
the toMatchObject assertion (the response JSON asserted after calling the route)
to explicitly include dockerHubRecentTags: [] so the test verifies an empty
array is returned; locate the test by its description and the mocks
(fetchLatestStableGitHubReleaseMock, fetchDockerHubTagCandidatesMock) and modify
the expectation that currently uses toMatchObject to add the
dockerHubRecentTags: [] key/value pair.
src/web/pages/settings/UpdateCenterSection.test.tsx (1)

459-501: New deploy-from-recent-tag test is meaningful but the card locator is fragile.

The assertion flow (locate card → click auto-deploy button → verify deployUpdateCenter payload → verify log stream) is good coverage for the new one-click path. However, the card locator on Lines 473-476 picks the first element with any style object whose rendered text contains the target string — that can match an ancestor (e.g., the whole section wrapper) rather than the intended tag card, silently masking rendering regressions. Prefer a more specific predicate (e.g., a data-testid, a class substring like docker-hub-recent-tag-card, or matching the immediate deploy-button container).

♻️ Suggested tightening
-      const recentTagCard = root.root.find((node) => (
-        typeof node.props?.style === 'object'
-        && collectText(node).includes('dev-20260417-f67ade2 @ sha256:bbbbbbbbbbbb')
-      ));
+      const recentTagCard = root.root.find((node) => (
+        typeof node.props?.className === 'string'
+        && node.props.className.includes('docker-hub-recent-tag') // or a data-testid
+        && collectText(node).includes('dev-20260417-f67ade2 @ sha256:bbbbbbbbbbbb')
+      ));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/web/pages/settings/UpdateCenterSection.test.tsx` around lines 459 - 501,
The test's card locator is too broad and may match an ancestor; tighten the
predicate in UpdateCenterSection.test.tsx (the "deploys auto-discovered recent
non-stable Docker Hub tags without manual input" test) so it targets the
specific tag card element instead of any node with a style object — for example,
look for a node with a dedicated identifier like data-testid or a class
substring (e.g., 'docker-hub-recent-tag-card'), or require the node to be a
container element that also contains the deploy button child (the same element
that yields deployRecentButton) before asserting and clicking; update the find
used to set recentTagCard to this stricter predicate so the subsequent
deployRecentButton click and apiMock assertions remain valid.
src/server/services/updateCenterVersionService.ts (1)

142-155: Alias detection is case-sensitive while priority is case-insensitive — minor inconsistency.

isPreferredDockerHubAlias compares against ['latest','main'] without lowercasing, but getRecentNonStableDockerHubPriority does lowercase the tag. In the unlikely case of a tag pushed as Latest/Main, it would slip past isStableDockerHubTag and end up in recentNonStable with priority 3. Low impact in practice (Docker Hub tags are conventionally lowercase), but trivial to align for consistency.

♻️ Suggested alignment
 function isPreferredDockerHubAlias(input: string | null | undefined): boolean {
-  const tag = normalizeDockerHubTagName(input);
+  const tag = normalizeDockerHubTagName(input).toLowerCase();
   return PREFERRED_DOCKER_HUB_TAG_ALIASES.includes(tag as typeof PREFERRED_DOCKER_HUB_TAG_ALIASES[number]);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/server/services/updateCenterVersionService.ts` around lines 142 - 155,
The alias check is currently case-sensitive (isPreferredDockerHubAlias uses
normalizeDockerHubTagName but compares against PREFERRED_DOCKER_HUB_TAG_ALIASES
as-is) while other logic lowercases tags (getRecentNonStableDockerHubPriority),
so make alias detection case-insensitive by normalizing case: update
normalizeDockerHubTagName to return the trimmed lowercase string (or
alternatively lowerCase the tag inside isPreferredDockerHubAlias before
comparing), and ensure isPreferredDockerHubAlias compares the lowercased tag
against the lowercased alias list (or against the existing constants if
normalize now lowercases) so 'Latest'/'Main' are treated the same as
'latest'/'main'.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/web/pages/settings/UpdateCenterSection.tsx`:
- Around line 224-227: The filter in normalizeRecentDockerCandidates currently
allows entries missing a real Docker tag by accepting entries with only
normalizedVersion; update the predicate so it only returns entries that have a
non-empty raw Docker tag (check entry?.tagName is a non-blank string) to ensure
the UI can only enable one-click deploys when a real tag is present; modify the
function normalizeRecentDockerCandidates (operating on
UpdateCenterStatus['dockerHubRecentTags']) to require and trim entry.tagName
rather than allowing normalizedVersion.
- Around line 817-823: The UI currently shows candidateLabel and publishedAt but
not the candidateDigest that runDeploy will use; update the JSX around the
candidate display (the divs rendering candidateLabel and the publishedAt hint in
UpdateCenterSection.tsx) to render the candidateDigest (e.g., a short/truncated
digest string or a copyable full digest) before the deploy controls so operators
can see which digest will be deployed; ensure the digest value referenced is the
same prop/variable named candidateDigest and leave the existing runDeploy call
unchanged.

---

Nitpick comments:
In `@src/server/routes/api/updateCenter.test.ts`:
- Around line 265-275: In the "returns partial status when a single version
source lookup fails" test, update the toMatchObject assertion (the response JSON
asserted after calling the route) to explicitly include dockerHubRecentTags: []
so the test verifies an empty array is returned; locate the test by its
description and the mocks (fetchLatestStableGitHubReleaseMock,
fetchDockerHubTagCandidatesMock) and modify the expectation that currently uses
toMatchObject to add the dockerHubRecentTags: [] key/value pair.

In `@src/server/services/updateCenterVersionService.ts`:
- Around line 142-155: The alias check is currently case-sensitive
(isPreferredDockerHubAlias uses normalizeDockerHubTagName but compares against
PREFERRED_DOCKER_HUB_TAG_ALIASES as-is) while other logic lowercases tags
(getRecentNonStableDockerHubPriority), so make alias detection case-insensitive
by normalizing case: update normalizeDockerHubTagName to return the trimmed
lowercase string (or alternatively lowerCase the tag inside
isPreferredDockerHubAlias before comparing), and ensure
isPreferredDockerHubAlias compares the lowercased tag against the lowercased
alias list (or against the existing constants if normalize now lowercases) so
'Latest'/'Main' are treated the same as 'latest'/'main'.

In `@src/web/pages/settings/UpdateCenterSection.test.tsx`:
- Around line 459-501: The test's card locator is too broad and may match an
ancestor; tighten the predicate in UpdateCenterSection.test.tsx (the "deploys
auto-discovered recent non-stable Docker Hub tags without manual input" test) so
it targets the specific tag card element instead of any node with a style object
— for example, look for a node with a dedicated identifier like data-testid or a
class substring (e.g., 'docker-hub-recent-tag-card'), or require the node to be
a container element that also contains the deploy button child (the same element
that yields deployRecentButton) before asserting and clicking; update the find
used to set recentTagCard to this stricter predicate so the subsequent
deployRecentButton click and apiMock assertions remain valid.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 85d1da34-6fd9-42ee-9959-d4eb921e8f33

📥 Commits

Reviewing files that changed from the base of the PR and between 262651a and 93912bb.

📒 Files selected for processing (10)
  • docs/k3s-update-center.md
  • src/server/routes/api/updateCenter.test.ts
  • src/server/services/updateCenterPollingService.test.ts
  • src/server/services/updateCenterRuntimeStateService.test.ts
  • src/server/services/updateCenterRuntimeStateService.ts
  • src/server/services/updateCenterStatusService.ts
  • src/server/services/updateCenterVersionService.test.ts
  • src/server/services/updateCenterVersionService.ts
  • src/web/pages/settings/UpdateCenterSection.test.tsx
  • src/web/pages/settings/UpdateCenterSection.tsx

Comment thread src/web/pages/settings/UpdateCenterSection.tsx Outdated
Comment thread src/web/pages/settings/UpdateCenterSection.tsx
Review feedback pointed out two small but important operator-facing gaps in the
recent-tag card: one-click deploy should only be available when a real raw
Docker tag exists, and the digest that will be deployed should be visible on
the card instead of remaining implicit. This patch tightens the candidate
filter to require tagName and renders the digest metadata before the deploy
actions, with regression coverage for both behaviors.

Constraint: The deploy API still requires a raw Docker tag, not a normalized display value
Constraint: The recent-tag card should surface the exact digest operators are about to deploy
Rejected: Keep accepting normalizedVersion-only candidates | could enable one-click deploy with a non-tag display value
Rejected: Rely on displayVersion alone for digest visibility | digest presence should stay explicit even if display text changes later
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Any future recent-tag UI should treat tagName as the deployable identity and digest as separately visible metadata
Tested: src/web/pages/settings/UpdateCenterSection.test.tsx, npm run typecheck, git diff --check
Not-tested: Full PR checks rerun pending after push
The release branch had fallen behind current main and only conflicted in the
Update Center recent-tag test. Keep the latest main-side deploy-state coverage
while preserving the PR's raw-tag filtering and digest visibility assertions.

Constraint: PR #495 must merge into the current main without widening the PR diff beyond the update-center candidate behavior.
Rejected: Drop the PR-specific digest/raw-tag assertions | would regress the review fixes that prompted the branch update.
Confidence: high
Scope-risk: narrow
Directive: Keep recent Docker tag cards deployable only from real tagName values and keep digest metadata visible before deployment.
Tested: npx vitest run --root . src/web/pages/settings/UpdateCenterSection.test.tsx src/server/services/updateCenterVersionService.test.ts src/server/routes/api/updateCenter.test.ts src/server/services/updateCenterStatusService.test.ts; npm run typecheck; npm run repo:drift-check; git diff --cached --check origin/main
Not-tested: Full npm test.
@chatgpt-codex-connector
Copy link
Copy Markdown

Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits.
Credits must be used to enable repository wide code reviews.

@github-actions github-actions Bot added size: XS Less than 50 lines changed and removed size: L 500 to 999 lines changed labels May 8, 2026
@cita-777 cita-777 merged commit 1d61a7a into main May 8, 2026
18 checks passed
@cita-777 cita-777 deleted the release/feat-update-center-recent-docker-tags-20260418 branch May 8, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: docs Docs and README changes area: server Server-side API and backend changes area: web Web UI changes size: XS Less than 50 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant