11#! /usr/bin/env bash
2- # sync-examples.sh — Pushes each examples/<name>/ as a snapshot to robotmk/example-<name>
3- # and each labs/<name>/ as a snapshot to robotmk/<name>.
2+ # sync-examples.sh — Pushes each examples/<name>/ as a snapshot to robotmk/example-<name>,
3+ # each labs/<name>/ as a snapshot to robotmk/lab-<name>,
4+ # and each os/<slug>/ as a snapshot to robotmk/os-<slug>.
45#
56# Requires:
67# - GH_TOKEN env var with a PAT that has Contents+Administration write on the robotmk org
78# - gh CLI (available on GitHub Actions runners)
89# - git configured with user.name and user.email
910#
1011# Usage:
11- # .github/scripts/sync-examples.sh [<example-name>] [--lab <lab-name>]
12+ # .github/scripts/sync-examples.sh [<example-name>] [<lab-name>] [<os-slug >]
1213
1314set -euo pipefail
1415
1516SCRIPT_DIR=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) " && pwd) "
1617REPO_ROOT=" $( cd " ${SCRIPT_DIR} /../.." && pwd) "
1718EXAMPLES_DIR=" ${REPO_ROOT} /examples"
1819LABS_DIR=" ${REPO_ROOT} /labs"
20+ OS_DIR=" ${REPO_ROOT} /os"
1921ORG=" robotmk"
2022EXAMPLE_FILTER=" ${1:- } "
2123LAB_FILTER=" ${2:- } " # passed as second arg from workflow (--lab value handled by caller)
24+ OS_FILTER=" ${3:- } "
2225SOURCE_SHA=" ${GITHUB_SHA:- $(git -C " ${REPO_ROOT} " rev-parse HEAD)} "
2326SOURCE_REPO=" ${GITHUB_REPOSITORY:- elabit/ robotmk-starter} "
2427
@@ -31,6 +34,7 @@ EXCLUDE=(
3134 " output.xml"
3235 " browser"
3336 " playwright-log.txt"
37+ " report.md"
3438)
3539
3640# ─── Helper ──────────────────────────────────────────────────────────────────
@@ -101,6 +105,20 @@ build_lab_footer() {
101105EOF
102106}
103107
108+ build_os_footer () {
109+ local slug=" $1 "
110+ cat << EOF
111+ > ---
112+ >
113+ > **This repository is automatically synced from [${SOURCE_REPO} ](https://github.com/${SOURCE_REPO} /tree/main/os/${slug} ).**
114+ > Do not edit files here directly — changes will be overwritten on the next sync.
115+ > Last sync: [\` ${SOURCE_SHA: 0: 7} \` ](https://github.com/${SOURCE_REPO} /commit/${SOURCE_SHA} )
116+
117+ ---
118+
119+ EOF
120+ }
121+
104122prepare_workdir () {
105123 local repo=" $1 "
106124 local tmpdir=" $2 "
@@ -244,6 +262,61 @@ sync_lab() {
244262 rm -rf " ${tmpdir} "
245263}
246264
265+ sync_os () {
266+ local name=" $1 "
267+ local src=" ${OS_DIR} /${name} "
268+ local repo=" ${ORG} /os-${name} "
269+ local tmpdir
270+ tmpdir=" $( mktemp -d) "
271+
272+ echo " "
273+ echo " ══ Syncing os ${name} → ${repo} ══"
274+
275+ ensure_repo " ${repo} " " Robotmk OS install verification target (synced from ${SOURCE_REPO} )"
276+
277+ local repo_id
278+ repo_id=" $( gh api " repos/${repo} " --jq ' .id' ) "
279+ echo " ✓ Repo ID: ${repo_id} "
280+
281+ local has_devcontainer=" false"
282+ [[ -d " ${src} /.devcontainer" ]] && has_devcontainer=" true"
283+
284+ # Prepare workdir: fetch existing content or init empty for brand-new repos
285+ prepare_workdir " ${repo} " " ${tmpdir} "
286+
287+ # Wipe tracked content so we do a clean snapshot
288+ if git -C " ${tmpdir} " rev-parse HEAD & > /dev/null; then
289+ git -C " ${tmpdir} " rm -rf . --quiet
290+ fi
291+
292+ rsync -a " ${src} /" " ${tmpdir} /"
293+
294+ for item in " ${EXCLUDE[@]} " ; do
295+ rm -rf " ${tmpdir:? } /${item} "
296+ done
297+
298+ # README.md is committed and static (Copier-rendered at generate time, see
299+ # _dev/_shared/README-os.md.jinja) -- unlike examples/labs it isn't
300+ # generated by a separate build step, so it's already present in ${src}.
301+ if [[ -f " ${tmpdir} /README.md" ]]; then
302+ prepend_header " ${tmpdir} /README.md" " $( build_header " ${name} " " ${repo_id} " " ${has_devcontainer} " ) "
303+ append_footer " ${tmpdir} /README.md" " $( build_os_footer " ${name} " ) "
304+ else
305+ echo " ❌ No README.md found — skipping header/footer injection."
306+ fi
307+
308+ git -C " ${tmpdir} " add -A
309+ if git -C " ${tmpdir} " diff --cached --quiet; then
310+ echo " No changes — skipping push."
311+ else
312+ git -C " ${tmpdir} " commit -m " sync: from ${SOURCE_REPO} @${SOURCE_SHA: 0: 7} "
313+ git -C " ${tmpdir} " push -u origin main
314+ echo " ✓ Pushed."
315+ fi
316+
317+ rm -rf " ${tmpdir} "
318+ }
319+
247320# ─── Main ────────────────────────────────────────────────────────────────────
248321
249322echo " === Syncing examples/ ==="
@@ -265,5 +338,16 @@ if [[ -d "${LABS_DIR}" ]]; then
265338 done
266339fi
267340
341+ echo " "
342+ echo " === Syncing os/ ==="
343+ if [[ -d " ${OS_DIR} " ]]; then
344+ for dir in " ${OS_DIR} " /* /; do
345+ name=" $( basename " ${dir} " ) "
346+ if [[ -z " ${OS_FILTER} " || " ${name} " == " ${OS_FILTER} " ]]; then
347+ sync_os " ${name} "
348+ fi
349+ done
350+ fi
351+
268352echo " "
269353echo " Sync complete."
0 commit comments