diff --git a/CHANGELOG.md b/CHANGELOG.md index 396727384..ccc7a675f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.6.0-rc.2] — 2026-07-18 + ### Added - **"Version update" container filter** ([#538](https://github.com/CodesWhat/drydock/issues/538)). The Containers filter bar gains a **Version Update** kind option that shows only real semver upgrades (major, minor, patch) and hides digest-only churn — the noise that dominates the dashboard on fleets that rebuild images daily in CI. Like every other container filter, it round-trips through the URL (`?filterKind=version`), so the filtered view can be saved as a bookmark for one-click access. @@ -2155,7 +2157,8 @@ Remaining upstream-only changes (not ported — not applicable to drydock): | Fix codeberg tests | Covered by drydock's own tests | | Update changelog | Upstream-specific | -[Unreleased]: https://github.com/CodesWhat/drydock/compare/v1.6.0-rc.1...HEAD +[Unreleased]: https://github.com/CodesWhat/drydock/compare/v1.6.0-rc.2...HEAD +[1.6.0-rc.2]: https://github.com/CodesWhat/drydock/compare/v1.6.0-rc.1...v1.6.0-rc.2 [1.6.0-rc.1]: https://github.com/CodesWhat/drydock/compare/v1.5.2...v1.6.0-rc.1 [1.5.2]: https://github.com/CodesWhat/drydock/compare/v1.5.2-rc.5...v1.5.2 [1.5.2-rc.5]: https://github.com/CodesWhat/drydock/compare/v1.5.2-rc.4...v1.5.2-rc.5 diff --git a/README.md b/README.md index 7ff7ef918..9f6a265b3 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@

- Version + Version Multi-arch License AGPL-3.0
@@ -171,7 +171,7 @@ See the [Quick Start guide](https://getdrydock.com/docs/quickstart) for Docker C

🆕 Recent Updates

-v1.6.0-rc.1 highlights +v1.6.0-rc.2 highlights - **Notifications** — Per-rule/per-provider title and body templates with live preview, plus audit-backed in-app bell categories and update severity thresholds. - **Dashboard** — Zero-dependency CSS Grid replacement with mouse/touch reorder, bounded resize, responsive layouts, widget visibility, reset, and optional cross-device preference sync. diff --git a/apps/demo/src/mocks/data/agents.ts b/apps/demo/src/mocks/data/agents.ts index 08dc96d5c..f2b60f218 100644 --- a/apps/demo/src/mocks/data/agents.ts +++ b/apps/demo/src/mocks/data/agents.ts @@ -4,7 +4,7 @@ export const agents = [ host: '192.168.1.50', port: 3001, connected: true, - version: '1.6.0-rc.1', + version: '1.6.0-rc.2', os: 'linux', arch: 'amd64', cpus: 4, diff --git a/apps/demo/src/mocks/data/audit.ts b/apps/demo/src/mocks/data/audit.ts index 2ecd513c3..c69337686 100644 --- a/apps/demo/src/mocks/data/audit.ts +++ b/apps/demo/src/mocks/data/audit.ts @@ -3,7 +3,7 @@ export const auditEntries = [ id: 'aud-001', timestamp: '2026-03-10T08:00:00.000Z', action: 'system:start', - details: 'Drydock v1.6.0-rc.1 started', + details: 'Drydock v1.6.0-rc.2 started', }, { id: 'aud-002', @@ -207,6 +207,6 @@ export const auditEntries = [ timestamp: '2026-03-03T18:00:00.000Z', action: 'container:watch', container: 'drydock', - details: 'Started watching ghcr.io/codeswhat/drydock:1.6.0-rc.1', + details: 'Started watching ghcr.io/codeswhat/drydock:1.6.0-rc.2', }, ]; diff --git a/apps/demo/src/mocks/data/containers.ts b/apps/demo/src/mocks/data/containers.ts index 231e31176..da777b2d6 100644 --- a/apps/demo/src/mocks/data/containers.ts +++ b/apps/demo/src/mocks/data/containers.ts @@ -330,7 +330,7 @@ export const containers = [ displayName: 'Drydock', displayIcon: 'sh-drydock', image: 'codeswhat/drydock', - tag: '1.6.0-rc.1', + tag: '1.6.0-rc.2', registryType: 'ghcr', registryUrl: 'https://ghcr.io', scanStatus: 'scanned', diff --git a/apps/demo/src/mocks/data/server.ts b/apps/demo/src/mocks/data/server.ts index df70b4564..a70aaf44d 100644 --- a/apps/demo/src/mocks/data/server.ts +++ b/apps/demo/src/mocks/data/server.ts @@ -1,5 +1,5 @@ export const serverInfo = { - version: '1.6.0-rc.1', + version: '1.6.0-rc.2', uptime: 864000, hostname: 'drydock-demo', platform: 'linux', diff --git a/apps/demo/src/mocks/handlers/app.ts b/apps/demo/src/mocks/handlers/app.ts index 8e9a0b1d8..692386b09 100644 --- a/apps/demo/src/mocks/handlers/app.ts +++ b/apps/demo/src/mocks/handlers/app.ts @@ -4,7 +4,7 @@ export const appHandlers = [ http.get('/api/v1/app', () => HttpResponse.json({ name: 'Drydock', - version: '1.6.0-rc.1', + version: '1.6.0-rc.2', description: 'Docker container update manager', repository: 'https://github.com/CodesWhat/drydock', documentation: 'https://getdrydock.com/docs', @@ -16,7 +16,7 @@ export const appHandlers = [ return HttpResponse.json( { generatedAt: new Date().toISOString(), - server: { version: '1.6.0-rc.1', mode: 'demo' }, + server: { version: '1.6.0-rc.2', mode: 'demo' }, summary: { containers: 25, watchers: 2, diff --git a/apps/web/src/lib/site-config.ts b/apps/web/src/lib/site-config.ts index f0ec455f3..a00d1ab08 100644 --- a/apps/web/src/lib/site-config.ts +++ b/apps/web/src/lib/site-config.ts @@ -15,7 +15,7 @@ export const SITE_CONFIG = { /** Brand name shown in the header, footer, and metadata. */ name: "Drydock", /** Current release version shown in the hero badge. */ - version: "1.6.0-rc.1", + version: "1.6.0-rc.2", /** Short product tagline used in page titles and OG metadata. */ tagline: "Container Update Monitoring", /** Default meta / OpenGraph / Twitter description. */ diff --git a/apps/web/src/lib/site-content.ts b/apps/web/src/lib/site-content.ts index 9fbf4b0ff..e9d82e249 100644 --- a/apps/web/src/lib/site-content.ts +++ b/apps/web/src/lib/site-content.ts @@ -281,7 +281,7 @@ export const roadmap: Milestone[] = [ ], }, { - version: "v1.6.0-rc.1", + version: "v1.6.0-rc.2", title: "Notifications, Policy & Release Intel", emoji: "\u{1F4E8}", status: "next", diff --git a/content/docs/current/api/agent.mdx b/content/docs/current/api/agent.mdx index 3776eb16f..54743a937 100644 --- a/content/docs/current/api/agent.mdx +++ b/content/docs/current/api/agent.mdx @@ -23,7 +23,7 @@ curl http://drydock:3000/api/v1/agents "host": "192.168.1.50", "port": 3000, "connected": true, - "version": "1.6.0-rc.1", + "version": "1.6.0-rc.2", "os": "linux", "arch": "amd64", "cpus": 4, @@ -153,7 +153,7 @@ Sent immediately upon connection to confirm the handshake. { "type": "dd:ack", "data": { - "version": "1.6.0-rc.1", + "version": "1.6.0-rc.2", "os": "linux", "arch": "amd64", "cpus": 4, diff --git a/content/docs/current/api/app.mdx b/content/docs/current/api/app.mdx index 6849cfa91..91b780bf4 100644 --- a/content/docs/current/api/app.mdx +++ b/content/docs/current/api/app.mdx @@ -12,7 +12,7 @@ curl http://drydock:3000/api/v1/app { "name":"drydock", - "version":"1.6.0-rc.1" + "version":"1.6.0-rc.2" } ``` diff --git a/content/docs/current/api/portwing.mdx b/content/docs/current/api/portwing.mdx index 7d8e16562..b1ac969cd 100644 --- a/content/docs/current/api/portwing.mdx +++ b/content/docs/current/api/portwing.mdx @@ -162,7 +162,7 @@ A versioned alias `/api/v1/portwing/ws` is also accepted and is signature-equiva "agentId": "edge-host-01", "agentName": "edge-host-01", "protocol": "portwing/1.0", - "version": "1.6.0-rc.1", + "version": "1.6.0-rc.2", "pubKeyId": "3f8a1c2e9b047d56", "timestamp": 1780329600, "nonce": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4", @@ -185,7 +185,7 @@ A name collision with an already-connected agent under the same key (or the in-f "data": { "pollInterval": 300, "config": { - "drydockVersion": "1.6.0-rc.1", + "drydockVersion": "1.6.0-rc.2", "supportedProtocols": "portwing/1.0", "serverCompatLevel": "1.4.0" } diff --git a/content/docs/current/quickstart/index.mdx b/content/docs/current/quickstart/index.mdx index cd4fbcaab..72ff99fa8 100644 --- a/content/docs/current/quickstart/index.mdx +++ b/content/docs/current/quickstart/index.mdx @@ -102,7 +102,7 @@ Release tags use the same channel names in every registry: | Tag | Behavior | | --- | --- | -| `1.6.0-rc.1` | Immutable release candidate; best for reproducible testing | +| `1.6.0-rc.2` | Immutable release candidate; best for reproducible testing | | `1.6-rc` | Rolling release-candidate channel; moves to the newest `1.6.0-rc.N` | | `1.6` | Rolling stable minor channel; published only for GA releases | | `1` | Rolling stable major channel; published only for GA releases | diff --git a/content/docs/current/updates/index.mdx b/content/docs/current/updates/index.mdx index 7e714c8bf..417a71db1 100644 --- a/content/docs/current/updates/index.mdx +++ b/content/docs/current/updates/index.mdx @@ -3,6 +3,12 @@ title: "Updates" description: "Release update notes and feature highlights, with direct links to current configuration and API docs." --- +## v1.6.0-rc.2 Highlights — July 18, 2026 + +- **Watch errors no longer erase update state** — a container whose registry check fails keeps its last successful comparison alongside the recorded error instead of appearing never-compared, errored containers reuse the same fast refresh path as healthy ones, and repair rebuilds preserve the registry-reconciled digest that keys security scan grouping. +- **"Version Update" container filter** — a new filter kind shows only real semver upgrades (major/minor/patch) and hides digest-only churn; bookmarkable via `?filterKind=version`. +- **Docs aligned with shipped behavior** — FAQ and README corrections (registry list, scanner parity, runnable `config migrate` commands), the removed `WS /api/log/stream` alias documented in Deprecations, and the quickstart registry/tag matrix refreshed. + ## v1.6.0-rc.1 Highlights — July 15, 2026 - **Notification rules are now a complete control surface** — configure delivery routing, audit-backed in-app bell categories, update severity threshold, and per-provider simple/batch templates in one detail panel; preview drafts before saving. Container-unhealthy events are bell-capable, and agent status changes refresh the bell promptly. diff --git a/scripts/changelog-links.test.mjs b/scripts/changelog-links.test.mjs index aa6603930..24c0c31cd 100644 --- a/scripts/changelog-links.test.mjs +++ b/scripts/changelog-links.test.mjs @@ -56,7 +56,8 @@ test('every linked changelog heading has exactly one link definition', () => { test('v1.6 RC and v1.5.2 GA have a complete chronological comparison-link chain', () => { const definitions = new Map(getLinkDefinitions(changelog).map(({ label, url }) => [label, url])); const expected = new Map([ - ['Unreleased', `${repositoryUrl}/compare/v1.6.0-rc.1...HEAD`], + ['Unreleased', `${repositoryUrl}/compare/v1.6.0-rc.2...HEAD`], + ['1.6.0-rc.2', `${repositoryUrl}/compare/v1.6.0-rc.1...v1.6.0-rc.2`], ['1.6.0-rc.1', `${repositoryUrl}/compare/v1.5.2...v1.6.0-rc.1`], ['1.5.2', `${repositoryUrl}/compare/v1.5.2-rc.5...v1.5.2`], ['1.5.2-rc.5', `${repositoryUrl}/compare/v1.5.2-rc.4...v1.5.2-rc.5`], diff --git a/scripts/release-docs-identity.test.mjs b/scripts/release-docs-identity.test.mjs index 419d5441c..a3993a04b 100644 --- a/scripts/release-docs-identity.test.mjs +++ b/scripts/release-docs-identity.test.mjs @@ -2,9 +2,9 @@ import assert from 'node:assert/strict'; import { readdirSync, readFileSync } from 'node:fs'; import test from 'node:test'; -const RC_VERSION = '1.6.0-rc.1'; -const RC_DATE = '2026-07-15'; -const RC_DISPLAY_DATE = 'July 15, 2026'; +const RC_VERSION = '1.6.0-rc.2'; +const RC_DATE = '2026-07-18'; +const RC_DISPLAY_DATE = 'July 18, 2026'; const DOC_ROOTS = ['content/docs/current', 'content/docs/v1.5']; function read(path) { @@ -21,16 +21,16 @@ test('public release surfaces identify the v1.6 release candidate', () => { const quickstart = read('content/docs/current/quickstart/index.mdx'); const changelog = read('CHANGELOG.md'); - assert.match(readme, /version-1\.6\.0--rc\.1-blue/u); - assert.match(readme, /v1\.6\.0-rc\.1 highlights/u); + assert.match(readme, /version-1\.6\.0--rc\.2-blue/u); + assert.match(readme, /v1\.6\.0-rc\.2 highlights/u); assert.match(siteConfig, new RegExp(`version: "${RC_VERSION.replaceAll('.', '\\.')}"`, 'u')); assert.ok(updates.includes(`## v${RC_VERSION} Highlights — ${RC_DISPLAY_DATE}`)); - assert.match(appApi, /"version":"1\.6\.0-rc\.1"/u); - assert.match(agentApi, /"version": "1\.6\.0-rc\.1"/u); - assert.match(portwingApi, /"version": "1\.6\.0-rc\.1"/u); - assert.match(portwingApi, /"drydockVersion": "1\.6\.0-rc\.1"/u); - assert.match(quickstart, /\| `1\.6\.0-rc\.1` \| Immutable release candidate/u); - assert.doesNotMatch(quickstart, /\| `1\.6\.0-rc\.(?!1\b)\d+` \| Immutable release candidate/u); + assert.match(appApi, /"version":"1\.6\.0-rc\.2"/u); + assert.match(agentApi, /"version": "1\.6\.0-rc\.2"/u); + assert.match(portwingApi, /"version": "1\.6\.0-rc\.2"/u); + assert.match(portwingApi, /"drydockVersion": "1\.6\.0-rc\.2"/u); + assert.match(quickstart, /\| `1\.6\.0-rc\.2` \| Immutable release candidate/u); + assert.doesNotMatch(quickstart, /\| `1\.6\.0-rc\.(?!2\b)\d+` \| Immutable release candidate/u); assert.ok(changelog.includes(`## [${RC_VERSION}] — ${RC_DATE}`)); assert.ok( changelog.includes( @@ -39,7 +39,7 @@ test('public release surfaces identify the v1.6 release candidate', () => { ); assert.ok( changelog.includes( - `[${RC_VERSION}]: https://github.com/CodesWhat/drydock/compare/v1.5.2...v${RC_VERSION}`, + `[${RC_VERSION}]: https://github.com/CodesWhat/drydock/compare/v1.6.0-rc.1...v${RC_VERSION}`, ), ); }); @@ -53,7 +53,7 @@ test('v1.5.2 is archived and public release routing advances to v1.6', () => { assert.match(readme, /v1\.5\.2 highlights<\/strong><\/summary>/u); assert.match(siteContent, /version: "v1\.5\.2",[\s\S]{0,500}?status: "released"/u); - assert.match(siteContent, /version: "v1\.6\.0-rc\.1",[\s\S]{0,500}?status: "next"/u); + assert.match(siteContent, /version: "v1\.6\.0-rc\.2",[\s\S]{0,500}?status: "next"/u); assert.match( docsVersions, /\{ slug: "v1\.6", source: "current", title: "v1\.6" \},\s+\{ slug: "v1\.5", source: "v1\.5", title: "v1\.5" \}/u, diff --git a/scripts/release-identity.test.mjs b/scripts/release-identity.test.mjs index f1f59f33d..70e08f767 100644 --- a/scripts/release-identity.test.mjs +++ b/scripts/release-identity.test.mjs @@ -3,7 +3,7 @@ import { readFileSync } from 'node:fs'; import test from 'node:test'; const BASE_VERSION = '1.6.0'; -const RC_VERSION = '1.6.0-rc.1'; +const RC_VERSION = '1.6.0-rc.2'; const DEMO_RELEASE_FIXTURES = [ { path: 'apps/demo/src/mocks/data/server.ts', @@ -52,7 +52,7 @@ test('release-gated workspace packages and locks use the v1.6 base version', () } }); -test('demo runtime fixtures identify the exact v1.6.0-rc.1 candidate', () => { +test('demo runtime fixtures identify the exact v1.6.0-rc.2 candidate', () => { for (const { path, valuePattern } of DEMO_RELEASE_FIXTURES) { const contents = readFileSync(path, 'utf8'); assert.deepEqual(extractVersionValues(contents, valuePattern), [RC_VERSION], path); @@ -63,18 +63,18 @@ test('release version patterns match exact optionally v-prefixed tokens', () => const rcPattern = versionPattern(RC_VERSION); const legacyPattern = versionPattern('1.5.0'); - assert.match('version: 1.6.0-rc.1', rcPattern); - assert.match('version: v1.6.0-rc.1', rcPattern); - assert.doesNotMatch('version: 1.6.0-rc.10', rcPattern); - assert.doesNotMatch('version: x1.6.0-rc.1', rcPattern); + assert.match('version: 1.6.0-rc.2', rcPattern); + assert.match('version: v1.6.0-rc.2', rcPattern); + assert.doesNotMatch('version: 1.6.0-rc.20', rcPattern); + assert.doesNotMatch('version: x1.6.0-rc.2', rcPattern); assert.match('version: v1.5.0', legacyPattern); assert.doesNotMatch('version: 1.5.0-rc.1', legacyPattern); }); test('fixture version extraction retains mixed candidate identities', () => { - const contents = "version: '1.6.0-rc.1', version: '1.6.0-rc.10'"; + const contents = "version: '1.6.0-rc.2', version: '1.6.0-rc.20'"; assert.deepEqual(extractVersionValues(contents, /version:\s*["']([^"']+)["']/gu), [ - '1.6.0-rc.1', - '1.6.0-rc.10', + '1.6.0-rc.2', + '1.6.0-rc.20', ]); });