Skip to content

Commit a9a7d35

Browse files
committed
ci(lint): add actionlint check and fix every finding it surfaces
With 17 workflow files and two composite actions after the per-type split, it's easy to introduce silent drift in workflow_dispatch input names, matrix expressions, `needs:` / `steps:` / `secrets:` / `vars:` references, `uses:` paths, and `if:` expressions. Add a small PR-time lint job (`.github/workflows/lint.yml`) that runs rhysd/actionlint against every push/PR touching `.github/` (workflows, composite actions, scripts, or the optional `actionlint.yaml` config). shellcheck is preinstalled on ubuntu-24.04, so actionlint also lints the `run:` shell snippets. The actionlint version is pinned via `ACTIONLINT_VERSION` so upstream rule additions don't silently change our lint surface between runs; bumping the version is an explicit, reviewable commit. The downloader script is taken verbatim from the actionlint README to avoid a third-party Action dependency. The shellcheck sub-linter is invoked with `-S warning` so CI only gates on warning+error severity. This filters out the large body of info-level SC2086 ('unquoted $var') findings in the older per-type workflows -- low-risk in practice because their values come from tightly-controlled workflow_dispatch inputs and GitHub expressions. `-e SC2046 -e SC2166` silences two additional warning-class codes deliberately deferred to a later shellcheck sweep PR (both are bash style/portability lints, not correctness bugs). The remaining genuine findings are fixed in the same commit so the job comes up green on first run: * gcp-publish.yml: drop invalid `default: ''` on two choice inputs. * gcp-test.yml: fix always-true `[ "${{ inputs.arch == 'ALL' }}" ]` test (SC2078), drop dead `matrix.zone` / `matrix.arch` references in the x86_64 per-shape job whose matrix declares only `shape:`. * azure-to-gallery.yml: bind GHA expressions (env.IMAGE_FILE, inputs.url_type, inputs.dry-run-mode, inputs.public_gallery, env.RELEASE_VERSION) to local shell variables before using them in `[[ ... ]]` / `case` tests (SC2193). * vagrant-publish.yml: drop unreachable `continue` after `exit 1`, and split `export VAR="$(cmd)"` into assign + export so a failing `hcp auth print-access-token` isn't masked by export's own exit code (SC2155). * ami-to-marketplace.yml: scoped `# shellcheck disable=SC2195` on the product-ID case block, with an explanatory comment whose lines don't start with the word 'shellcheck' (would otherwise be mis-parsed as directives, SC1072 / SC1073).
1 parent 2d2019c commit a9a7d35

6 files changed

Lines changed: 101 additions & 17 deletions

File tree

.github/workflows/ami-to-marketplace.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,15 @@ jobs:
6868
short_name="${{ fromJSON(env.AMI_JSON).Images[0].Name }}" && short_name="${short_name% * *}"
6969
version_major="${{ env.OS_VERSION }}" && version_major="${version_major%%.*}"
7070
71-
# List of AlmaLinux public products and their IDs
71+
# List of AlmaLinux public products and their IDs.
72+
#
73+
# NOTE: the disable directive below is intentional -- the linter
74+
# can't track the '${short_name% * *}' expansion above and flags
75+
# every case arm with SC2195 'pattern will never match'. The
76+
# composed word is always 'AlmaLinux OS <major> <arch>' in
77+
# practice (verified by the AWS AMI Name field format for
78+
# AlmaLinux images, e.g. 'AlmaLinux OS 9.6.20240619 x86_64').
79+
# shellcheck disable=SC2195
7280
case "${short_name} ${version_major} ${{ env.AMI_ARCH }}" in
7381
"AlmaLinux OS 8 x86_64") PRODUCT_ID="c076b20a-2305-4771-823f-944909847a05" ;;
7482
"AlmaLinux OS 8 arm64") PRODUCT_ID="744775f7-4efd-4c75-ac32-eb2540b4030c" ;;

.github/workflows/azure-to-gallery.yml

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -74,16 +74,23 @@ jobs:
7474
7575
- name: Read the image info
7676
run: |
77+
# Bind the GHA expressions to local shell variables up front so
78+
# the later bash [[ ... ]] and case tests operate on real string
79+
# values rather than raw GitHub-expression templates. Also avoids
80+
# surprises if anyone ever pokes the RHS through set -x.
81+
image_file='${{ env.IMAGE_FILE }}'
82+
url_type='${{ inputs.url_type }}'
83+
7784
# Capture version, timestamp and architecture
78-
case '${{ inputs.url_type }}' in
85+
case "$url_type" in
7986
RAW*)
8087
regex='-([0-9]+\.?[0-9]*)-([0-9]{8,9}(\.[0-9])?).*\.(x86_64|aarch64)'
81-
if [[ ${{ env.IMAGE_FILE }} =~ $regex ]]; then
88+
if [[ $image_file =~ $regex ]]; then
8289
release_version="${BASH_REMATCH[1]}"
8390
timestamp="${BASH_REMATCH[2]}"
8491
arch="${BASH_REMATCH[4]}"
8592
else
86-
echo "[Error] Could not parse '${{ env.IMAGE_FILE }}' file name!"
93+
echo "[Error] Could not parse '${image_file}' file name!"
8794
exit 1
8895
fi
8996
;;
@@ -93,19 +100,19 @@ jobs:
93100
regex_simple='almalinux-([0-9]+\.[0-9]+)-(x86_64|aarch64|arm64)\.([0-9]{8})'
94101
95102
# Modern .vhd files like AlmaLinux-10-Azure-10.0-20250529.0-64k.aarch64.vhd
96-
if [[ ${{ env.IMAGE_FILE }} =~ $regex_azure ]]; then
103+
if [[ $image_file =~ $regex_azure ]]; then
97104
release_version="${BASH_REMATCH[1]}"
98105
timestamp="${BASH_REMATCH[2]}"
99106
arch="${BASH_REMATCH[4]}"
100107
101108
# Legacy .vhd files like almalinux-9.6-arm64.20250522-01.vhd
102-
elif [[ ${{ env.IMAGE_FILE }} =~ $regex_simple ]]; then
109+
elif [[ $image_file =~ $regex_simple ]]; then
103110
release_version="${BASH_REMATCH[1]}"
104111
arch="${BASH_REMATCH[2]}"
105112
timestamp="${BASH_REMATCH[3]}"
106113
107114
else
108-
echo "[Error] Could not parse '${{ env.IMAGE_FILE }}' file name!"
115+
echo "[Error] Could not parse '${image_file}' file name!"
109116
exit 1
110117
fi
111118
;;
@@ -122,7 +129,7 @@ jobs:
122129
x86_64) image_type="default" ;;
123130
aarch64|arm64)
124131
image_type="arm64"
125-
[[ ${{ env.IMAGE_FILE }} == *-64k* ]] && image_type="arm64-64k"
132+
[[ $image_file == *-64k* ]] && image_type="arm64-64k"
126133
;;
127134
*) echo "[Error] Unknown architecture: $arch" ; exit 1 ;;
128135
esac
@@ -155,12 +162,15 @@ jobs:
155162
esac
156163
157164
# If dry-run-mode is false, then pass the -f option to upload to the Gallery
158-
[[ ${{ inputs.dry-run-mode }} == false ]] && \
165+
dry_run='${{ inputs.dry-run-mode }}'
166+
[[ "$dry_run" == false ]] && \
159167
release_options+=' -f'
160168
161169
# If public_gallery is true, then upload to 'almalinux' public Gallery
162170
# TODO: AlmaLinux 10 and Kitten are not released to the public Gallery
163-
[[ ${{ inputs.public_gallery }} == true ]] && [[ ${{ env.RELEASE_VERSION }} != "10"* ]] && \
171+
public_gallery='${{ inputs.public_gallery }}'
172+
release_version='${{ env.RELEASE_VERSION }}'
173+
[[ "$public_gallery" == true && "$release_version" != "10"* ]] && \
164174
release_options+=' -g almalinux'
165175
166176
./azure_uploader.sh ${release_options} \

.github/workflows/gcp-publish.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ on:
66
version_major:
77
description: 'AlmaLinux major version'
88
required: true
9-
default: ''
109
type: choice
1110
options:
1211
- 10-kitten
@@ -16,7 +15,6 @@ on:
1615
arch:
1716
description: 'Architecture we are publishing'
1817
required: true
19-
default: ''
2018
type: choice
2119
options:
2220
- x86_64

.github/workflows/gcp-test.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ jobs:
4444
if [ -n "${{ inputs.image_override }}" ]; then
4545
echo "Using image override: ${{ inputs.image_override }}"
4646
image_path="${{ inputs.image_override }}"
47-
elif [ "${{ inputs.arch == 'ALL' }}" ]; then
47+
elif [ "${{ inputs.arch }}" = "ALL" ]; then
4848
echo "Using version major: ${{ inputs.version_major }}"
4949
echo "Using all architectures"
5050
image_path="projects/almalinux-dev-images-469421/global/images/family/almalinux-${{ inputs.version_major }}"
@@ -262,9 +262,8 @@ jobs:
262262
-project almalinux-image-testing-469421 \
263263
-x86_shape ${{ matrix.shape }} \
264264
-parallel_count ${{ github.run_attempt > 1 && '1' || '1' }} \
265-
${{ matrix.zone && format('-zone {0}', matrix.zone) || '' }} \
266265
-filter '^(cvm|livemigrate|suspendresume|loadbalancer|guestagent|hostnamevalidation|imageboot|licensevalidation|network|security|hotattach|packagevalidation|ssh|metadata)$' \
267-
-images '${{ needs.init-data.outputs.image_path || inputs.image_override }}${{ inputs.image_override == '' && matrix.arch == 'aarch64' && '-arm64' || ''}}'
266+
-images '${{ needs.init-data.outputs.image_path || inputs.image_override }}'
268267
269268
test-gcp-pershape-aarch64:
270269
name: ${{ inputs.image_override || format('{0}', inputs.version_major) }} aarch64 ${{ matrix.shape }}

.github/workflows/lint.yml

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
name: "Lint: GitHub Actions workflows"
2+
3+
# Static check for the growing workflow / composite-action surface (17
4+
# workflow files + 2 composite actions at the time of writing). Catches
5+
# drift and typos in:
6+
#
7+
# * workflow_dispatch input declarations and references
8+
# * matrix / needs / steps / inputs / secrets / vars expressions
9+
# * `uses:` paths (including local composite actions)
10+
# * if: / expression grammar
11+
# * run: shell snippets (via shellcheck, preinstalled on ubuntu-24.04)
12+
#
13+
# See https://github.com/rhysd/actionlint for the full rule list.
14+
15+
on:
16+
push:
17+
branches: [main]
18+
paths:
19+
- ".github/workflows/**"
20+
- ".github/actions/**"
21+
- ".github/actionlint.yaml"
22+
- ".github/scripts/**"
23+
pull_request:
24+
paths:
25+
- ".github/workflows/**"
26+
- ".github/actions/**"
27+
- ".github/actionlint.yaml"
28+
- ".github/scripts/**"
29+
workflow_dispatch:
30+
31+
jobs:
32+
actionlint:
33+
name: actionlint
34+
runs-on: ubuntu-24.04
35+
permissions:
36+
contents: read
37+
steps:
38+
- uses: actions/checkout@v4
39+
40+
# Pin actionlint to a specific release so upstream rule additions
41+
# don't silently change our lint surface between runs. Bumping the
42+
# version is an explicit, reviewable commit.
43+
- name: Install actionlint
44+
id: get_actionlint
45+
env:
46+
ACTIONLINT_VERSION: '1.7.7'
47+
run: |
48+
bash <(curl -fsSL https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) \
49+
"${ACTIONLINT_VERSION}"
50+
shell: bash
51+
52+
# `-shellcheck` passes custom args to the shellcheck sub-linter:
53+
# -S warning gate on warning+error severity only. The bulk of
54+
# the info-level SC2086 ('unquoted $var') findings
55+
# in the older per-type workflows are low-risk in
56+
# practice (values come from tightly-controlled
57+
# workflow_dispatch inputs and GitHub expressions),
58+
# so we don't want to block CI on them until a
59+
# dedicated shellcheck sweep PR lands.
60+
# -e SC2046 'unquoted $(cmd)' in a handful of echo lines;
61+
# defer to the same sweep.
62+
# -e SC2166 '[ x -o y ]' / '[ x -a y ]' bashisms; widespread
63+
# in vagrant-build.yml / oci-marketplace-publish.yml
64+
# and mechanical to convert, but not in scope here.
65+
- name: Run actionlint
66+
run: |
67+
${{ steps.get_actionlint.outputs.executable }} -color \
68+
-shellcheck='shellcheck -S warning -e SC2046 -e SC2166'
69+
shell: bash

.github/workflows/vagrant-publish.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ jobs:
7979
8080
else
8181
echo "[Error]: No pattern matched for '$image_file'" && exit 1
82-
continue
8382
fi
8483
8584
# Remap "vmware" to the correct Vagrant provider name "vmware_desktop"
@@ -135,7 +134,8 @@ jobs:
135134
echo "[Debug] provider=${{ env.vagrant_provider }} box_name=${{ env.version_major }} checksum=${checksum} image_file=${{ env.image_file }}"
136135
137136
hcp auth login --client-id=${{ secrets.HCP_CLIENT_ID }} --client-secret=${{ secrets.HCP_CLIENT_SECRET }}
138-
export VAGRANT_CLOUD_TOKEN="$(hcp auth print-access-token)"
137+
VAGRANT_CLOUD_TOKEN="$(hcp auth print-access-token)"
138+
export VAGRANT_CLOUD_TOKEN
139139
[[ ${{ inputs.dry-run-mode }} = "true" ]] && cmd="echo " \
140140
|| cmd=''
141141
${cmd}vagrant cloud publish \

0 commit comments

Comments
 (0)