name: Sync models.dev upstream
on:
schedule: [{ cron: "0 */6 * * *" }]
workflow_dispatch: {}
permissions: { contents: write, pull-requests: write }
concurrency:
group: sync-models-dev
cancel-in-progress: false
jobs:
sync:
runs-on: ubuntu-latest
env:
UPSTREAM_REPO: https://github.com/sst/models.dev.git
SYNC_BRANCH: chore/sync-models-dev
BASE_BRANCH: ${{ github.event.repository.default_branch }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- name: Configure git user
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
- name: Determine upstream default branch
id: upstream
run: |
set -euo pipefail
DEFAULT_BRANCH=$(git ls-remote --symref "$UPSTREAM_REPO" HEAD | awk '/^ref:/{gsub("refs/heads/","",$2); print $2; exit}')
echo "default_branch=$DEFAULT_BRANCH" >> "$GITHUB_OUTPUT"
- name: Create/update sync branch from base
run: |
set -euo pipefail
git fetch origin "$BASE_BRANCH":"refs/remotes/origin/$BASE_BRANCH"
git checkout -B "$SYNC_BRANCH" "origin/$BASE_BRANCH"
- name: Pull subtree (squashed)
id: subtree
run: |
set -euo pipefail
BEFORE=$(git rev-parse HEAD)
# Try pulling subtree; if it fails, add it instead
if git subtree pull --prefix=vendor/models.dev "$UPSTREAM_REPO" "${{ steps.upstream.outputs.default_branch }}" --squash -m "chore: sync models.dev upstream"; then
echo "Subtree pulled"
else
git subtree add --prefix=vendor/models.dev "$UPSTREAM_REPO" "${{ steps.upstream.outputs.default_branch }}" --squash -m "chore: sync models.dev upstream"
fi
AFTER=$(git rev-parse HEAD)
if [ "$BEFORE" != "$AFTER" ]; then
echo "has_changes=true" >> "$GITHUB_OUTPUT"
else
echo "has_changes=false" >> "$GITHUB_OUTPUT"
fi
- name: Push branch
if: steps.subtree.outputs.has_changes == 'true'
env:
SYNC_PAT: ${{ secrets.SYNC_PAT }}
run: |
set -euo pipefail
if [ -z "${SYNC_PAT:-}" ]; then
echo "SYNC_PAT is not set. Please add a repo-scoped PAT as secret SYNC_PAT." >&2
exit 1
fi
git remote set-url origin "https://x-access-token:${SYNC_PAT}@github.com/${GITHUB_REPOSITORY}.git"
git push --force-with-lease origin "$SYNC_BRANCH"
- name: Open or update PR
if: steps.subtree.outputs.has_changes == 'true'
uses: actions/github-script@v7
env:
SYNC_BRANCH: ${{ env.SYNC_BRANCH }}
BASE_BRANCH: ${{ env.BASE_BRANCH }}
with:
github-token: ${{ secrets.SYNC_PAT }}
script: |
const { owner, repo } = context.repo;
const head = `${owner}:${process.env.SYNC_BRANCH}`;
const base = process.env.BASE_BRANCH;
const title = 'chore: sync models.dev upstream';
const body = 'Automated subtree sync from upstream.';
const existing = await github.rest.pulls.list({ owner, repo, state: 'open', head, base, per_page: 1 });
if (existing.data.length > 0) {
core.info(`PR already exists: ${existing.data[0].html_url}`);
} else {
const pr = await github.rest.pulls.create({ owner, repo, head, base, title, body });
await github.rest.issues.addLabels({ owner, repo, issue_number: pr.data.number, labels: ['upstream-sync'] }).catch(() => {});
core.info(`Created PR: ${pr.data.html_url}`);
}