native macOS codings agent orchestrator
6
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add fork sync and personal release workflow docs

onevcat 3599f5f7 d0ec4897

+201
+107
doc-onevcat/fork-sync-and-release.md
··· 1 + # Fork Sync and Personal Release Workflow 2 + 3 + ## Goal 4 + 5 + Keep `onevcat/supacode` close to `supabitapp/supacode` while preserving local customizations (keybindings and feature trims), and make personal releases easy to produce and download from the fork Release page. 6 + 7 + ## Current Release Build in This Repo 8 + 9 + The repository already has two production-grade workflows: 10 + 11 + - `.github/workflows/release.yml` 12 + - Trigger: GitHub Release published. 13 + - Build: `make archive` + `make export-archive` on `macos-26`. 14 + - Packaging: app zip, dmg, Sparkle appcast, delta files. 15 + - Signing/notarization: required (Apple cert + notary credentials). 16 + - Publish target in workflow: hard-coded `supabitapp/supacode`. 17 + - `.github/workflows/release-tip.yml` 18 + - Trigger: push to `main` (and manual dispatch). 19 + - Produces/updates `tip` prerelease assets and appcast. 20 + - Also requires signing/notarization secrets. 21 + 22 + ### Fork Impact 23 + 24 + Out of the box, these workflows are not fork-friendly: 25 + 26 + - They require many signing/secrets that forks usually do not have. 27 + - Stable release publish target is hard-coded to upstream repo (`supabitapp/supacode`). 28 + - Some appcast URLs are hard-coded to `supacode.sh`. 29 + 30 + ## Recommended Branch Strategy 31 + 32 + - `upstream/main`: source of truth (read-only remote branch). 33 + - `main` (origin): your integration branch with custom patches. 34 + - `feat/onevcat-*`: optional short-lived branches per local customization. 35 + 36 + ## One-Time Setup 37 + 38 + ```bash 39 + git fetch origin upstream --prune 40 + git config rerere.enabled true 41 + git config rerere.autoupdate true 42 + ``` 43 + 44 + `rerere` records your conflict resolutions so repeated upstream syncs become easier. 45 + 46 + ## Upstream Sync Runbook (Recommended: Merge) 47 + 48 + ```bash 49 + git switch main 50 + git fetch origin upstream --prune 51 + git pull --ff-only origin main 52 + git merge --no-ff upstream/main 53 + make build-app 54 + make test 55 + git push origin main 56 + ``` 57 + 58 + If conflicts happen, resolve once, commit, and `rerere` will likely auto-apply next time. 59 + 60 + ## Personal Release Strategy (Fork Release Page) 61 + 62 + For personal usage, the easiest path is: 63 + 64 + 1) Build unsigned Debug app locally (`make build-app`). 65 + 2) Zip app bundle. 66 + 3) Create a tag. 67 + 4) Upload zip to your fork GitHub Release page. 68 + 69 + This avoids Apple signing/notarization setup and keeps the workflow simple. 70 + 71 + ## Helper Scripts 72 + 73 + - Sync helper: `doc-onevcat/scripts/sync-upstream-main.sh` 74 + - Release helper: `doc-onevcat/scripts/release-to-fork.sh` 75 + 76 + ### Example 77 + 78 + ```bash 79 + # Sync upstream into local main and verify build 80 + ./doc-onevcat/scripts/sync-upstream-main.sh 81 + 82 + # Create a personal release on fork release page 83 + ./doc-onevcat/scripts/release-to-fork.sh 84 + 85 + # Or specify tag explicitly 86 + ./doc-onevcat/scripts/release-to-fork.sh onevcat-v2026.02.26-01 87 + ``` 88 + 89 + ## Optional: Full Signed Release on Fork 90 + 91 + If you need notarized DMG and Sparkle feed in your fork: 92 + 93 + - Copy/adjust release workflows to publish to `${{ github.repository }}`. 94 + - Replace hard-coded download URL and release-notes URL with fork values. 95 + - Configure all required secrets: 96 + - `DEVELOPER_ID_CERT_P12` 97 + - `DEVELOPER_ID_CERT_PASSWORD` 98 + - `DEVELOPER_ID_IDENTITY` 99 + - `KEYCHAIN_PASSWORD` 100 + - `APPLE_TEAM_ID` 101 + - `APPLE_NOTARIZATION_ISSUER` 102 + - `APPLE_NOTARIZATION_KEY_ID` 103 + - `APPLE_NOTARIZATION_KEY` 104 + - `SPARKLE_PRIVATE_KEY` 105 + - plus telemetry/sentry secrets used by workflow 106 + 107 + For your current goal (personal periodic builds), the unsigned release helper is usually enough.
+69
doc-onevcat/scripts/release-to-fork.sh
··· 1 + #!/usr/bin/env bash 2 + set -euo pipefail 3 + 4 + if ! command -v gh >/dev/null 2>&1; then 5 + echo "error: gh CLI is required" 6 + exit 1 7 + fi 8 + 9 + if ! command -v jq >/dev/null 2>&1; then 10 + echo "error: jq is required" 11 + exit 1 12 + fi 13 + 14 + REPO="$(gh repo view --json nameWithOwner -q .nameWithOwner)" 15 + SHORT_SHA="$(git rev-parse --short HEAD)" 16 + DEFAULT_TAG="onevcat-v$(date +%Y.%m.%d)-${SHORT_SHA}" 17 + TAG="${1:-$DEFAULT_TAG}" 18 + 19 + echo "[release] repository: ${REPO}" 20 + echo "[release] tag: ${TAG}" 21 + 22 + if git rev-parse "${TAG}" >/dev/null 2>&1; then 23 + echo "error: local tag ${TAG} already exists" 24 + exit 1 25 + fi 26 + 27 + echo "[release] build app" 28 + make build-app 29 + 30 + echo "[release] resolve app path from xcodebuild settings" 31 + SETTINGS="$(xcodebuild -project supacode.xcodeproj -scheme supacode -configuration Debug -showBuildSettings -json 2>/dev/null)" 32 + BUILD_DIR="$(echo "$SETTINGS" | jq -r '.[0].buildSettings.BUILT_PRODUCTS_DIR')" 33 + PRODUCT_NAME="$(echo "$SETTINGS" | jq -r '.[0].buildSettings.FULL_PRODUCT_NAME')" 34 + APP_PATH="${BUILD_DIR}/${PRODUCT_NAME}" 35 + 36 + if [ ! -d "${APP_PATH}" ]; then 37 + echo "error: app not found at ${APP_PATH}" 38 + exit 1 39 + fi 40 + 41 + mkdir -p build 42 + ZIP_PATH="build/${PRODUCT_NAME%.app}-${TAG}.app.zip" 43 + NOTES_PATH="build/release-notes-${TAG}.md" 44 + 45 + echo "[release] package ${APP_PATH} -> ${ZIP_PATH}" 46 + ditto -c -k --sequesterRsrc --keepParent "${APP_PATH}" "${ZIP_PATH}" 47 + 48 + UPSTREAM_MAIN_SHA="$(git rev-parse --short upstream/main 2>/dev/null || echo unknown)" 49 + cat > "${NOTES_PATH}" <<EOF 50 + Personal fork build for onevcat. 51 + 52 + - Commit: ${SHORT_SHA} 53 + - Upstream main (local): ${UPSTREAM_MAIN_SHA} 54 + - Build type: Debug (unsigned) 55 + - Branch: $(git branch --show-current) 56 + EOF 57 + 58 + echo "[release] create and push tag ${TAG}" 59 + git tag "${TAG}" 60 + git push origin "${TAG}" 61 + 62 + echo "[release] create GitHub Release and upload asset" 63 + gh release create "${TAG}" "${ZIP_PATH}" \ 64 + --repo "${REPO}" \ 65 + --title "Personal build ${TAG}" \ 66 + --notes-file "${NOTES_PATH}" 67 + 68 + echo 69 + echo "[done] release created: https://github.com/${REPO}/releases/tag/${TAG}"
+25
doc-onevcat/scripts/sync-upstream-main.sh
··· 1 + #!/usr/bin/env bash 2 + set -euo pipefail 3 + 4 + TARGET_BRANCH="${1:-main}" 5 + 6 + echo "[sync] fetch remotes" 7 + git fetch origin upstream --prune 8 + 9 + echo "[sync] switch to ${TARGET_BRANCH}" 10 + git switch "${TARGET_BRANCH}" 11 + 12 + echo "[sync] fast-forward from origin/${TARGET_BRANCH}" 13 + git pull --ff-only origin "${TARGET_BRANCH}" 14 + 15 + echo "[sync] merge upstream/main into ${TARGET_BRANCH}" 16 + git merge --no-ff upstream/main 17 + 18 + echo "[sync] verify build" 19 + make build-app 20 + 21 + echo 22 + echo "[done] upstream merged into ${TARGET_BRANCH}" 23 + echo "Next recommended steps:" 24 + echo " 1) make test" 25 + echo " 2) git push origin ${TARGET_BRANCH}"