diff --git a/.github/workflows/open-model-release-pr.yml b/.github/workflows/open-model-release-pr.yml new file mode 100644 index 0000000..793c915 --- /dev/null +++ b/.github/workflows/open-model-release-pr.yml @@ -0,0 +1,59 @@ +name: Open model-release PR + +# The daily model-release watch runs in a scheduled Claude session, which can +# push a branch but cannot open a pull request: the GitHub API access an +# interactive session has is not passed through to a scheduled one, and the +# container's git credentials are scoped to git transport only. So the branch +# arrives here with nothing behind it and this workflow opens the PR. +# +# The pushing session has no way to set a title and body either, so it puts +# them in the commit message — subject becomes the PR title, body becomes the +# PR body. Keep that contract in step with the routine's prompt. + +on: + push: + branches: + - "claude/model-release-**" + +permissions: + contents: read + pull-requests: write + +concurrency: + group: open-model-release-pr-${{ github.ref }} + cancel-in-progress: false + +jobs: + open-draft-pr: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Open a draft PR if the branch has none + env: + GH_TOKEN: ${{ github.token }} + BRANCH: ${{ github.ref_name }} + BASE: ${{ github.event.repository.default_branch }} + run: | + set -euo pipefail + + if [ "$(gh pr list --head "$BRANCH" --state open --json number --jq 'length')" != "0" ]; then + echo "An open PR already exists for $BRANCH — leaving it alone." + exit 0 + fi + + title=$(git log -1 --pretty=%s) + + # Commit trailers are bookkeeping, not PR prose. + { + git log -1 --pretty=%b | sed -E '/^(Co-Authored-By|Claude-Session):/d' + printf '\n---\n\nOpened automatically from `%s` by the daily model-release watch.\n' "$BRANCH" + printf 'The companion change is on the same branch name in the other repository.\n' + } > /tmp/pr-body.md + + gh pr create \ + --draft \ + --base "$BASE" \ + --head "$BRANCH" \ + --title "$title" \ + --body-file /tmp/pr-body.md