Skip to content

Commit c82333d

Browse files
Add Root Level Manifest Checks
2 parents 01d706f + ade0d05 commit c82333d

3 files changed

Lines changed: 99 additions & 38 deletions

File tree

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#!/usr/bin/env bash
2+
3+
# Validates manifest readability, JSON shape, and duplicate zip entries.
4+
validate_manifest() {
5+
local manifest_path="${1:?manifest path is required}"
6+
7+
if [[ ! -f "$manifest_path" ]]; then
8+
echo "::error file=$manifest_path::Manifest not found"
9+
return 1
10+
fi
11+
12+
if ! jq -e . "$manifest_path" >/dev/null; then
13+
echo "::error file=$manifest_path::Manifest is not valid JSON"
14+
return 1
15+
fi
16+
17+
local dup_zips
18+
dup_zips="$(
19+
jq -r '
20+
[
21+
to_entries[]
22+
| select(.value | type == "array")
23+
| .value[]?
24+
| select(type == "object" and ((.zip // "") != ""))
25+
| .zip
26+
]
27+
| group_by(.)
28+
| map(select(length > 1) | .[0])
29+
| .[]?
30+
' "$manifest_path"
31+
)"
32+
33+
if [[ -n "$dup_zips" ]]; then
34+
while IFS= read -r dup; do
35+
[[ -z "$dup" ]] && continue
36+
echo "::error file=$manifest_path::Duplicate zip entry found in manifest: $dup"
37+
done <<< "$dup_zips"
38+
return 1
39+
fi
40+
}
41+
42+
# Returns exactly one matching manifest entry JSON object for zip filename.
43+
get_manifest_entry_for_zip() {
44+
local zip_file="${1:?zip filename is required}"
45+
local manifest_path="${2:?manifest path is required}"
46+
47+
local matches
48+
matches="$(
49+
jq -c --arg z "$zip_file" '
50+
[
51+
to_entries[]
52+
| select(.value | type == "array")
53+
| .value[]?
54+
| select(type == "object" and (.zip? == $z))
55+
]
56+
' "$manifest_path"
57+
)"
58+
59+
local match_count
60+
match_count="$(jq 'length' <<< "$matches")"
61+
62+
if [[ "$match_count" -eq 0 ]]; then
63+
echo "::error file=$manifest_path::No manifest entry found for ZIP $zip_file"
64+
return 1
65+
fi
66+
if [[ "$match_count" -gt 1 ]]; then
67+
echo "::error file=$manifest_path::Multiple manifest entries found for ZIP $zip_file"
68+
return 1
69+
fi
70+
71+
jq -c '.[0]' <<< "$matches"
72+
}

.github/workflows/update-catalog.yml

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ jobs:
2727
AFTER_SHA: ${{ github.sha }}
2828
run: |
2929
set -euo pipefail
30+
source ".github/scripts/root-manifest-utils.sh"
31+
manifest_path="commerce-apps-manifest/manifest.json"
32+
validate_manifest "$manifest_path"
3033
3134
# 1) Find ZIP files changed in this push to main (merge commit)
3235
mapfile -t changed_zips < <(git diff --name-only "$BEFORE_SHA" "$AFTER_SHA" -- '**/*.zip')
@@ -50,28 +53,24 @@ jobs:
5053
5154
zip_dir="$(dirname "$zip_path")"
5255
catalog_path="$zip_dir/catalog.json"
53-
manifest_path="$zip_dir/manifest.json"
5456
5557
# 2) If no catalog.json next to this zip, exit (no-op)
5658
if [[ ! -f "$catalog_path" ]]; then
5759
echo "No catalog.json at $catalog_path. Exiting."
5860
exit 0
5961
fi
6062
61-
if [[ ! -f "$manifest_path" ]]; then
62-
echo "::error file=$manifest_path::manifest.json not found next to ZIP ($zip_path)"
63-
exit 1
64-
fi
63+
zip_file="$(basename "$zip_path")"
64+
entry="$(get_manifest_entry_for_zip "$zip_file" "$manifest_path")"
6565
66-
# Version from manifest.json (expects .version)
67-
version="$(jq -r '.version // empty' "$manifest_path")"
66+
# Version from manifest entry (expects .version)
67+
version="$(jq -r '.version // empty' <<< "$entry")"
6868
if [[ -z "$version" || "$version" == "null" ]]; then
69-
echo "::error file=$manifest_path::Missing .version in manifest.json"
69+
echo "::error file=$manifest_path::Missing .version for ZIP $zip_file"
7070
exit 1
7171
fi
7272
7373
# 3) Tag name = zip filename without .zip
74-
zip_file="$(basename "$zip_path")"
7574
tag_name="${zip_file%.zip}"
7675
7776
# Create + push tag (skip if already exists)

.github/workflows/verify-zip.yml

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ jobs:
2323
shell: bash
2424
run: |
2525
set -euo pipefail
26+
source ".github/scripts/root-manifest-utils.sh"
27+
manifest_path="commerce-apps-manifest/manifest.json"
28+
validate_manifest "$manifest_path"
2629
2730
# Collect changed ZIPs into a file that the next step can reuse
2831
: > changed_zips.txt
@@ -46,22 +49,17 @@ jobs:
4649
continue
4750
fi
4851
49-
dir="$(dirname "$zip_path")"
50-
manifest_path="$dir/manifest.json"
51-
52-
if [[ ! -f "$manifest_path" ]]; then
53-
echo "::error file=$manifest_path::manifest.json not found next to ZIP ($zip_path)"
54-
exit 1
55-
fi
52+
zip_file="$(basename "$zip_path")"
53+
entry="$(get_manifest_entry_for_zip "$zip_file" "$manifest_path")"
5654
5755
# Compute checksum of the ZIP
5856
computed="$(sha256sum "$zip_path" | awk '{print $1}' | tr '[:upper:]' '[:lower:]')"
5957
60-
# Read sha256 from manifest.json
61-
manifest_sha="$(jq -r '.sha256 // empty' "$manifest_path" | tr '[:upper:]' '[:lower:]')"
58+
# Read sha256 from manifest entry
59+
manifest_sha="$(jq -r '.sha256 // empty' <<< "$entry" | tr '[:upper:]' '[:lower:]')"
6260
6361
if [[ -z "$manifest_sha" || "$manifest_sha" == "null" ]]; then
64-
echo "::error file=$manifest_path::Missing or empty \"sha256\" field in manifest.json"
62+
echo "::error file=$manifest_path::Missing or empty \"sha256\" for ZIP $zip_file"
6563
exit 1
6664
fi
6765
@@ -79,42 +77,34 @@ jobs:
7977
shell: bash
8078
run: |
8179
set -euo pipefail
80+
source ".github/scripts/root-manifest-utils.sh"
81+
manifest_path="commerce-apps-manifest/manifest.json"
82+
validate_manifest "$manifest_path"
8283
8384
[[ -s changed_zips.txt ]] || exit 0
8485
8586
while IFS= read -r zip_path; do
8687
[[ -f "$zip_path" ]] || continue
8788
8889
dir="$(dirname "$zip_path")"
89-
manifest_path="$dir/manifest.json"
9090
catalog_path="$dir/catalog.json"
9191
9292
if [[ ! -f "$catalog_path" ]]; then
9393
echo "::error file=$catalog_path::catalog.json not found next to ZIP ($zip_path)"
9494
exit 1
9595
fi
9696
97-
if [[ ! -f "$manifest_path" ]]; then
98-
echo "::error file=$manifest_path::manifest.json not found next to ZIP ($zip_path)"
99-
exit 1
100-
fi
101-
10297
zip_file="$(basename "$zip_path")"
103-
manifest_zip="$(jq -r '.zip // empty' "$manifest_path")"
98+
entry="$(get_manifest_entry_for_zip "$zip_file" "$manifest_path")"
99+
manifest_zip="$(jq -r '.zip // empty' <<< "$entry")"
104100
if [[ -z "$manifest_zip" || "$manifest_zip" == "null" ]]; then
105-
echo "::error file=$manifest_path::Missing \"zip\" field in manifest.json"
101+
echo "::error file=$manifest_path::Missing \"zip\" for ZIP $zip_file"
106102
exit 1
107103
fi
108104
109-
version="$(jq -r '.version // empty' "$manifest_path")"
105+
version="$(jq -r '.version // empty' <<< "$entry")"
110106
if [[ -z "$version" || "$version" == "null" ]]; then
111-
echo "::error file=$manifest_path::Missing \"version\" field in manifest.json"
112-
exit 1
113-
fi
114-
115-
# Verify zip field in manifest matches file name
116-
if [[ "$manifest_zip" != "$zip_file" ]]; then
117-
echo "::error file=$manifest_path::manifest.json \"zip\" ($manifest_zip) does not match changed zip filename ($zip_file)"
107+
echo "::error file=$manifest_path::Missing \"version\" for ZIP $zip_file"
118108
exit 1
119109
fi
120110
@@ -165,10 +155,10 @@ jobs:
165155
fi
166156
done
167157
168-
# Ensure app-configuration/taskList.json exists in the ZIP payload
169-
required_task_list="$root/app-configuration/taskList.json"
158+
# Ensure app-configuration/tasksList.json exists in the ZIP payload
159+
required_task_list="$root/app-configuration/tasksList.json"
170160
if [[ ! -f "$required_task_list" ]]; then
171-
echo "::error file=$zip_path::Missing required file app-configuration/taskList.json"
161+
echo "::error file=$zip_path::Missing required file app-configuration/tasksList.json"
172162
rm -rf "$tmpdir"
173163
exit 1
174164
fi

0 commit comments

Comments
 (0)