-
Notifications
You must be signed in to change notification settings - Fork 0
118 lines (102 loc) · 4.42 KB
/
Copy pathvalidate.yml
File metadata and controls
118 lines (102 loc) · 4.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
name: Validate variants.yaml
on:
pull_request:
branches:
- main
permissions:
contents: read
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
- name: Get changed variants.yaml files
id: changed
uses: tj-actions/changed-files@2d756ea4c53f7f6b397767d8723b3a10a9f35bf2 # v44.0.0
with:
files: '*/*/variants.yaml'
- name: Validate each manifest
if: steps.changed.outputs.any_changed == 'true'
shell: bash
env:
CHANGED_MANIFESTS: ${{ steps.changed.outputs.all_changed_files }}
run: |
set -uo pipefail
errors=0
for manifest in $CHANGED_MANIFESTS; do
case "$manifest" in
[A-Za-z0-9_./-]*) ;;
*) echo "::warning::skipping suspicious path '$manifest'"; continue ;;
esac
echo "::group::${manifest}"
dir="$(dirname "$manifest")"
dockerfile="${dir}/Dockerfile"
if ! yq eval '.' "$manifest" > /dev/null 2>&1; then
echo "::error file=${manifest}::invalid YAML syntax"
errors=$((errors+1))
echo "::endgroup::"
continue
fi
kind=$(yq eval 'type' "$manifest")
if [ "$kind" != "!!seq" ]; then
echo "::error file=${manifest}::root must be a YAML list (got ${kind})"
errors=$((errors+1))
echo "::endgroup::"
continue
fi
entries=$(yq eval -o=json "$manifest")
bad=$(jq -c '[.[] | select(
(.target | type) != "string" or .target == "" or
(has("suffix") | not) or
(.suffix != null and (.suffix | type) != "string")
)]' <<< "$entries")
if [ "$(jq 'length' <<< "$bad")" != "0" ]; then
echo "::error file=${manifest}::entries with invalid 'target' (non-empty string required) or 'suffix' (string or null required):"
jq -r '.[] | " - " + (. | tostring)' <<< "$bad"
errors=$((errors+1))
fi
bad_args=$(jq -c '[.[] | select(has("args") and (.args | type) != "object")]' <<< "$entries")
if [ "$(jq 'length' <<< "$bad_args")" != "0" ]; then
echo "::error file=${manifest}::'args' must be a mapping when present:"
jq -r '.[] | " - " + (. | tostring)' <<< "$bad_args"
errors=$((errors+1))
fi
bad_platforms=$(jq -c '[.[] | select(
has("platforms") and (
(.platforms | type) != "string" or
(.platforms | length) == 0
)
)]' <<< "$entries")
if [ "$(jq 'length' <<< "$bad_platforms")" != "0" ]; then
echo "::error file=${manifest}::'platforms' must be a non-empty string when present (e.g. 'linux/amd64' or 'linux/amd64,linux/arm64'):"
jq -r '.[] | " - " + (. | tostring)' <<< "$bad_platforms"
errors=$((errors+1))
fi
if [ ! -f "$dockerfile" ]; then
echo "::error file=${manifest}::sibling Dockerfile not found at ${dockerfile}"
errors=$((errors+1))
else
for target in $(jq -r '.[].target' <<< "$entries" | sort -u); do
if ! grep -qE "^FROM[[:space:]]+.*[[:space:]]+AS[[:space:]]+${target}([[:space:]]|$)" "$dockerfile"; then
echo "::error file=${manifest}::target '${target}' is not declared as a stage in ${dockerfile} (expected: FROM <base> AS ${target})"
errors=$((errors+1))
fi
done
fi
duplicates=$(jq -r '
[.[] | (if (.suffix // "") == "" then "<empty>" else .suffix end)] |
group_by(.) | map(select(length > 1)) | map(.[0]) | .[]
' <<< "$entries" | sort -u)
if [ -n "$duplicates" ]; then
echo "::error file=${manifest}::duplicate suffix(es) detected (would produce colliding tags):"
echo "$duplicates" | sed 's/^/ - /'
errors=$((errors+1))
fi
echo "::endgroup::"
done
if [ $errors -gt 0 ]; then
echo "Found ${errors} error(s) across the changed manifests."
exit 1
fi
echo "All changed variants.yaml are valid."