Skip to content

Commit 1ade191

Browse files
guguclaude
andcommitted
ci: fetch latest versions at runtime; run weekly or on demand
Replace pinned TIMESCALE_VERSION / TIMESCALE_TOOLKIT_VERSION env vars and the postgres_version / cnpg_version matrix with a runtime resolver: - TimescaleDB + Toolkit: GitHub releases/latest - PostgreSQL (CNPG): ghcr.io tags/list filtered to ^16\.[0-9]+$, sort -V Add schedule (Sun 00:00 UTC) and workflow_dispatch triggers so the image can be rebuilt against upstream without a PR to bump pins. Push is still gated to main; branch pushes remain validation-only. Add CLAUDE.md documenting the resolver, build contract, triggers, and tag scheme. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 4bc0a54 commit 1ade191

2 files changed

Lines changed: 85 additions & 60 deletions

File tree

.github/workflows/build.yaml

Lines changed: 49 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,57 @@
11
name: Build
22

3-
on: push
4-
5-
env:
6-
# renovate datasource=github-releases depName=timescale/timescaledb
7-
TIMESCALE_VERSION: 2.24.0
8-
9-
# renovate datasource=github-releases depName=timescale/timescaledb-toolkit
10-
TIMESCALE_TOOLKIT_VERSION: 1.22.0
3+
on:
4+
push:
5+
schedule:
6+
# Weekly, Sunday 00:00 UTC
7+
- cron: '0 0 * * 0'
8+
workflow_dispatch:
119

1210
jobs:
1311
build:
14-
name: Build Image (pg${{ matrix.postgres_version }})
12+
name: Build Image
1513
runs-on: ubuntu-latest
1614
permissions:
1715
contents: read
1816
packages: write
19-
strategy:
20-
matrix:
21-
include:
22-
- postgres_version: "16.11"
23-
# renovate datasource=docker depName=ghcr.io/cloudnative-pg/postgresql
24-
cnpg_version: 16.11
25-
latest: "true"
2617
steps:
2718
- name: Checkout
2819
uses: actions/checkout@v4
29-
- name: Get CloudNativePG version
30-
id: cnpg
20+
- name: Resolve latest versions
21+
id: versions
3122
env:
32-
VERSION: ${{ matrix.cnpg_version }}
33-
run: |
34-
{
35-
echo "version=$VERSION"
36-
echo "minor=$(cut -d- -f1 <<<"$VERSION")"
37-
echo "major=$(cut -d. -f1 <<<"$VERSION")"
38-
} >> $GITHUB_OUTPUT
39-
- name: Get Timescale version
40-
id: timescale
23+
GH_TOKEN: ${{ github.token }}
4124
run: |
25+
set -euo pipefail
26+
27+
ts=$(curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \
28+
https://api.github.com/repos/timescale/timescaledb/releases/latest \
29+
| jq -r .tag_name | sed 's/^v//')
30+
tk=$(curl -fsSL -H "Authorization: Bearer $GH_TOKEN" \
31+
https://api.github.com/repos/timescale/timescaledb-toolkit/releases/latest \
32+
| jq -r .tag_name | sed 's/^v//')
33+
34+
reg_token=$(curl -fsSL 'https://ghcr.io/token?service=ghcr.io&scope=repository:cloudnative-pg/postgresql:pull' | jq -r .token)
35+
pg=$(curl -fsSL -H "Authorization: Bearer $reg_token" \
36+
'https://ghcr.io/v2/cloudnative-pg/postgresql/tags/list?n=10000' \
37+
| jq -r '.tags[]' | grep -E '^16\.[0-9]+$' | sort -V | tail -1)
38+
4239
{
43-
echo "version=$TIMESCALE_VERSION"
44-
echo "minor=$(cut -d. -f-2 <<<"$TIMESCALE_VERSION")"
45-
echo "major=$(cut -d. -f1 <<<"$TIMESCALE_VERSION")"
46-
} >> $GITHUB_OUTPUT
47-
- name: Get Timescale Toolkit version
48-
id: timescale_toolkit
49-
run: |
40+
echo "timescale=$ts"
41+
echo "timescale_minor=$(echo "$ts" | cut -d. -f-2)"
42+
echo "timescale_major=$(echo "$ts" | cut -d. -f1)"
43+
echo "timescale_toolkit=$tk"
44+
echo "postgres=$pg"
45+
echo "postgres_minor=$(echo "$pg" | cut -d. -f-2)"
46+
echo "postgres_major=$(echo "$pg" | cut -d. -f1)"
47+
} >> "$GITHUB_OUTPUT"
48+
5049
{
51-
echo "version=$TIMESCALE_TOOLKIT_VERSION"
52-
echo "minor=$(cut -d. -f-2 <<<"$TIMESCALE_TOOLKIT_VERSION")"
53-
echo "major=$(cut -d. -f1 <<<"$TIMESCALE_TOOLKIT_VERSION")"
54-
} >> $GITHUB_OUTPUT
50+
echo "## Resolved versions"
51+
echo "- TimescaleDB: \`$ts\`"
52+
echo "- TimescaleDB Toolkit: \`$tk\`"
53+
echo "- PostgreSQL (CNPG): \`$pg\`"
54+
} >> "$GITHUB_STEP_SUMMARY"
5555
- name: Docker meta
5656
id: meta
5757
uses: docker/metadata-action@v5
@@ -60,13 +60,13 @@ jobs:
6060
ghcr.io/${{ github.repository_owner }}/cloudnativepg-timescale
6161
flavor: latest=false
6262
tags: |
63-
type=raw,priority=1000,value=latest,enable=${{ matrix.latest || 'false' }}
64-
type=raw,priority=999,value=${{ steps.cnpg.outputs.version }}-ts${{ steps.timescale.outputs.version }}
65-
type=raw,priority=998,value=${{ steps.cnpg.outputs.minor }}-ts${{ steps.timescale.outputs.minor }}
66-
type=raw,priority=997,value=${{ steps.cnpg.outputs.major }}-ts${{ steps.timescale.outputs.major }}
67-
type=raw,priority=996,value=${{ steps.cnpg.outputs.version }}
68-
type=raw,priority=995,value=${{ steps.cnpg.outputs.minor }}
69-
type=raw,priority=994,value=${{ steps.cnpg.outputs.major }}
63+
type=raw,priority=1000,value=latest
64+
type=raw,priority=999,value=${{ steps.versions.outputs.postgres }}-ts${{ steps.versions.outputs.timescale }}
65+
type=raw,priority=998,value=${{ steps.versions.outputs.postgres_minor }}-ts${{ steps.versions.outputs.timescale_minor }}
66+
type=raw,priority=997,value=${{ steps.versions.outputs.postgres_major }}-ts${{ steps.versions.outputs.timescale_major }}
67+
type=raw,priority=996,value=${{ steps.versions.outputs.postgres }}
68+
type=raw,priority=995,value=${{ steps.versions.outputs.postgres_minor }}
69+
type=raw,priority=994,value=${{ steps.versions.outputs.postgres_major }}
7070
- name: Set up QEMU
7171
uses: docker/setup-qemu-action@v3
7272
- name: Set up Buildx
@@ -87,20 +87,9 @@ jobs:
8787
tags: ${{ steps.meta.outputs.tags }}
8888
labels: ${{ steps.meta.outputs.labels }}
8989
build-args: |
90-
POSTGRES_VERSION=${{ matrix.postgres_version }}
91-
CLOUDNATIVEPG_VERSION=${{ steps.cnpg.outputs.version }}
92-
TIMESCALE_VERSION=${{ steps.timescale.outputs.version }}
93-
TIMESCALE_TOOLKIT_VERSION=${{ steps.timescale_toolkit.outputs.version }}
90+
POSTGRES_VERSION=${{ steps.versions.outputs.postgres }}
91+
CLOUDNATIVEPG_VERSION=${{ steps.versions.outputs.postgres }}
92+
TIMESCALE_VERSION=${{ steps.versions.outputs.timescale }}
93+
TIMESCALE_TOOLKIT_VERSION=${{ steps.versions.outputs.timescale_toolkit }}
9494
cache-from: type=gha
9595
cache-to: type=gha,mode=max
96-
97-
# Summarize matrix https://github.community/t/status-check-for-a-matrix-jobs/127354/7
98-
build-success:
99-
name: Build Successful
100-
runs-on: ubuntu-latest
101-
needs: build
102-
if: ${{ always() }}
103-
steps:
104-
- if: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled') }}
105-
name: Check matrix status
106-
run: exit 1

CLAUDE.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## What this repo is
6+
7+
A Dockerfile + GitHub Actions pipeline that layers TimescaleDB and TimescaleDB Toolkit onto the upstream `ghcr.io/cloudnative-pg/postgresql` image and publishes it to `ghcr.io/clevyr/cloudnativepg-timescale`. There is no application code, no tests, and no local build scripts — the source of truth is the workflow.
8+
9+
## How versions are resolved
10+
11+
Versions are **not pinned** in this repo. The `Resolve latest versions` step in `.github/workflows/build.yaml` fetches them at build time:
12+
13+
- TimescaleDB + Toolkit: GitHub `releases/latest` of `timescale/timescaledb` and `timescale/timescaledb-toolkit` (leading `v` stripped).
14+
- PostgreSQL / CNPG: `ghcr.io/v2/cloudnative-pg/postgresql/tags/list`, filtered to `^16\.[0-9]+$` and `sort -V | tail -1`. Only Postgres 16 is tracked — to add another major, add a parallel filter or matrix, don't change `16` in place.
15+
16+
`POSTGRES_VERSION` and `CLOUDNATIVEPG_VERSION` are fed the **same** resolved value (the CNPG tag like `16.11`). The Dockerfile uses `$POSTGRES_VERSION` inside the Timescale apt package name, so this relies on Timescale's Debian repo accepting the full `major.minor` (or on apt's loose matching for the major). If a scheduled build starts failing on `apt-get install` of `timescaledb-2-postgresql-<ver>`, verify the packagecloud triplet first — upstream may not have published yet for a brand-new CNPG minor.
17+
18+
Renovate (`renovate.json`) no longer drives these versions; its regex managers now match nothing in `build.yaml` but are left in place for future use. Don't reintroduce the old Renovate comment pragmas — they'd fight the runtime resolver.
19+
20+
## Build cadence and triggers
21+
22+
`build.yaml` runs on `push`, on `workflow_dispatch` (manual), and weekly via `schedule: '0 0 * * 0'` (Sun 00:00 UTC). Only runs on `main` actually push images (`push: ${{ github.ref_name == 'main' }}`); branch pushes are validation-only. Because versions resolve at runtime, two runs minutes apart can produce different images if upstream cut a release in between — that's intentional.
23+
24+
## Build contract
25+
26+
`Dockerfile` consumes four build args: `CLOUDNATIVEPG_VERSION`, `POSTGRES_VERSION`, `TIMESCALE_VERSION`, `TIMESCALE_TOOLKIT_VERSION`. It installs `timescaledb-2-postgresql-$POSTGRES_VERSION=$TIMESCALE_VERSION~debian$VERSION_ID` and the Toolkit as `=1:$TIMESCALE_TOOLKIT_VERSION~debian$VERSION_ID`, so upstream has to have published a matching `~debianNN` package before a build will succeed.
27+
28+
The image ends with `USER 26` (the `postgres` user id CNPG expects). Do not add layers after that as root without resetting the user.
29+
30+
## Tag scheme
31+
32+
`docker/metadata-action` emits seven tags per build, in priority order: `latest`, `<pg>-ts<ts>` (full), `<pg-minor>-ts<ts-minor>`, `<pg-major>-ts<ts-major>`, then the same three without the `-ts…` suffix. The README example `16-ts2` is the major/major form. Toolkit version does not appear in any tag.
33+
34+
## Local iteration
35+
36+
`docker build --build-arg ...` against the four args above; no scheduled/remote infra needed. Branches are safe to experiment on — pushes are gated to `main`.

0 commit comments

Comments
 (0)