Sync screenpipe fork #57
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Sync screenpipe fork | |
| # Keeps AnkushMalaker/screenpipe's `chronicle` branch rebased directly onto | |
| # upstream screenpipe/screenpipe main. The branch carries Chronicle's complete | |
| # patch stack; the former `custom/linux-timeline-stability` base branch was | |
| # folded into it and deleted in August 2026. | |
| # | |
| # This lives in chronicle rather than in the fork itself for two reasons: | |
| # `schedule` only fires from a repo's default branch, so hosting it in the fork | |
| # would permanently diverge that fork's main from upstream; and GitHub disables | |
| # scheduled workflows in forked repositories, which would stop the sync | |
| # silently. | |
| # Maintenance and conflict-recovery runbook: docs/screenpipe-fork-sync.md. | |
| on: | |
| schedule: | |
| # 04:00 UTC daily — well clear of the local build window. | |
| - cron: "0 4 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| push: | |
| # Compared against the string 'false' as well as boolean false at the | |
| # use site: `gh workflow run -f push=false` sends the *string* "false", | |
| # and a non-empty string is truthy in GitHub expressions, so a naive | |
| # `if: inputs.push` would force-push when asked not to. Use -F (capital) | |
| # to send a real boolean, but the guard does not rely on that. | |
| description: "Push the rebased branch to the fork" | |
| type: boolean | |
| default: true | |
| permissions: | |
| contents: read | |
| issues: write | |
| env: | |
| FORK: AnkushMalaker/screenpipe | |
| UPSTREAM: https://github.com/screenpipe/screenpipe | |
| jobs: | |
| rebase: | |
| name: Rebase chronicle onto upstream/main | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Check out the fork's Chronicle branch | |
| uses: actions/checkout@v4 | |
| with: | |
| repository: ${{ env.FORK }} | |
| ref: chronicle | |
| # Full history: a rebase needs the merge base with its target, which a | |
| # shallow clone does not have. | |
| fetch-depth: 0 | |
| token: ${{ secrets.SCREENPIPE_FORK_TOKEN }} | |
| persist-credentials: true | |
| - name: Fetch the rebase target | |
| run: | | |
| git remote add upstream "$UPSTREAM" | |
| # Only main: upstream carries hundreds of agent/* branches. | |
| git fetch --no-tags upstream main | |
| - name: Report divergence | |
| id: diverge | |
| env: | |
| ONTO: upstream/main | |
| run: | | |
| base=$(git merge-base HEAD "$ONTO") | |
| behind=$(git rev-list --count "$base".."$ONTO") | |
| ours=$(git rev-list --count "$base"..HEAD) | |
| echo "behind=$behind" >>"$GITHUB_OUTPUT" | |
| echo "ours=$ours" >>"$GITHUB_OUTPUT" | |
| echo "$behind new commit(s) on $ONTO; $ours local commit(s) on top" | |
| - name: Rebase | |
| id: rebase | |
| if: steps.diverge.outputs.behind != '0' | |
| env: | |
| ONTO: upstream/main | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| if git rebase "$ONTO"; then | |
| echo "clean=true" >>"$GITHUB_OUTPUT" | |
| else | |
| git rebase --abort || true | |
| echo "clean=false" >>"$GITHUB_OUTPUT" | |
| echo "::warning::rebase hit conflicts; leaving the fork untouched" | |
| fi | |
| - name: Push rebased branch | |
| if: | | |
| steps.rebase.outputs.clean == 'true' && | |
| (github.event_name == 'schedule' || | |
| (inputs.push && inputs.push != 'false')) | |
| env: | |
| BRANCH: chronicle | |
| run: | | |
| # --force-with-lease, never plain --force: the rebase rewrote history, | |
| # but this still refuses if the branch moved since checkout (e.g. a | |
| # local push landed while this job was running). | |
| git push --force-with-lease origin "HEAD:$BRANCH" | |
| - name: Open an issue on conflict | |
| if: steps.rebase.outputs.clean == 'false' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| BEHIND: ${{ steps.diverge.outputs.behind }} | |
| BRANCH: chronicle | |
| ONTO: upstream/main | |
| run: | | |
| title="screenpipe fork: $BRANCH needs manual conflict resolution" | |
| # Reuse one open issue rather than filing a new one every night. | |
| existing=$(gh issue list --repo "$GITHUB_REPOSITORY" \ | |
| --state open --search "$title in:title" --json number --jq '.[0].number') | |
| body=$(printf '%s\n' \ | |
| "\`$BRANCH\` no longer rebases cleanly onto \`$ONTO\` ($BEHIND commits behind)." \ | |
| "" \ | |
| "The fork was left untouched. Resolve it locally:" \ | |
| "" \ | |
| '```' \ | |
| "cd untracked/screenpipe && SYNC_BRANCH=$BRANCH ./sync-fork.sh" \ | |
| "# fix conflicts, then: git add <files> && git rebase --continue" \ | |
| "SYNC_BRANCH=$BRANCH ./sync-fork.sh --push" \ | |
| '```' \ | |
| "" \ | |
| "Run: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID") | |
| if [ -n "$existing" ]; then | |
| gh issue comment "$existing" --repo "$GITHUB_REPOSITORY" --body "$body" | |
| else | |
| gh issue create --repo "$GITHUB_REPOSITORY" --title "$title" --body "$body" | |
| fi |