Skip to content

Commit 8d564d8

Browse files
committed
fix: harden ci and sync workflow
1 parent a37f0c8 commit 8d564d8

3 files changed

Lines changed: 45 additions & 9 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ on:
66
paths:
77
- ".github/workflows/ci.yml"
88
- ".github/scripts/**"
9+
- ".gitignore"
910
- "README.md"
1011
- "CITATION.cff"
1112
- "SECURITY.md"
@@ -17,6 +18,7 @@ on:
1718
paths:
1819
- ".github/workflows/ci.yml"
1920
- ".github/scripts/**"
21+
- ".gitignore"
2022
- "README.md"
2123
- "CITATION.cff"
2224
- "SECURITY.md"

scripts/sync-payload.sh

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ ROOT="$(cd "$(dirname "$0")/.." && pwd)"
77
MANIFEST="$ROOT/scripts/payload-manifest.json"
88
PAYLOAD_DIR="$ROOT/skills/python-project-workflow"
99
CI_MODE=false
10+
declare -a MANIFEST_FILES MANIFEST_SCRIPTS
1011

1112
[ "${1:-}" = "--ci" ] && CI_MODE=true
1213

@@ -17,6 +18,40 @@ DRIFT=false
1718
CHANGED=false
1819
SYNC_ERROR=false
1920

21+
manifest_entries() {
22+
local key="$1"
23+
24+
python3 - "$MANIFEST" "$key" <<'PY'
25+
import json
26+
import sys
27+
28+
path, key = sys.argv[1], sys.argv[2]
29+
with open(path, encoding="utf-8") as fh:
30+
data = json.load(fh)
31+
for item in data.get(key, []):
32+
sys.stdout.write(f"{item}\0")
33+
PY
34+
}
35+
36+
manifest_scalar() {
37+
local key="$1"
38+
39+
python3 - "$MANIFEST" "$key" <<'PY'
40+
import json
41+
import sys
42+
43+
path, key = sys.argv[1], sys.argv[2]
44+
with open(path, encoding="utf-8") as fh:
45+
data = json.load(fh)
46+
value = data.get(key, "")
47+
sys.stdout.write(value if isinstance(value, str) else "")
48+
PY
49+
}
50+
51+
mapfile -d '' -t MANIFEST_FILES < <(manifest_entries files)
52+
mapfile -d '' -t MANIFEST_SCRIPTS < <(manifest_entries scripts)
53+
REF_MODE="$(manifest_scalar references)"
54+
2055
mode_matches() {
2156
local target="$1"
2257
local mode="$2"
@@ -62,15 +97,13 @@ is_covered() {
6297
case "$rel" in
6398
SKILL.md) return 0 ;;
6499
esac
65-
for f in $(python3 -c "import json; d=json.load(open('$MANIFEST')); print('\n'.join(str(x) for x in d.get('files',[])))" 2>/dev/null); do
100+
for f in "${MANIFEST_FILES[@]}"; do
66101
[ "$rel" = "$f" ] && return 0
67102
done
68-
for s in $(python3 -c "import json; d=json.load(open('$MANIFEST')); print('\n'.join(str(x) for x in d.get('scripts',[])))" 2>/dev/null); do
103+
for s in "${MANIFEST_SCRIPTS[@]}"; do
69104
[ "$rel" = "scripts/$s" ] && return 0
70105
done
71-
local ref_mode
72-
ref_mode=$(python3 -c "import json; d=json.load(open('$MANIFEST')); r=d.get('references',''); print(r if isinstance(r,str) else '')" 2>/dev/null)
73-
if [ "$ref_mode" = "*" ]; then
106+
if [ "$REF_MODE" = "*" ]; then
74107
case "$rel" in
75108
references/*) [ -f "$ROOT/$rel" ] && return 0 ;;
76109
esac
@@ -79,14 +112,14 @@ is_covered() {
79112
}
80113

81114
# Files
82-
for f in $(python3 -c "import json; d=json.load(open('$MANIFEST')); print('\n'.join(str(x) for x in d.get('files',[])))" 2>/dev/null); do
115+
for f in "${MANIFEST_FILES[@]}"; do
83116
source="$ROOT/$f"
84117
target="$PAYLOAD_DIR/$f"
85118
sync_file "$source" "$target" "$f"
86119
done
87120

88121
# Scripts
89-
for s in $(python3 -c "import json; d=json.load(open('$MANIFEST')); print('\n'.join(str(x) for x in d.get('scripts',[])))" 2>/dev/null); do
122+
for s in "${MANIFEST_SCRIPTS[@]}"; do
90123
source="$ROOT/scripts/$s"
91124
target="$PAYLOAD_DIR/scripts/$s"
92125
mode=644
@@ -95,8 +128,7 @@ for s in $(python3 -c "import json; d=json.load(open('$MANIFEST')); print('\n'.j
95128
done
96129

97130
# References (mirror)
98-
ref_mode=$(python3 -c "import json; d=json.load(open('$MANIFEST')); r=d.get('references',''); print(r if isinstance(r,str) else '')" 2>/dev/null)
99-
if [ "$ref_mode" = "*" ]; then
131+
if [ "$REF_MODE" = "*" ]; then
100132
for source in "$ROOT/references/"*.md; do
101133
if [ ! -f "$source" ]; then
102134
echo " MISSING source: references/*.md"

scripts/validate-ci.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ def main() -> int:
2929
if validate is None:
3030
errors.append("ci.yml: missing validate job")
3131
else:
32+
if '".gitignore"' not in workflow:
33+
errors.append("ci.yml: validation workflow must trigger on .gitignore changes")
3234
if "python3 scripts/verify-urls.py" in validate:
3335
errors.append(
3436
"ci.yml: live URL checks must not run in the validation matrix"

0 commit comments

Comments
 (0)