Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
</div>

<p align="center">
<a href="https://github.com/CodesWhat/drydock/releases"><img src="https://img.shields.io/badge/version-1.6.0--rc.1-blue" alt="Version"></a>
<a href="https://github.com/CodesWhat/drydock/releases"><img src="https://img.shields.io/badge/version-1.6.0--rc.2-blue" alt="Version"></a>
<a href="https://github.com/orgs/CodesWhat/packages/container/package/drydock"><img src="https://img.shields.io/badge/platforms-amd64%20%7C%20arm64-informational?logo=linux&logoColor=white" alt="Multi-arch"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-AGPL--3.0-C9A227" alt="License AGPL-3.0"></a>
<br>
Expand Down Expand Up @@ -171,7 +171,7 @@ See the [Quick Start guide](https://getdrydock.com/docs/quickstart) for Docker C
<h2 align="center" id="recent-updates">πŸ†• Recent Updates</h2>

<details open>
<summary><strong>v1.6.0-rc.1 highlights</strong></summary>
<summary><strong>v1.6.0-rc.2 highlights</strong></summary>

- **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.
Expand Down
2 changes: 1 addition & 1 deletion apps/demo/src/mocks/data/agents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions apps/demo/src/mocks/data/audit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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',
},
];
2 changes: 1 addition & 1 deletion apps/demo/src/mocks/data/containers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down
2 changes: 1 addition & 1 deletion apps/demo/src/mocks/data/server.ts
Original file line number Diff line number Diff line change
@@ -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',
Expand Down
4 changes: 2 additions & 2 deletions apps/demo/src/mocks/handlers/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/lib/site-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/lib/site-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions content/docs/current/api/agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion content/docs/current/api/app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
```

Expand Down
4 changes: 2 additions & 2 deletions content/docs/current/api/portwing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
}
Expand Down
2 changes: 1 addition & 1 deletion content/docs/current/quickstart/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down
6 changes: 6 additions & 0 deletions content/docs/current/updates/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## 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.
Expand Down
3 changes: 2 additions & 1 deletion scripts/changelog-links.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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`],
Expand Down
26 changes: 13 additions & 13 deletions scripts/release-docs-identity.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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(
Expand All @@ -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}`,
),
);
});
Expand All @@ -53,7 +53,7 @@ test('v1.5.2 is archived and public release routing advances to v1.6', () => {

assert.match(readme, /<summary><strong>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,
Expand Down
18 changes: 9 additions & 9 deletions scripts/release-identity.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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);
Expand All @@ -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',
]);
});