|
1 | 1 | version: '3' |
2 | | - |
3 | 2 | silent: true |
4 | | - |
5 | 3 | vars: |
6 | 4 | PR_TEMPLATE: https://raw.githubusercontent.com/devops-infra/.github/refs/tags/v1/PULL_REQUEST_TEMPLATE.md |
7 | 5 | CONFIGS_BASE_URL: https://raw.githubusercontent.com/devops-infra/.github/refs/tags/v1/templates/dockerized/configs |
8 | 6 | TASKFILES_BASE_URL: https://raw.githubusercontent.com/devops-infra/.github/refs/tags/v1/templates/dockerized/taskfiles |
9 | | - |
10 | 7 | tasks: |
11 | 8 | pre-commit: |
12 | 9 | desc: Run all pre-commit hooks |
13 | 10 | cmds: |
14 | 11 | - pre-commit run --all-files |
15 | | - |
16 | 12 | pre-commit:install: |
17 | 13 | desc: Install pre-commit hooks |
18 | 14 | cmds: |
19 | 15 | - pre-commit install |
20 | | - |
21 | 16 | lint: |
22 | 17 | desc: Run all linters (Dockerfile, shell scripts, workflows, YAML) |
23 | 18 | cmds: |
24 | 19 | - task: lint:actionlint |
25 | 20 | - task: lint:hadolint |
26 | 21 | - task: lint:shellcheck |
27 | 22 | - task: lint:yamllint |
28 | | - |
29 | 23 | lint:actionlint: |
30 | 24 | desc: Lint GitHub Actions workflows with actionlint |
31 | 25 | cmds: |
32 | | - - | |
33 | | - echo "▶️ Running actionlint..." |
34 | | - set +e |
35 | | - docker run --rm -i -v "$PWD:/work" -w /work rhysd/actionlint:latest -color |
36 | | - rc=$? |
37 | | - set -e |
38 | | - if [ "$rc" -eq 0 ]; then |
39 | | - echo "✅ actionlint passed" |
40 | | - else |
41 | | - echo "❌ actionlint failed" |
42 | | - exit $rc |
43 | | - fi |
44 | | -
|
| 26 | + - task: scripts:lint:actionlint |
45 | 27 | lint:hadolint: |
46 | 28 | desc: Lint Dockerfile with hadolint |
47 | 29 | cmds: |
48 | | - - | |
49 | | - echo "▶️ Running hadolint..." |
50 | | - set +e |
51 | | - docker run --rm -i -v "$PWD:/work" -w /work hadolint/hadolint:latest-debian < Dockerfile |
52 | | - rc=$? |
53 | | - set -e |
54 | | - if [ "$rc" -eq 0 ]; then |
55 | | - echo "✅ hadolint passed" |
56 | | - else |
57 | | - echo "❌ hadolint failed" |
58 | | - exit $rc |
59 | | - fi |
60 | | -
|
| 30 | + - task: scripts:lint:hadolint |
61 | 31 | lint:shellcheck: |
62 | 32 | desc: Lint shell scripts with shellcheck |
63 | 33 | cmds: |
64 | 34 | - task: scripts:lint:shellcheck |
65 | | - |
66 | 35 | lint:yamllint: |
67 | 36 | desc: Lint YAML files with yamllint |
68 | 37 | cmds: |
69 | | - - | |
70 | | - echo "▶️ Running yamllint..." |
71 | | - set +e |
72 | | - docker run --rm -i -v "$PWD:/work" -w /work cytopia/yamllint -c .yamllint.yml . |
73 | | - rc=$? |
74 | | - set -e |
75 | | - if [ "$rc" -eq 0 ]; then |
76 | | - echo "✅ yamllint passed" |
77 | | - else |
78 | | - echo "❌ yamllint failed" |
79 | | - exit $rc |
80 | | - fi |
81 | | -
|
| 38 | + - task: scripts:lint:yamllint |
82 | 39 | dependency:update: |
83 | | - desc: Update repository dependencies not covered by dependabot |
| 40 | + desc: 'No-op: no dedicated dependency updater configured for this profile' |
84 | 41 | cmds: |
85 | | - - task: scripts:packages:update |
86 | | - |
| 42 | + - task: scripts:dependency:update |
87 | 43 | version:set: |
88 | 44 | desc: Validate version |
89 | 45 | cmds: |
90 | | - - | |
91 | | - if [ -z "{{.VERSION}}" ]; then |
92 | | - echo "❌ ERROR: VERSION is empty" |
93 | | - exit 1 |
94 | | - fi |
95 | | - if ! echo "{{.VERSION}}" | grep -Eq '^v?[0-9]+\.[0-9]+\.[0-9]+$'; then |
96 | | - echo "❌ ERROR: VERSION '{{.VERSION}}' is not a valid semantic version (expected vX.Y.Z or X.Y.Z)" |
97 | | - exit 1 |
98 | | - fi |
99 | | -
|
| 46 | + - task: scripts:version:set |
100 | 47 | version:update:patch: |
101 | 48 | desc: Increment patch version (e.g., 1.2.3 -> 1.2.4) |
102 | 49 | cmds: |
103 | 50 | - task version:set VERSION=v{{.MAJOR}}.{{.MINOR}}.{{.NEXT_PATCH}} |
104 | | - |
105 | 51 | version:update:minor: |
106 | 52 | desc: Increment minor version (e.g., 1.2.3 -> 1.3.0) |
107 | 53 | cmds: |
108 | 54 | - task version:set VERSION=v{{.MAJOR}}.{{.NEXT_MINOR}}.0 |
109 | | - |
110 | 55 | version:update:major: |
111 | 56 | desc: Increment major version (e.g., 1.2.3 -> 2.0.0) |
112 | 57 | cmds: |
113 | 58 | - task version:set VERSION=v{{.NEXT_MAJOR}}.0.0 |
114 | | - |
115 | 59 | version:resolve-next: |
116 | 60 | desc: Resolve next version from bump type and profile |
117 | 61 | cmds: |
118 | | - - | |
119 | | - set -eu |
120 | | - bump_type="${BUMP_TYPE:-patch}" |
121 | | - input_version="${INPUT_VERSION:-}" |
122 | | -
|
123 | | - normalize_version() { |
124 | | - candidate="${1#v}" |
125 | | - if ! printf "%s" "${candidate}" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$'; then |
126 | | - return 1 |
127 | | - fi |
128 | | - printf "v%s" "${candidate}" |
129 | | - } |
130 | | -
|
131 | | - current="$(task version:get 2>/dev/null || true)" |
132 | | -
|
133 | | - case "$bump_type" in |
134 | | - set) |
135 | | - [ -n "$input_version" ] || { echo "Missing version for type=set"; exit 1; } |
136 | | - next="$(normalize_version "$input_version")" || { |
137 | | - echo "Invalid explicit version: $input_version. Expected vX.Y.Z or X.Y.Z" |
138 | | - exit 1 |
139 | | - } |
140 | | - ;; |
141 | | - patch|minor|major) |
142 | | - [ -n "$current" ] || { echo "Current version not found or invalid. Expected vX.Y.Z"; exit 1; } |
143 | | - current="$(normalize_version "$current")" || { echo "Current version not found or invalid. Expected vX.Y.Z"; exit 1; } |
144 | | - no_v="${current#v}" |
145 | | - major="$(printf "%s" "$no_v" | awk -F. '{print $1}')" |
146 | | - minor="$(printf "%s" "$no_v" | awk -F. '{print $2}')" |
147 | | - patch="$(printf "%s" "$no_v" | awk -F. '{print $3}')" |
148 | | - case "$bump_type" in |
149 | | - patch) next="v${major}.${minor}.$((patch + 1))" ;; |
150 | | - minor) next="v${major}.$((minor + 1)).0" ;; |
151 | | - major) next="v$((major + 1)).0.0" ;; |
152 | | - esac |
153 | | - ;; |
154 | | - *) |
155 | | - echo "Unknown type: $bump_type" |
156 | | - exit 1 |
157 | | - ;; |
158 | | - esac |
159 | | -
|
160 | | - printf "%s" "$next" |
161 | | -
|
| 62 | + - task: scripts:version:resolve-next |
162 | 63 | version:tag-release: |
163 | 64 | desc: Create set of git tags |
164 | 65 | cmds: |
165 | | - - | |
166 | | - set -eu |
167 | | - if (set -o | grep -q pipefail) 2>/dev/null; then set -o pipefail; fi |
168 | | -
|
169 | | - REMOTE='origin' |
170 | | - FULL='{{.VERSION_FULL}}' |
171 | | - MINOR='{{.VERSION_MINOR}}' |
172 | | - MAJOR='{{.VERSION_MAJOR}}' |
173 | | -
|
174 | | - # Validate vX.Y.Z |
175 | | - if ! printf "%s" "$FULL" | grep -Eq '^v[0-9]+\.[0-9]+\.[0-9]+$'; then |
176 | | - echo "❌ ERROR: VERSION '$FULL' must match vX.Y.Z" >&2 |
177 | | - exit 1 |
178 | | - fi |
179 | | -
|
180 | | - tag_sha() { git rev-parse "refs/tags/$1" 2>/dev/null || true; } |
181 | | - remote_tag_sha() { git ls-remote --tags "$REMOTE" "refs/tags/$1" 2>/dev/null | awk '{print $1}' || true; } |
182 | | -
|
183 | | - echo "ℹ️ INFO: Tags - Full: $FULL | Minor: $MINOR | Major: $MAJOR" |
184 | | -
|
185 | | - # Full tag: must NOT exist on remote; fail fast if it does |
186 | | - full_remote_sha="$(remote_tag_sha "$FULL")" |
187 | | - if [ -n "$full_remote_sha" ]; then |
188 | | - echo "❌ ERROR: Full tag '$FULL' already exists on remote; aborting" >&2 |
189 | | - exit 1 |
190 | | - fi |
191 | | -
|
192 | | - # Create full tag locally (if missing) and push |
193 | | - if git rev-parse --quiet --verify "refs/tags/$FULL" >/dev/null 2>&1; then |
194 | | - echo "ℹ️ INFO: Full tag '$FULL' exists locally but not on remote; pushing" |
195 | | - else |
196 | | - echo "ℹ️ INFO: Creating full tag '$FULL'" |
197 | | - git tag --annotate "$FULL" --message "$FULL" |
198 | | - fi |
199 | | - git push "$REMOTE" "refs/tags/$FULL" |
200 | | - echo "✅ OK: Pushed full tag '$FULL'" |
201 | | -
|
202 | | - # Minor tag: create or update |
203 | | - git tag --force --annotate "$MINOR" --message "$FULL" |
204 | | - minor_local_sha="$(tag_sha "$MINOR")" |
205 | | - minor_remote_sha="$(remote_tag_sha "$MINOR")" |
206 | | - if [ -z "$minor_remote_sha" ]; then |
207 | | - git push "$REMOTE" "refs/tags/$MINOR" |
208 | | - echo "✅ OK: Created and pushed minor tag '$MINOR' -> $minor_local_sha" |
209 | | - else |
210 | | - if [ "$minor_local_sha" != "$minor_remote_sha" ]; then |
211 | | - echo "⚠️ WARN: Updating remote minor tag '$MINOR' to $minor_local_sha (was $minor_remote_sha)" |
212 | | - git push --force "$REMOTE" "refs/tags/$MINOR" |
213 | | - else |
214 | | - echo "ℹ️ INFO: Minor tag '$MINOR' already up-to-date" |
215 | | - fi |
216 | | - fi |
217 | | -
|
218 | | - # Major tag: create or update |
219 | | - git tag --force --annotate "$MAJOR" --message "$FULL" |
220 | | - major_local_sha="$(tag_sha "$MAJOR")" |
221 | | - major_remote_sha="$(remote_tag_sha "$MAJOR")" |
222 | | - if [ -z "$major_remote_sha" ]; then |
223 | | - git push "$REMOTE" "refs/tags/$MAJOR" |
224 | | - echo "✅ OK: Created and pushed major tag '$MAJOR' -> $major_local_sha" |
225 | | - else |
226 | | - if [ "$major_local_sha" != "$major_remote_sha" ]; then |
227 | | - echo "⚠️ WARN: Updating remote major tag '$MAJOR' to $major_local_sha (was $major_remote_sha)" |
228 | | - git push --force "$REMOTE" "refs/tags/$MAJOR" |
229 | | - else |
230 | | - echo "ℹ️ INFO: Major tag '$MAJOR' already up-to-date" |
231 | | - fi |
232 | | - fi |
233 | | -
|
| 66 | + - task: scripts:version:tag-release |
234 | 67 | git:get-pr-template: |
235 | 68 | desc: Get pull request template |
236 | 69 | cmds: |
237 | | - - mkdir -p .tmp |
238 | | - - curl -LsS {{.PR_TEMPLATE}} -o .tmp/PULL_REQUEST_TEMPLATE.md |
239 | | - |
| 70 | + - task: scripts:git:get-pr-template |
240 | 71 | git:set-config: |
241 | 72 | desc: Set git user config |
242 | 73 | cmds: |
243 | | - - git config user.name "github-actions[bot]" |
244 | | - - git config user.email "github-actions[bot]@users.noreply.github.com" |
245 | | - |
| 74 | + - task: scripts:git:set-config |
246 | 75 | version:get: |
247 | 76 | desc: Get current version |
248 | 77 | cmds: |
249 | | - - echo "{{.VERSION}}" |
| 78 | + - task: scripts:version:get |
0 commit comments