Skip to content
Open
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
43 changes: 24 additions & 19 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ on:
push:
branches:
- main
tags:
- 'v*'
pull_request:
branches:
- main
Expand Down Expand Up @@ -36,23 +38,20 @@ jobs:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_PAT || secrets.GITHUB_TOKEN }}

- name: Generate Docker tags
- name: Extract Docker metadata
id: meta
run: |
IMAGE="${{ env.REGISTRY }}/${{ steps.image.outputs.name }}"
SHA_SHORT=$(echo ${{ github.sha }} | cut -c1-7)

if [ "${{ github.event_name }}" = "pull_request" ]; then
# PR builds: tag as pr-<number>
TAGS="${IMAGE}:pr-${{ github.event.pull_request.number }},${IMAGE}:sha-${SHA_SHORT}"
else
# Push to main: tag as both 'main' and 'latest'
TAGS="${IMAGE}:main,${IMAGE}:latest,${IMAGE}:sha-${SHA_SHORT}"
fi

echo "tags=${TAGS}" >> $GITHUB_OUTPUT
echo "primary_tag=$(echo ${TAGS} | cut -d',' -f1 | cut -d':' -f2)" >> $GITHUB_OUTPUT
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ steps.image.outputs.name }}
tags: |
type=ref,event=branch
type=ref,event=tag
type=ref,event=pr
type=semver,pattern={{version}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=semver,pattern={{major}}.{{minor}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=semver,pattern={{major}},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
type=sha,format=short

- name: Build and push Docker image
uses: docker/build-push-action@v5
Expand All @@ -62,11 +61,17 @@ jobs:
platforms: linux/amd64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max

- name: Image summary
run: |
echo "### Docker Image Built 🐳" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Tags:** ${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
{
echo "### Docker Image Built 🐳"
echo
echo "**Tags:**"
while IFS= read -r tag; do
printf -- "- %s\n" "$tag"
done <<< "${{ steps.meta.outputs.tags }}"
} >> "$GITHUB_STEP_SUMMARY"
10 changes: 8 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
.PHONY: help setup lint format typecheck pre-commit build push clean
.PHONY: help setup lint format typecheck pre-commit build push clean release

IMAGE_NAME := ghcr.io/eopf-explorer/data-pipeline
TAG := v0
TAG ?= v0
MESSAGE ?=
FLAGS ?=

help: ## Show this help message
@echo "🚀 EOPF GeoZarr Data Pipeline (Slim Branch)"
Expand Down Expand Up @@ -43,6 +45,10 @@ push: ## Push Docker image to registry
docker push $(IMAGE_NAME):$(TAG)
docker push $(IMAGE_NAME):latest

release: ## Cut and push a git tag (set TAG=vX[.Y[.Z]], optional MESSAGE="...", FLAGS="--force")
@if [ "$(origin TAG)" = "default" ]; then echo "TAG is required, e.g. make release TAG=v0"; exit 1; fi
@if [ -n "$(MESSAGE)" ]; then scripts/tag_release.sh $(FLAGS) "$(TAG)" "$(MESSAGE)"; else scripts/tag_release.sh $(FLAGS) "$(TAG)"; fi

clean: ## Clean generated files and caches
@echo "Cleaning generated files..."
find . -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
Expand Down
85 changes: 85 additions & 0 deletions scripts/tag_release.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/usr/bin/env bash
set -euo pipefail

usage() {
cat <<'EOF' >&2
Usage: tag_release.sh [-f|--force] <tag> [message]

<tag> Annotated tag to create (semantic version, e.g. v1.2.0)
[message] Optional tag message (defaults to "Release <tag>")

Options:
-f, --force Move an existing tag locally and on origin (force-with-lease)
-h, --help Show this help and exit
EOF
}

die() {
printf 'Error: %s\n' "$1" >&2
exit 1
}

FORCE=0
TAG=""

while [[ $# -gt 0 ]]; do
case "$1" in
-f|--force)
FORCE=1
shift
;;
-h|--help)
usage
exit 0
;;
--)
shift
break
;;
-*)
die "unknown option: $1"
;;
*)
TAG="$1"
shift
break
;;
esac
done

[[ -n "$TAG" ]] || { usage; exit 1; }

MESSAGE=${*:-"Release ${TAG}"}

[[ "$TAG" =~ ^v[0-9]+(\.[0-9]+)*$ ]] || die "tag must follow semantic style (e.g. v1.2.0)."

if [[ -n $(git status --porcelain) ]]; then
die "working tree has uncommitted changes."
fi

CURRENT_BRANCH=$(git symbolic-ref --short HEAD)
[[ "$CURRENT_BRANCH" == "main" ]] || die "releases must be created from main (current: $CURRENT_BRANCH)."

REMOTE=origin
git config --get remote."$REMOTE".url >/dev/null 2>&1 || die "remote '$REMOTE' is not configured."

git fetch "$REMOTE" main --tags --quiet >/dev/null 2>&1 || die "failed to fetch $REMOTE/main."
[[ $(git rev-parse HEAD) == $(git rev-parse "$REMOTE/main") ]] || die "local main is out of sync with $REMOTE/main."

if git rev-parse "$TAG" >/dev/null 2>&1 && [[ $FORCE -eq 0 ]]; then
die "tag '$TAG' already exists locally. Use --force to move it."
fi

if git ls-remote --tags "$REMOTE" "$TAG" | grep -q "refs/tags/$TAG$" && [[ $FORCE -eq 0 ]]; then
die "tag '$TAG' already exists on $REMOTE. Use --force to replace it."
fi

if [[ $FORCE -eq 1 ]]; then
git tag -fa "$TAG" -m "$MESSAGE"
git push "$REMOTE" "$TAG" --force-with-lease
echo "Moved tag '$TAG' to $(git rev-parse --short HEAD) and pushed with force-with-lease."
else
git tag -a "$TAG" -m "$MESSAGE"
git push "$REMOTE" "$TAG"
echo "Created tag '$TAG' at $(git rev-parse --short HEAD) and pushed to $REMOTE."
fi
15 changes: 15 additions & 0 deletions workflows/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,21 @@ geozarr-jflnj Failed 10h

## Configuration

### Docker Image Versions

CI now publishes images to `ghcr.io/eopf-explorer/data-pipeline` with the following tags:

- `main`, `latest`, and `sha-<short>` whenever a change lands on `main`.
- `vX.Y.Z`, `vX.Y`, `vX`, and `sha-<short>` from annotated semantic tags (for example `v1.2.0`).
- `pr-<number>` and `sha-<short>` for every pull-request build.

**Releasing a new tag**
1. Merge to `main`, then run `make release TAG=v1.2.0 [MESSAGE="Release v1.2.0"]` from a clean repo. The helper ensures `main` is clean and in sync before tagging.
2. Need to reuse an existing tag? Add `FLAGS="--force"`.
3. After GitHub Actions completes, production keeps running the new `latest` image. To pin a specific tag:
- **Staging first (preferred):** set `pipeline_image_version` in `workflows/overlays/staging/kustomization.yaml` to the tag (for example `v1.2.0`) and run `kubectl apply -k workflows/overlays/staging`. If it passes validation, make the same edit in `workflows/overlays/production/kustomization.yaml` and apply it.
- **Ship now:** set the tag directly in `workflows/overlays/production/kustomization.yaml` and apply. Staging already tracks the latest `main`; bump it too if you want staging and production on the same image.

### S3 Storage

- **Endpoint**: `https://s3.de.io.cloud.ovh.net` (OVH Frankfurt)
Expand Down
2 changes: 1 addition & 1 deletion workflows/base/workflowtemplate.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ spec:
- name: s3_output_prefix
value: tests-output
- name: pipeline_image_version
value: feature-align-data-model
value: latest
# Optional conversion parameter overrides (empty = use collection defaults)
- name: override_groups
value: ""
Expand Down