name: sync-project-tree # Keeps this repo's file-layout snapshot (docs/link/PROJECT_TREE.md in the # RunicGateway/docs repo) current. On every push to `main` it regenerates the # tree from tracked files and, if it changed, opens (or force-updates) a pull # request against the docs repo. It never writes to the docs repo's `main` # directly. Auth reuses the same REGISTRY_USER / REGISTRY_TOKEN secrets the # other workflows use (the token needs repo read/write on RunicGateway/docs). on: push: branches: [main] workflow_dispatch: {} concurrency: group: sync-project-tree cancel-in-progress: true env: GITEA_HOST: gitea.whitlocktech.com DOCS_REPO: RunicGateway/docs SELF_REPO: RunicGateway/link DOCS_PATH: link/PROJECT_TREE.md TREE_TITLE: uo-link ROOT_LABEL: link PR_BRANCH: chore/sync-link-tree jobs: sync: runs-on: ubuntu-latest steps: - name: Check out this repo uses: actions/checkout@v4 with: fetch-depth: 1 - name: Ensure python3 is available run: | set -euo pipefail command -v python3 >/dev/null 2>&1 || { sudo apt-get update -qq && sudo apt-get install -y -qq python3; } - name: Render PROJECT_TREE.md from tracked files run: | set -euo pipefail mkdir -p _sync { printf '# %s — Project Tree\n\n' "${TREE_TITLE}" printf '> **Auto-generated.** This file is maintained by the `sync-project-tree` CI workflow in\n' printf '> the [`%s`](https://%s/%s) repository, which\n' "${SELF_REPO}" "${GITEA_HOST}" "${SELF_REPO}" printf '> opens a pull request here whenever the tracked file layout on `main` changes. Do not edit\n' printf '> by hand — changes will be overwritten by the next sync.\n\n' printf 'A snapshot of the tracked files in the repository (build output, dependencies, and other\n' printf 'git-ignored paths are excluded).\n\n' printf '```text\n' git ls-files | python3 .gitea/scripts/gen_tree.py "${ROOT_LABEL}" printf '```\n' } > _sync/PROJECT_TREE.md echo "----- generated ${DOCS_PATH} -----" cat _sync/PROJECT_TREE.md - name: Open or update the docs PR if the tree changed env: REGISTRY_USER: ${{ secrets.REGISTRY_USER }} REGISTRY_TOKEN: ${{ secrets.REGISTRY_TOKEN }} run: | set -euo pipefail # Secrets can carry a trailing CR/LF depending on how they were pasted; # strip line breaks before they land in a URL or Authorization header. CI_USER="$(printf '%s' "${REGISTRY_USER}" | tr -d '\r\n')" CI_TOKEN="$(printf '%s' "${REGISTRY_TOKEN}" | tr -d '\r\n')" API="https://${GITEA_HOST}/api/v1/repos/${DOCS_REPO}" REMOTE="https://${CI_USER}:${CI_TOKEN}@${GITEA_HOST}/${DOCS_REPO}.git" git clone --depth 1 "${REMOTE}" docs_repo cd docs_repo git config user.name "runic-docs-bot" git config user.email "ci@whitlocktech.com" mkdir -p "$(dirname "${DOCS_PATH}")" cp ../_sync/PROJECT_TREE.md "${DOCS_PATH}" git add "${DOCS_PATH}" if git diff --cached --quiet; then echo "PROJECT_TREE.md already up to date — nothing to sync." exit 0 fi SHORT_SHA="$(echo "${GITHUB_SHA:-local}" | cut -c1-7)" git checkout -B "${PR_BRANCH}" git commit -m "docs(tree): sync ${DOCS_PATH} from ${SELF_REPO}@${SHORT_SHA} [skip ci]" git push --force "${REMOTE}" "HEAD:${PR_BRANCH}" # Open a PR only if one isn't already open for this branch (a force-push # to an existing open PR's head updates it in place). OPEN="$(curl -sSf -H "Authorization: token ${CI_TOKEN}" \ "${API}/pulls?state=open&limit=50" \ | jq --arg b "${PR_BRANCH}" '[.[] | select(.head.ref == $b)] | length')" if [ "${OPEN}" = "0" ]; then curl -sSf -X POST "${API}/pulls" \ -H "Authorization: token ${CI_TOKEN}" \ -H "Content-Type: application/json" \ -d "$(jq -n \ --arg head "${PR_BRANCH}" \ --arg base "main" \ --arg title "docs(tree): sync ${DOCS_PATH}" \ --arg body "Automated project-tree sync from [\`${SELF_REPO}\`](https://${GITEA_HOST}/${SELF_REPO}), regenerated from tracked files on \`main\`. Merge once the layout looks right; the workflow will keep this branch current until then." \ '{head: $head, base: $base, title: $title, body: $body}')" \ >/dev/null echo "Opened a new docs PR for ${PR_BRANCH}." else echo "Existing open docs PR for ${PR_BRANCH} was updated via force-push." fi