@@ -2137,27 +2137,71 @@ jobs:
21372137 fi
21382138 echo "== Prereqs deployment validation PASSED =="
21392139
2140+ # ── Stage generated azuredeploy.json into a workspace-rooted tree ───────
2141+ # actions/upload-artifact@v4 rebases uploaded files to the *least common
2142+ # ancestor* of the matched paths. For a typical sample with no prereqs/
2143+ # folder only one file matches (<sample>/azuredeploy.json) and the LCA
2144+ # collapses to the file itself, so the artifact would contain a bare
2145+ # `azuredeploy.json` at its root — which the merge job would then
2146+ # extract into the repository root instead of the sample folder.
2147+ #
2148+ # To preserve the full repo-relative path, copy the generated files
2149+ # into ${RUNNER_TEMP}/generated/<sample_path>/... and upload that
2150+ # directory. The merge job extracts it into the checked-out default
2151+ # branch with `path: .`, so the files land in the correct sample
2152+ # folders.
2153+ - name : Stage generated azuredeploy.json files for artifact upload
2154+ id : stage-generated
2155+ if : >-
2156+ steps.preflight.outputs.skip != 'true' &&
2157+ (steps.compile-main.outputs.generated == 'true' ||
2158+ steps.compile-prereqs.outputs.generated == 'true')
2159+ shell : bash
2160+ env :
2161+ SAMPLE_PATH : ${{ steps.find-metadata.outputs.sample_path }}
2162+ run : |
2163+ set -euo pipefail
2164+ STAGE_DIR="${RUNNER_TEMP}/generated"
2165+ DEST_DIR="${STAGE_DIR}/${SAMPLE_PATH}"
2166+ mkdir -p "${DEST_DIR}/prereqs"
2167+
2168+ copied=0
2169+ for rel in azuredeploy.json prereqs/azuredeploy.json prereqs/prereq.azuredeploy.json; do
2170+ src="${SAMPLE_PATH}/${rel}"
2171+ if [[ -f "${src}" ]]; then
2172+ cp "${src}" "${DEST_DIR}/${rel}"
2173+ echo "Staged ${src} → ${DEST_DIR}/${rel}"
2174+ copied=$((copied + 1))
2175+ fi
2176+ done
2177+
2178+ # Drop the empty prereqs/ dir if nothing landed there, so the
2179+ # artifact tree mirrors only files that actually exist.
2180+ rmdir "${DEST_DIR}/prereqs" 2>/dev/null || true
2181+
2182+ echo "stage_dir=${STAGE_DIR}" >> "$GITHUB_OUTPUT"
2183+ echo "copied=${copied}" >> "$GITHUB_OUTPUT"
2184+
21402185 # ── Upload generated azuredeploy.json artifact ──────────────────────────
21412186 # If either compile step actually generated a file (and templateHash
21422187 # validation succeeded above), upload it as a workflow artifact keyed by
21432188 # PR number + head SHA. The merge-time `commit-generated-on-merge` job
21442189 # downloads this artifact and commits the JSON to master, so the merged
21452190 # commit contains the generated ARM template.
21462191 #
2147- # Files are uploaded preserving their repo-relative path so the merge
2148- # job can copy them straight back into a fresh master checkout.
2192+ # Uploading the staged directory (rather than the original files
2193+ # directly) preserves the repo-relative paths end-to-end — see the
2194+ # stage-generated step above for the rationale.
21492195 - name : Upload generated azuredeploy.json artifact
21502196 if : >-
21512197 steps.preflight.outputs.skip != 'true' &&
2198+ steps.stage-generated.outputs.copied != '0' &&
21522199 (steps.compile-main.outputs.generated == 'true' ||
21532200 steps.compile-prereqs.outputs.generated == 'true')
21542201 uses : actions/upload-artifact@v4
21552202 with :
21562203 name : generated-azuredeploy-${{ steps.pr.outputs.number }}-${{ steps.pr.outputs.head_sha }}
2157- path : |
2158- ${{ steps.find-metadata.outputs.sample_path }}/azuredeploy.json
2159- ${{ steps.find-metadata.outputs.sample_path }}/prereqs/azuredeploy.json
2160- ${{ steps.find-metadata.outputs.sample_path }}/prereqs/prereq.azuredeploy.json
2204+ path : ${{ steps.stage-generated.outputs.stage_dir }}
21612205 if-no-files-found : ignore
21622206 retention-days : 7
21632207 include-hidden-files : false
@@ -2468,6 +2512,13 @@ jobs:
24682512 # is safe and cannot pick up unrelated changes.
24692513 git add -A -- '**/azuredeploy.json' '**/prereq.azuredeploy.json' || true
24702514
2515+ # Safety net: a buggy artifact (e.g. one whose paths got collapsed
2516+ # to the artifact root) could land a bare azuredeploy.json or
2517+ # prereq.azuredeploy.json at the repository root. Those two files
2518+ # never legitimately live at the repo root, so unstage them if
2519+ # they somehow got picked up.
2520+ git reset -q -- azuredeploy.json prereq.azuredeploy.json 2>/dev/null || true
2521+
24712522 if git diff --cached --quiet; then
24722523 echo "No changes to commit — generated JSON already matches the merged tree."
24732524 exit 0
0 commit comments