11name : ingest
22
3- # Reusable, manual PR generator (ADR-017). Only TechAPI's collect.yml calls it,
4- # from workflow_dispatch, so github.token is TechAPI's GITHUB_TOKEN and the
5- # branch and PR come from github-actions[bot]. Nothing here runs on a schedule,
6- # posts a comment, or uses a personal or bot-account token. Crawlers send the
7- # honest TechEngine-* User-Agent and keep their --sleep and limits.
3+ # Reusable, manual change generator (ADR-017). Only TechAPI's collect.yml calls
4+ # it, from workflow_dispatch, with a read-only token. The run commits locally,
5+ # gates the result and uploads the commit as collect.patch; a maintainer opens
6+ # the PR from their own account with TechAPI's .github/scripts/open-collect-pr.sh.
7+ # Nothing here pushes, opens a PR, posts a comment, runs on a schedule, or uses
8+ # a personal or bot-account token. Crawlers send the honest TechEngine-*
9+ # User-Agent and keep their --sleep and limits.
810#
911# Task: scrape upstream catalogs and draft missing SKUs into TechAPI data/.
1012on :
2426 default : false
2527
2628permissions :
27- contents : write
28- pull-requests : write
29+ contents : read
2930
3031concurrency :
3132 group : collect-ingest-${{ inputs.category }}
3940 CATEGORY : ${{ inputs.category }}
4041 LIMIT : ${{ inputs.limit }}
4142 INCLUDE_DRAFTS : ${{ inputs.include_drafts }}
42- DRAFT_FLAG : ${{ inputs.include_drafts && '--draft' || '' }}
4343 BRANCH : collect/ingest-${{ inputs.category }}
4444 TITLE : " feat(data/${{ inputs.category }}): ingest new SKUs"
4545 TECHAPI_DATA_DIR : ${{ github.workspace }}/TechAPI/data
5555 submodules : true
5656 # The Tier 0 diff compares the new commit with develop's tip only.
5757 fetch-depth : 1
58- # The write token is handed to the push step alone .
58+ # Nothing in this job pushes .
5959 persist-credentials : false
6060
6161 - uses : actions/setup-python@6d4fd22b20465ccc0f7354476588e8df7c9ca0e0 # v7.1.0
@@ -112,7 +112,7 @@ jobs:
112112 set -euo pipefail
113113 git add data/
114114 if git diff --cached --quiet; then
115- echo "No data changes; no PR ."
115+ echo "No data changes; no patch ."
116116 echo "changed=false" >> "$GITHUB_OUTPUT"
117117 exit 0
118118 fi
@@ -123,8 +123,8 @@ jobs:
123123 git commit -q -m "$TITLE"
124124 echo "changed=true" >> "$GITHUB_OUTPUT"
125125
126- # Gate: a PR opened with GITHUB_TOKEN triggers no checks, so the gate runs
127- # here and its result goes in the PR body. Any failure stops the push .
126+ # Gate: the result goes in the PR body. Any failure stops the run before
127+ # the patch is uploaded .
128128 - name : Gate (app.validate + integrity_check --strict)
129129 if : steps.commit.outputs.changed == 'true'
130130 working-directory : TechAPI/TechEngine
@@ -143,8 +143,8 @@ jobs:
143143 > "$GITHUB_WORKSPACE/verify-report.md" 2>&1 \
144144 || echo "_Tier 0 report unavailable._" > "$GITHUB_WORKSPACE/verify-report.md"
145145
146- # github-actions[bot] writes the body, so scraped text must not mention
147- # anyone or cross-reference an issue: drop "@", break "#123"/"GH-123" and
146+ # The body carries scraped text, which must not mention anyone or
147+ # cross-reference an issue: drop "@", break "#123"/"GH-123" and
148148 # URLs with a zero-width space. Colours such as #3fb950 are untouched.
149149 - name : Build PR body
150150 if : steps.commit.outputs.changed == 'true'
@@ -187,26 +187,46 @@ jobs:
187187 Path("pr-body.md").write_text(body, encoding="utf-8")
188188 PY
189189
190- # One open PR per task: the fixed branch is cut from develop and
191- # force-pushed each run; an open PR is edited in place. No comments.
192- - name : Push and open or update the PR
190+ # The token is read-only, so the commit leaves the run as a patch. A
191+ # maintainer opens the PR from their own account with TechAPI's
192+ # .github/scripts/open-collect-pr.sh <run-id>, so the PR's checks run.
193+ - name : Export the commit as collect.patch
193194 if : steps.commit.outputs.changed == 'true'
194- working-directory : TechAPI
195195 env :
196- GH_TOKEN : ${{ github.token }}
196+ BASE : ${{ steps.commit.outputs.base }}
197+ DRAFT : ${{ inputs.include_drafts }}
197198 run : |
198199 set -euo pipefail
199- auth=$(printf 'x-access-token:%s' "$GH_TOKEN" | base64 -w0)
200- git -c "http.https://github.com/.extraheader=AUTHORIZATION: basic $auth" \
201- push --force origin "HEAD:refs/heads/$BRANCH"
202- number=$(gh pr list --repo GetTechAPI/TechAPI --head "$BRANCH" --base develop \
203- --state open --json number --jq '.[0].number // empty')
204- if [ -n "$number" ]; then
205- gh pr edit "$number" --repo GetTechAPI/TechAPI --title "$TITLE" --body-file ../pr-body.md
206- else
207- gh pr create --repo GetTechAPI/TechAPI --base develop --head "$BRANCH" \
208- --title "$TITLE" --body-file ../pr-body.md $DRAFT_FLAG \
209- --assignee Seungpyo1007 --assignee TechEngineBot \
210- --label data --label enhancement \
211- --milestone "Massive dataset rebuild (1989-2026)"
200+ outside=$(git -C TechAPI diff --no-renames --name-only "$BASE" HEAD | grep -v '^data/' || true)
201+ if [ -n "$outside" ]; then
202+ echo "::error::The commit touches files outside data/:"
203+ echo "$outside"
204+ exit 1
212205 fi
206+ git -C TechAPI format-patch -1 --base="$BASE" --stdout HEAD > collect.patch
207+ python - <<'PY'
208+ import json
209+ import os
210+ meta = {
211+ "branch": os.environ["BRANCH"],
212+ "title": os.environ["TITLE"],
213+ "draft": os.environ.get("DRAFT") == "true",
214+ "base": os.environ["BASE"],
215+ }
216+ with open("pr.json", "w", encoding="utf-8") as f:
217+ json.dump(meta, f, indent=2)
218+ f.write("\n")
219+ PY
220+ cat pr-body.md >> "$GITHUB_STEP_SUMMARY"
221+
222+ - name : Upload collect.patch
223+ if : steps.commit.outputs.changed == 'true'
224+ uses : actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
225+ with :
226+ name : collect-ingest-${{ inputs.category }}
227+ path : |
228+ collect.patch
229+ pr-body.md
230+ pr.json
231+ if-no-files-found : error
232+ retention-days : 14
0 commit comments