chore(ci): publish latest from main and retire the edge tag (#711)
* fix(docs): update versioning strategy and tag policies for Docker images * fix(docs): clarify versioning strategy in environment configuration fix(docker): update docker-push script to remove local latest tag handling * fix(docs): clarify VERSION variable usage in Docker push script
This commit is contained in:
+4
-2
@@ -7,8 +7,10 @@
|
|||||||
# Image version (only used by docker-compose.images.yaml — the pull-based stack)
|
# Image version (only used by docker-compose.images.yaml — the pull-based stack)
|
||||||
# ──────────────────────────────────────────────
|
# ──────────────────────────────────────────────
|
||||||
# Which published image tag to pull for api/dashboard/jobs.
|
# Which published image tag to pull for api/dashboard/jobs.
|
||||||
# - Pin to a release (e.g. 1.4.2) in production so a new release never auto-breaks you.
|
# - "latest" (below) = freshest main build; it MOVES on every merge to main (rolling, may
|
||||||
# - "latest" = newest stable release. "edge" = bleeding edge (last main build).
|
# include unreleased code), so a later `pull` can shift you to a newer build unannounced.
|
||||||
|
# - For production, PIN an exact release (e.g. 1.4.2) so a merge to main never auto-breaks you.
|
||||||
|
# "1.4.2" / "1.4" / "1" are immutable, published on a v* git tag.
|
||||||
# Rollback = set this back to the previous version, then `... pull && up -d`.
|
# Rollback = set this back to the previous version, then `... pull && up -d`.
|
||||||
CIO_VERSION=latest
|
CIO_VERSION=latest
|
||||||
|
|
||||||
|
|||||||
@@ -124,15 +124,14 @@ jobs:
|
|||||||
uses: docker/metadata-action@v5
|
uses: docker/metadata-action@v5
|
||||||
with:
|
with:
|
||||||
images: ${{ env.DOCKERHUB_USERNAME }}/${{ matrix.image }}
|
images: ${{ env.DOCKERHUB_USERNAME }}/${{ matrix.image }}
|
||||||
# Tag policy (stable-releases + edge):
|
# Tag policy:
|
||||||
# git tag v1.4.2 -> 1.4.2, 1.4, 1, latest (a real, stable release)
|
# push to main -> latest (freshest main build; moves on every merge)
|
||||||
# push to main -> edge only (latest is NEVER moved by a merge)
|
# git tag v1.4.2 -> 1.4.2, 1.4, 1 (immutable, pinned release)
|
||||||
tags: |
|
tags: |
|
||||||
type=semver,pattern={{version}}
|
type=semver,pattern={{version}}
|
||||||
type=semver,pattern={{major}}.{{minor}}
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
type=semver,pattern={{major}}
|
type=semver,pattern={{major}}
|
||||||
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/') }}
|
type=raw,value=latest,enable={{is_default_branch}}
|
||||||
type=raw,value=edge,enable={{is_default_branch}}
|
|
||||||
|
|
||||||
- name: Build and push ${{ matrix.name }}
|
- name: Build and push ${{ matrix.name }}
|
||||||
uses: docker/build-push-action@v5
|
uses: docker/build-push-action@v5
|
||||||
|
|||||||
@@ -112,8 +112,8 @@ The script builds and starts Postgres, Redis, MinIO (object storage), the API, t
|
|||||||
|
|
||||||
ClassroomIO publishes versioned images. `CIO_VERSION` controls which tag you run:
|
ClassroomIO publishes versioned images. `CIO_VERSION` controls which tag you run:
|
||||||
|
|
||||||
- Pin an exact release (e.g. `1.4.2`) in production so a new release never restarts you onto changed images unattended.
|
- Pin an exact release (e.g. `1.4.2`) in production so a merge to `main` never restarts you onto changed images unattended.
|
||||||
- `latest` = newest stable release. `edge` = bleeding edge (last `main` build).
|
- `latest` = the freshest `main` build — it moves on every merge (rolling; may include unreleased code). Version tags (`1.4.2`, `1.4`, `1`) are the immutable, pinned releases.
|
||||||
|
|
||||||
**Pre-built images path** — bump `CIO_VERSION` in `.env`, then re-pull and recreate:
|
**Pre-built images path** — bump `CIO_VERSION` in `.env`, then re-pull and recreate:
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
# CIO_VERSION=1.4.2 docker compose -f docker-compose.images.yaml --env-file .env up -d
|
# CIO_VERSION=1.4.2 docker compose -f docker-compose.images.yaml --env-file .env up -d
|
||||||
#
|
#
|
||||||
# CIO_VERSION pins the release. Use a specific version (e.g. 1.4.2) in production;
|
# CIO_VERSION pins the release. Use a specific version (e.g. 1.4.2) in production;
|
||||||
# "latest" = newest stable release, "edge" = bleeding edge (last main build).
|
# "latest" = freshest main build (moves on every merge — rolling, may include unreleased code).
|
||||||
#
|
#
|
||||||
# KEEP IN SYNC with docker-compose.yaml: the api/dashboard/jobs `environment`,
|
# KEEP IN SYNC with docker-compose.yaml: the api/dashboard/jobs `environment`,
|
||||||
# healthchecks, depends_on, and volumes must match the build-based file. The only
|
# healthchecks, depends_on, and volumes must match the build-based file. The only
|
||||||
|
|||||||
+4
-10
@@ -8,16 +8,13 @@ set -e # Exit on error
|
|||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
DOCKERHUB_USERNAME="${DOCKERHUB_USERNAME:-classroomio}" # Change this to your Docker Hub username
|
DOCKERHUB_USERNAME="${DOCKERHUB_USERNAME:-classroomio}" # Change this to your Docker Hub username
|
||||||
VERSION="${VERSION:-latest}" # Can be overridden with VERSION env var
|
VERSION="${VERSION:?set VERSION to the tag to publish, e.g. VERSION=1.4.2 — this script never pushes :latest (CI owns latest from main)}"
|
||||||
PUBLIC_IS_SELFHOSTED="${PUBLIC_IS_SELFHOSTED:-true}"
|
PUBLIC_IS_SELFHOSTED="${PUBLIC_IS_SELFHOSTED:-true}"
|
||||||
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
|
PLATFORMS="${PLATFORMS:-linux/amd64,linux/arm64}"
|
||||||
|
|
||||||
# Only a real semver release should also move the `latest` tag — building edge/main/dev
|
# This manual/local helper pushes ONLY the explicit ${VERSION} tag. `latest` is published
|
||||||
# must NOT clobber the stable `latest` pointer (mirrors docker-publish.yml's tag policy).
|
# exclusively by CI from `main` (see .github/workflows/docker-publish.yml) — to move `latest`,
|
||||||
# Use `if` (not `&&`) so the function always returns 0 even when it emits no tag — a helper
|
# merge to main or re-run that workflow, never this script.
|
||||||
# returning non-zero inside a $(...) argument is fragile under `set -e` / inherit_errexit.
|
|
||||||
is_release_version() { [[ "${VERSION}" =~ ^v?[0-9]+\.[0-9]+\.[0-9]+$ ]]; }
|
|
||||||
latest_arg() { if is_release_version; then printf -- '-t %s:latest' "$1"; fi; }
|
|
||||||
|
|
||||||
# Colors for output
|
# Colors for output
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
@@ -46,7 +43,6 @@ docker buildx build \
|
|||||||
--platform "${PLATFORMS}" \
|
--platform "${PLATFORMS}" \
|
||||||
-f docker/Dockerfile.api \
|
-f docker/Dockerfile.api \
|
||||||
-t ${DOCKERHUB_USERNAME}/api:${VERSION} \
|
-t ${DOCKERHUB_USERNAME}/api:${VERSION} \
|
||||||
$(latest_arg ${DOCKERHUB_USERNAME}/api) \
|
|
||||||
--push \
|
--push \
|
||||||
.
|
.
|
||||||
echo -e "${GREEN}✓ API image published successfully!${NC}"
|
echo -e "${GREEN}✓ API image published successfully!${NC}"
|
||||||
@@ -60,7 +56,6 @@ docker buildx build \
|
|||||||
-f docker/Dockerfile.dashboard \
|
-f docker/Dockerfile.dashboard \
|
||||||
--build-arg PUBLIC_IS_SELFHOSTED=${PUBLIC_IS_SELFHOSTED} \
|
--build-arg PUBLIC_IS_SELFHOSTED=${PUBLIC_IS_SELFHOSTED} \
|
||||||
-t ${DOCKERHUB_USERNAME}/dashboard:${VERSION} \
|
-t ${DOCKERHUB_USERNAME}/dashboard:${VERSION} \
|
||||||
$(latest_arg ${DOCKERHUB_USERNAME}/dashboard) \
|
|
||||||
--push \
|
--push \
|
||||||
.
|
.
|
||||||
echo -e "${GREEN}✓ Dashboard image published successfully!${NC}"
|
echo -e "${GREEN}✓ Dashboard image published successfully!${NC}"
|
||||||
@@ -72,7 +67,6 @@ docker buildx build \
|
|||||||
--platform "${PLATFORMS}" \
|
--platform "${PLATFORMS}" \
|
||||||
-f docker/Dockerfile.jobs \
|
-f docker/Dockerfile.jobs \
|
||||||
-t ${DOCKERHUB_USERNAME}/jobs:${VERSION} \
|
-t ${DOCKERHUB_USERNAME}/jobs:${VERSION} \
|
||||||
$(latest_arg ${DOCKERHUB_USERNAME}/jobs) \
|
|
||||||
--push \
|
--push \
|
||||||
.
|
.
|
||||||
echo -e "${GREEN}✓ Jobs image published successfully!${NC}"
|
echo -e "${GREEN}✓ Jobs image published successfully!${NC}"
|
||||||
|
|||||||
@@ -57,8 +57,8 @@ Check your Docker Hub repository at:
|
|||||||
|
|
||||||
The workflow will automatically publish images when:
|
The workflow will automatically publish images when:
|
||||||
|
|
||||||
1. **Push to `main`**: Publishes the **`edge`** tag only (does NOT move `latest`).
|
1. **Push to `main`**: Publishes the **`latest`** tag (the freshest `main` build).
|
||||||
2. **Push a version tag `vX.Y.Z`**: Publishes `X.Y.Z`, `X.Y`, `X`, and `latest`.
|
2. **Push a version tag `vX.Y.Z`**: Publishes `X.Y.Z`, `X.Y`, `X` (immutable, pinned releases).
|
||||||
3. **Manual trigger**: Use the Actions tab in GitHub.
|
3. **Manual trigger**: Use the Actions tab in GitHub.
|
||||||
|
|
||||||
Every build is **boot smoke-tested** (started against ephemeral postgres + redis, healthcheck
|
Every build is **boot smoke-tested** (started against ephemeral postgres + redis, healthcheck
|
||||||
@@ -107,7 +107,7 @@ docker pull classroomio/dashboard:latest
|
|||||||
|
|
||||||
For self-hosting with Docker Compose, see [SELF_HOST.md](SELF_HOST.md). The setup uses a single root `.env` file and `docker-compose.yaml`.
|
For self-hosting with Docker Compose, see [SELF_HOST.md](SELF_HOST.md). The setup uses a single root `.env` file and `docker-compose.yaml`.
|
||||||
|
|
||||||
## Versioning Strategy (stable-releases + edge)
|
## Versioning Strategy (rolling `latest` + pinned releases)
|
||||||
|
|
||||||
The published tags and what they mean:
|
The published tags and what they mean:
|
||||||
|
|
||||||
@@ -115,17 +115,15 @@ The published tags and what they mean:
|
|||||||
|-----|--------------|---------|
|
|-----|--------------|---------|
|
||||||
| `1.4.2` (exact) | a `v1.4.2` git tag | Immutable, smoke-tested release — **what production should pin** |
|
| `1.4.2` (exact) | a `v1.4.2` git tag | Immutable, smoke-tested release — **what production should pin** |
|
||||||
| `1.4`, `1` | a `v1.4.2` git tag | Latest patch/minor of that line |
|
| `1.4`, `1` | a `v1.4.2` git tag | Latest patch/minor of that line |
|
||||||
| `latest` | a `v*` git tag only | The newest *released* version |
|
| `latest` | every push to `main` | The freshest `main` build (rolling; may include unreleased code) |
|
||||||
| `edge` | every push to `main` | Bleeding edge; may be unstable |
|
|
||||||
|
|
||||||
The key rule: **`latest` is never moved by a routine merge to `main`** — only a deliberate release
|
The key rule: **`latest` moves on every merge to `main`**, so it can change under you. Self-hosters
|
||||||
tag moves it. Self-hosters pin `CIO_VERSION` (see [SELF_HOST.md](SELF_HOST.md)) and upgrade on their
|
pin `CIO_VERSION` (see [SELF_HOST.md](SELF_HOST.md)) and upgrade on their own schedule.
|
||||||
own schedule.
|
|
||||||
|
|
||||||
### Cutting a release
|
### Cutting a release
|
||||||
|
|
||||||
Versioning is driven by git tags; the CI workflow does the rest (build multi-arch → smoke-test →
|
Versioning is driven by git tags; the CI workflow does the rest (build multi-arch → smoke-test →
|
||||||
push `X.Y.Z`/`X.Y`/`X`/`latest`).
|
push `X.Y.Z`/`X.Y`/`X`). `latest` is published separately, on every merge to `main`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Bump version + create the vX.Y.Z tag from the repo's changelog tooling
|
# Bump version + create the vX.Y.Z tag from the repo's changelog tooling
|
||||||
|
|||||||
@@ -44,18 +44,16 @@ From a full clone you can also use the helper: `./run-docker-full-stack.sh --ima
|
|||||||
|
|
||||||
## Versioning & Upgrades
|
## Versioning & Upgrades
|
||||||
|
|
||||||
Published images use a **stable-releases + edge** tag policy:
|
Published images use a **rolling `latest` + pinned releases** tag policy:
|
||||||
|
|
||||||
| Tag | Meaning | Use it for |
|
| Tag | Meaning | Use it for |
|
||||||
|-----|---------|-----------|
|
|-----|---------|-----------|
|
||||||
| `1.4.2` (exact) | An immutable, smoke-tested release | **Production — always pin this** |
|
| `1.4.2` (exact) | An immutable, smoke-tested release | **Production — always pin this** |
|
||||||
| `1.4`, `1` | Latest patch/minor of that line | Tracking a line |
|
| `1.4`, `1` | Latest patch/minor of that line | Tracking a line |
|
||||||
| `latest` | The newest *released* version | Trying it out |
|
| `latest` | The freshest `main` build (rolling; may include unreleased code) | Trying the newest code |
|
||||||
| `edge` | The last `main` build (may be unstable) | Testing upcoming changes |
|
|
||||||
|
|
||||||
`latest` only moves when a real release is tagged — a routine merge to `main` publishes `edge`, never
|
`latest` moves on **every merge to `main`**, so it can change under you. **Pin `CIO_VERSION` to an
|
||||||
`latest`. **Pin `CIO_VERSION` to an exact version in production** so a new release can't break you
|
exact version in production** so a merge can't break you unattended.
|
||||||
unattended.
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Upgrade: bump the version, pull, recreate
|
# Upgrade: bump the version, pull, recreate
|
||||||
|
|||||||
Reference in New Issue
Block a user