Skip to content

Commit d48a7f8

Browse files
committed
write non-timestamped tag to GitOps repo
Signed-off-by: André Bauer <andre.bauer@staffbase.com>
1 parent 2ac9c02 commit d48a7f8

4 files changed

Lines changed: 80 additions & 3 deletions

File tree

README.md

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ Whenever the action updates a GitOps file, it stamps the following annotations o
114114
|------------|-------|
115115
| `deploy.staffbase.com/repositoryFullName` | The source repository in `owner/repo` form (`$GITHUB_REPOSITORY`) |
116116
| `deploy.staffbase.com/commitSha` | The commit SHA being deployed (`$GITHUB_SHA`) |
117-
| `deploy.staffbase.com/version` | The deployed image tag `dev-<timestamp>-<short-sha>` on `dev`, `main-<timestamp>-<short-sha>` on `main`, `master-<timestamp>-<short-sha>` on `master` (the UTC timestamp is inserted by default; with `docker-tag-timestamp: 'false'` it falls back to `<prefix>-<short-sha>`), the version without the leading `v` on `v*` tag pushes, and the tag name on other tag pushes |
117+
| `deploy.staffbase.com/version` | The image tag written to the GitOps repo — always the **non-timestamped** tag: `dev-<short-sha>` on `dev`, `main-<short-sha>` on `main`, `master-<short-sha>` on `master`, the version without the leading `v` on `v*` tag pushes, and the tag name on other tag pushes. See [GitOps tag](#gitops-tag) below |
118118

119119
These keys mirror the [Swarmia Deployment API](https://help.swarmia.com/settings/organization/configuring-deployments-in-swarmia) field names and are read by `flux-deployment-reporter` to report deployments to Swarmia once Flux finishes reconciling.
120120

@@ -176,10 +176,27 @@ to fall back to the legacy `<prefix>-<short-sha>` shape.
176176

177177
> **Note:** with the timestamp enabled (the default) the build also pushes the plain
178178
> `<prefix>-<short-sha>` tag alongside the timestamped one. That stable per-commit
179-
> tag is what the release step retags into the version tag, so it must continue
179+
> tag is what the release step retags into the version tag and what the action
180+
> writes to the GitOps repo (see [GitOps tag](#gitops-tag)), so it must continue
180181
> to exist. It does not match the `^<prefix>-[0-9]+-[0-9a-f]+$` filter below, so
181182
> Flux ignores it.
182183

184+
### GitOps tag
185+
186+
The tag the action **builds and pushes** is the timestamped one (so Flux image
187+
automation can sort it). The tag the action **writes to the external GitOps repo**
188+
(`gitops-dev`/`gitops-stage`/`gitops-prod` files and the deployment annotations) is
189+
always the **non-timestamped** tag — the stable `<prefix>-<short-sha>` alias for
190+
branch builds, and the plain tag for `v*`/custom builds (which never carry a
191+
timestamp).
192+
193+
This is deliberate and not configurable. When the action runs across separate
194+
invocations — e.g. one step builds the image and a later step pushes and updates
195+
GitOps — each invocation recomputes a *fresh* timestamp, so the timestamped tag
196+
differs between them. The `<prefix>-<short-sha>` alias is deterministic, so the
197+
GitOps reference stays consistent and always points at an image that was actually
198+
pushed.
199+
183200
With the timestamp enabled, use one `ImagePolicy` per environment, filtering by prefix:
184201

185202
```yaml

action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ runs:
195195
env:
196196
INPUT_DOCKER_REGISTRY: ${{ inputs.docker-registry }}
197197
INPUT_DOCKER_IMAGE: ${{ inputs.docker-image }}
198-
INPUT_TAG: ${{ steps.preparation.outputs.tag }}
198+
INPUT_TAG: ${{ steps.preparation.outputs.gitops_tag }}
199199
INPUT_PUSH: ${{ steps.preparation.outputs.push }}
200200
INPUT_GITOPS_USER: ${{ inputs.gitops-user }}
201201
INPUT_GITOPS_EMAIL: ${{ inputs.gitops-email }}

scripts/generate-tags.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,19 @@ if [[ -n "${LATEST:-}" ]]; then
9595
TAG_LIST+=",${INPUT_DOCKER_REGISTRY}/${INPUT_DOCKER_IMAGE}:${LATEST}"
9696
fi
9797

98+
# GITOPS_TAG is the tag written to the external GitOps repo. It is always the
99+
# non-timestamped tag: the stable <prefix>-<short-sha> alias for branch builds
100+
# (ALIAS_TAG), and the plain TAG for release/custom builds (which have no
101+
# timestamp anyway). Decoupling it from the timestamped image TAG avoids a
102+
# mismatch when the action runs in separate invocations (e.g. build then push):
103+
# each invocation recomputes a fresh timestamp for TAG, but the alias is
104+
# deterministic, so the GitOps reference stays consistent and points at an image
105+
# that was actually pushed.
106+
GITOPS_TAG="${ALIAS_TAG:-$TAG}"
107+
98108
set_output "build" "$BUILD"
99109
set_output "latest" "${LATEST:-}"
100110
set_output "push" "$PUSH"
101111
set_output "tag" "$TAG"
102112
set_output "tag_list" "$TAG_LIST"
113+
set_output "gitops_tag" "$GITOPS_TAG"

tests/generate-tags.bats

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,55 @@ teardown() {
282282
[[ "$tag_list" == "registry.staffbase.com/my-service:abcdef12" ]]
283283
}
284284

285+
# --- gitops_tag (always non-timestamped; written to the external GitOps repo) ---
286+
287+
@test "gitops_tag drops the timestamp on dev branch (default)" {
288+
export GITHUB_REF="refs/heads/dev"
289+
run "$SCRIPT"
290+
assert_success
291+
assert_output_value "tag" "dev-20260602143055-abcdef12"
292+
assert_output_value "gitops_tag" "dev-abcdef12"
293+
}
294+
295+
@test "gitops_tag drops the timestamp on main branch (default)" {
296+
export GITHUB_REF="refs/heads/main"
297+
run "$SCRIPT"
298+
assert_success
299+
assert_output_value "tag" "main-20260602143055-abcdef12"
300+
assert_output_value "gitops_tag" "main-abcdef12"
301+
}
302+
303+
@test "gitops_tag equals tag when timestamp flag is off" {
304+
export INPUT_DOCKER_TAG_TIMESTAMP="false"
305+
export GITHUB_REF="refs/heads/main"
306+
run "$SCRIPT"
307+
assert_success
308+
assert_output_value "tag" "main-abcdef12"
309+
assert_output_value "gitops_tag" "main-abcdef12"
310+
}
311+
312+
@test "gitops_tag equals tag for version (prod) tags" {
313+
export GITHUB_REF="refs/tags/v1.2.3"
314+
run "$SCRIPT"
315+
assert_success
316+
assert_output_value "gitops_tag" "1.2.3"
317+
}
318+
319+
@test "gitops_tag equals tag for custom tags" {
320+
export GITHUB_REF="refs/heads/main"
321+
export INPUT_DOCKER_CUSTOM_TAG="my-custom-tag"
322+
run "$SCRIPT"
323+
assert_success
324+
assert_output_value "gitops_tag" "my-custom-tag"
325+
}
326+
327+
@test "gitops_tag equals tag for feature branches" {
328+
export GITHUB_REF="refs/heads/feature/my-feature"
329+
run "$SCRIPT"
330+
assert_success
331+
assert_output_value "gitops_tag" "abcdef12"
332+
}
333+
285334
# --- validation ---
286335

287336
@test "fails when GITHUB_REF is missing" {

0 commit comments

Comments
 (0)