Skip to content

Commit 261842d

Browse files
authored
Add new sanitize-image-tag action and remove the unused container-tag action (#835)
1 parent c8455af commit 261842d

4 files changed

Lines changed: 209 additions & 124 deletions

File tree

.github/workflows/test-container-tag.yml renamed to .github/workflows/test-sanitize-image-tag.yml

Lines changed: 103 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
name: Test Container Tag Action
1+
name: Test Sanitize Image Tag Action
22

33
on:
44
pull_request:
55
paths:
6-
- "container-tag/**"
7-
- ".github/workflows/test-container-tag.yml"
6+
- "sanitize-image-tag/**"
7+
- ".github/workflows/test-sanitize-image-tag.yml"
88
workflow_dispatch:
99

1010
permissions:
1111
contents: read
1212

1313
jobs:
14-
test-tag-generation:
15-
name: Test Tag Generation
14+
test-basic:
15+
name: Test basic tag generation
1616
runs-on: ubuntu-24.04
1717
strategy:
1818
fail-fast: false
@@ -56,7 +56,7 @@ jobs:
5656

5757
- name: Generate tag - ${{ matrix.name }}
5858
id: generate
59-
uses: ./container-tag
59+
uses: ./sanitize-image-tag
6060
with:
6161
ref: ${{ matrix.ref }}
6262

@@ -73,51 +73,122 @@ jobs:
7373
echo "Actual: $ACTUAL"
7474
7575
if [[ "$ACTUAL" == "$EXPECTED" ]]; then
76-
echo "Test passed"
76+
echo "Test passed"
7777
else
78-
echo "Test failed: expected '$EXPECTED' but got '$ACTUAL'"
78+
echo "Test failed: expected '$EXPECTED' but got '$ACTUAL'"
7979
exit 1
8080
fi
8181
82-
test-github-context:
83-
name: Test with GitHub context
82+
test-prefix:
83+
name: Test prefix prepending
8484
runs-on: ubuntu-24.04
85+
strategy:
86+
fail-fast: false
87+
matrix:
88+
include:
89+
- name: Server prefix on main
90+
ref: main
91+
prefix: "server-"
92+
expected: server-dev
93+
- name: Web prefix on rc
94+
ref: rc
95+
prefix: "web-"
96+
expected: web-rc
97+
- name: Server prefix on feature branch
98+
ref: feature/foo
99+
prefix: "server-"
100+
expected: server-feature-foo
101+
- name: Prefix preserves main-to-dev mapping
102+
ref: refs/heads/main
103+
prefix: "server-"
104+
expected: server-dev
85105
steps:
86106
- name: Checkout
87107
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
88108
with:
89109
persist-credentials: false
90110

91-
- name: Generate tag from GitHub ref
92-
id: tag
93-
uses: ./container-tag
111+
- name: Generate tag - ${{ matrix.name }}
112+
id: generate
113+
uses: ./sanitize-image-tag
94114
with:
95-
ref: ${{ github.head_ref || github.ref }}
115+
ref: ${{ matrix.ref }}
116+
prefix: ${{ matrix.prefix }}
96117

97-
- name: Display generated tag
118+
- name: Verify output
98119
env:
99-
TAG: ${{ steps.tag.outputs.tag }}
100-
REF: ${{ github.head_ref || github.ref }}
120+
ACTUAL: ${{ steps.generate.outputs.tag }}
121+
EXPECTED: ${{ matrix.expected }}
122+
TEST_NAME: ${{ matrix.name }}
101123
run: |
102-
echo "GitHub ref: $REF"
103-
echo "Generated tag: $TAG"
124+
echo "Test: $TEST_NAME"
125+
echo "Expected: $EXPECTED"
126+
echo "Actual: $ACTUAL"
104127
105-
# Verify tag is not empty
106-
if [[ -z "$TAG" ]]; then
107-
echo "✗ Error: Generated tag is empty"
128+
if [[ "$ACTUAL" == "$EXPECTED" ]]; then
129+
echo "Test passed"
130+
else
131+
echo "Test failed: expected '$EXPECTED' but got '$ACTUAL'"
108132
exit 1
109133
fi
110134
111-
# Verify tag only contains valid characters
112-
if ! [[ "$TAG" =~ ^[a-z0-9._-]+$ ]]; then
113-
echo "✗ Error: Tag contains invalid characters"
135+
test-fork-repo:
136+
name: Test fork repo prepending
137+
runs-on: ubuntu-24.04
138+
strategy:
139+
fail-fast: false
140+
matrix:
141+
include:
142+
- name: Fork PR on feature branch
143+
ref: feature/foo
144+
fork_repo: bobuser/server
145+
expected: bobuser-server-feature-foo
146+
- name: Fork PR on main keeps fork name
147+
ref: main
148+
fork_repo: bobuser/server
149+
expected: bobuser-server-main
150+
- name: Fork with uppercase repo name
151+
ref: feature/bar
152+
fork_repo: BobUser/Server
153+
expected: bobuser-server-feature-bar
154+
- name: Fork with prefix
155+
ref: feature/foo
156+
prefix: "server-"
157+
fork_repo: bobuser/server
158+
expected: server-bobuser-server-feature-foo
159+
steps:
160+
- name: Checkout
161+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
162+
with:
163+
persist-credentials: false
164+
165+
- name: Generate tag - ${{ matrix.name }}
166+
id: generate
167+
uses: ./sanitize-image-tag
168+
with:
169+
ref: ${{ matrix.ref }}
170+
prefix: ${{ matrix.prefix }}
171+
fork_repo: ${{ matrix.fork_repo }}
172+
173+
- name: Verify output
174+
env:
175+
ACTUAL: ${{ steps.generate.outputs.tag }}
176+
EXPECTED: ${{ matrix.expected }}
177+
TEST_NAME: ${{ matrix.name }}
178+
run: |
179+
echo "Test: $TEST_NAME"
180+
echo "Expected: $EXPECTED"
181+
echo "Actual: $ACTUAL"
182+
183+
if [[ "$ACTUAL" == "$EXPECTED" ]]; then
184+
echo "Test passed"
185+
else
186+
echo "Test failed: expected '$EXPECTED' but got '$ACTUAL'"
114187
exit 1
115188
fi
116189
117-
echo "✓ Tag validation passed"
118-
119190
test-edge-cases:
120-
name: Test Edge Cases
191+
name: Test edge cases
121192
runs-on: ubuntu-24.04
122193
strategy:
123194
fail-fast: false
@@ -129,15 +200,12 @@ jobs:
129200
- name: Leading and trailing special chars
130201
ref: -feature-branch-
131202
expected: feature-branch
132-
- name: Only underscores and dots preserved
203+
- name: Underscores and dots preserved
133204
ref: feature_test.version
134205
expected: feature_test.version
135206
- name: Mixed special characters
136207
ref: FE@TUR#/T$ST%BR^NCH
137208
expected: fe-tur-t-st-br-nch
138-
- name: Leading dot after v stripping
139-
ref: v.something
140-
expected: something
141209
- name: Long branch name truncation
142210
ref: feature/this-is-a-very-long-branch-name-that-exceeds-the-maximum-allowed-length-of-128-characters-for-docker-tags-and-should-be-truncated-properly-without-leaving-trailing-special-chars
143211
expected: feature-this-is-a-very-long-branch-name-that-exceeds-the-maximum-allowed-length-of-128-characters-for-docker-tags-and-should-be
@@ -152,7 +220,7 @@ jobs:
152220

153221
- name: Generate tag - ${{ matrix.name }}
154222
id: generate
155-
uses: ./container-tag
223+
uses: ./sanitize-image-tag
156224
with:
157225
ref: ${{ matrix.ref }}
158226

@@ -169,8 +237,8 @@ jobs:
169237
echo "Actual: $ACTUAL"
170238
171239
if [[ "$ACTUAL" == "$EXPECTED" ]]; then
172-
echo "Test passed"
240+
echo "Test passed"
173241
else
174-
echo "Test failed: expected '$EXPECTED' but got '$ACTUAL'"
242+
echo "Test failed: expected '$EXPECTED' but got '$ACTUAL'"
175243
exit 1
176244
fi

container-tag/README.md

Lines changed: 0 additions & 81 deletions
This file was deleted.

sanitize-image-tag/README.md

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
# Sanitize Image Tag
2+
3+
A reusable GitHub Action that generates standardized container image tags from a Git ref, with optional prefix and fork-repo prepending. Centralizes the tag-derivation logic that was previously duplicated across `bitwarden/server`, `bitwarden/clients`, and `bitwarden/self-host`.
4+
5+
## Usage
6+
7+
### Basic
8+
9+
```yaml
10+
- name: Generate Docker image tag
11+
id: tag
12+
uses: bitwarden/gh-actions/sanitize-image-tag@main
13+
with:
14+
ref: ${{ github.head_ref || github.ref }}
15+
16+
- name: Build and push
17+
run: docker push ghcr.io/bitwarden/myimage:${{ steps.tag.outputs.tag }}
18+
```
19+
20+
### With prefix (e.g., dispatching Bitwarden Lite from server/clients)
21+
22+
```yaml
23+
- name: Generate override tag
24+
id: tag
25+
uses: bitwarden/gh-actions/sanitize-image-tag@main
26+
with:
27+
ref: ${{ github.head_ref || github.ref }}
28+
prefix: "server-"
29+
```
30+
31+
### With fork-PR handling
32+
33+
```yaml
34+
- name: Generate tag
35+
id: tag
36+
uses: bitwarden/gh-actions/sanitize-image-tag@main
37+
with:
38+
ref: ${{ github.head_ref || github.ref }}
39+
fork_repo: ${{ github.event.pull_request.head.repo.fork == true && github.event.pull_request.head.repo.full_name || '' }}
40+
```
41+
42+
## Inputs
43+
44+
| Input | Description | Required | Default |
45+
| ----------- | ---------------------------------------------------------------------------------------------------------------------- | -------- | ------- |
46+
| `ref` | Branch or tag reference. Accepts both `refs/heads/<name>` / `refs/tags/<name>` form and bare branch names. | Yes | |
47+
| `prefix` | Prepended verbatim to the final tag (include trailing dash, e.g., `server-`). | No | `""` |
48+
| `fork_repo` | Sanitized fork repo full name (e.g., `forkuser/repo`) prepended to distinguish fork-PR builds. Empty for non-fork events. | No | `""` |
49+
50+
## Outputs
51+
52+
| Output | Description |
53+
| ------ | --------------------------------- |
54+
| `tag` | The generated container image tag |
55+
56+
## Tag generation rules
57+
58+
1. **Ref extraction**: strips `refs/heads/` or `refs/tags/` prefix if present.
59+
2. **Sanitization**:
60+
- Lowercases the entire string.
61+
- Strips a single leading `v` (so `v1.2.3` → `1.2.3`).
62+
- Replaces any run of characters outside `[a-z0-9._-]` with a single `-`.
63+
- Collapses repeated dashes.
64+
- Strips leading/trailing `.` or `-`.
65+
3. **Fork prepending** (if `fork_repo` is set): sanitized fork name + `-` is prepended.
66+
4. **Main-to-dev mapping**: a final value of exactly `main` becomes `dev`. Runs after fork prepending so `fork-main` is unaffected.
67+
5. **Prefix**: `prefix` is prepended verbatim.
68+
6. **Length cap**: truncated to 128 characters; trailing `.` or `-` after truncation is stripped.
69+
70+
## Examples
71+
72+
| `ref` | `prefix` | `fork_repo` | Output |
73+
| --------------------------- | --------- | ------------------ | ------------------------------- |
74+
| `main` | `""` | `""` | `dev` |
75+
| `main` | `server-` | `""` | `server-dev` |
76+
| `rc` | `""` | `""` | `rc` |
77+
| `hotfix-rc` | `web-` | `""` | `web-hotfix-rc` |
78+
| `feature/PM-1234_update` | `""` | `""` | `feature-pm-1234_update` |
79+
| `Feature/Add-Login` | `server-` | `""` | `server-feature-add-login` |
80+
| `refs/tags/v2024.12.0` | `""` | `""` | `2024.12.0` |
81+
| `feature/foo` | `""` | `bobuser/server` | `bobuser-server-feature-foo` |
82+
| `main` | `""` | `bobuser/server` | `bobuser-server-main` |

0 commit comments

Comments
 (0)