-
Notifications
You must be signed in to change notification settings - Fork 34
chore(dev): add a safe upstream sync workflow #80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| # Keeping local features when upstream updates | ||
|
|
||
| Run the synchronization script from the repository root whenever CodexIsland | ||
| publishes a new version: | ||
|
|
||
| ```bash | ||
| ./scripts/sync-upstream.sh | ||
| ``` | ||
|
|
||
| The script fetches `origin/main`, creates a `codex/backup-before-upstream-*` | ||
| backup branch, merges instead of replacing local history, and runs the test | ||
| suite before committing. To build the app as part of the same operation: | ||
|
|
||
| ```bash | ||
| SYNC_BUILD_APP=1 ./scripts/sync-upstream.sh | ||
| ``` | ||
|
|
||
| If Git reports conflicts, review and stage the resolved files, then run: | ||
|
|
||
| ```bash | ||
| ./scripts/sync-upstream.sh --continue | ||
| ``` | ||
|
|
||
| Use `./scripts/sync-upstream.sh --abort` to return to the exact pre-merge state. | ||
| The backup branch remains available even after a successful merge. | ||
|
|
||
| Local builds intentionally omit the official Sparkle update feed. Otherwise an | ||
| official release could replace the customized binary after a restart. The | ||
| release workflow explicitly enables Sparkle only for official distribution | ||
| builds. Your preferences remain in the normal CodexIsland UserDefaults domain. | ||
|
|
||
| ## 上游更新时保留本地功能 | ||
|
|
||
| CodexIsland 发布新版本后,在项目根目录执行: | ||
|
|
||
| ```bash | ||
| ./scripts/sync-upstream.sh | ||
| ``` | ||
|
|
||
| 脚本会获取 `origin/main`,自动创建 | ||
| `codex/backup-before-upstream-*` 备份分支,通过合并保留本地历史, | ||
| 并在提交前运行测试。如果希望同时构建应用: | ||
|
|
||
| ```bash | ||
| SYNC_BUILD_APP=1 ./scripts/sync-upstream.sh | ||
| ``` | ||
|
|
||
| 如果发生冲突,脚本会停下,不会覆盖任何本地代码。解决冲突并将文件 | ||
| 加入暂存区后,执行: | ||
|
|
||
| ```bash | ||
| ./scripts/sync-upstream.sh --continue | ||
| ``` | ||
|
|
||
| 如果希望取消本次合并,执行 `./scripts/sync-upstream.sh --abort`。 | ||
|
|
||
| 本地定制构建会有意关闭官方 Sparkle 更新源,避免重启后官方原版覆盖定制功能。 | ||
| 只有正式发布脚本才会启用 Sparkle。外观、服务显示和任务提醒等偏好仍保存在 | ||
| CodexIsland 原有的 UserDefaults 中。 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,151 @@ | ||
| #!/bin/bash | ||
| # Merge the latest upstream release into the current customization branch. | ||
| # This script never resets or overwrites local history. It requires a clean | ||
| # worktree, creates a backup branch, and pauses safely when conflicts occur. | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| cd "$(dirname "$0")/.." | ||
|
|
||
| UPSTREAM_REMOTE="${UPSTREAM_REMOTE:-origin}" | ||
| UPSTREAM_BRANCH="${UPSTREAM_BRANCH:-main}" | ||
| ACTION="${1:-sync}" | ||
|
|
||
| usage() { | ||
| cat <<'EOF' | ||
| Usage: | ||
| ./scripts/sync-upstream.sh Fetch, test, and merge upstream/main | ||
| ./scripts/sync-upstream.sh --continue Continue after resolving conflicts | ||
| ./scripts/sync-upstream.sh --abort Abort the current upstream merge | ||
|
|
||
| Optional environment variables: | ||
| UPSTREAM_REMOTE=origin | ||
| UPSTREAM_BRANCH=main | ||
| SYNC_SKIP_TESTS=1 | ||
| SYNC_BUILD_APP=1 | ||
| SYNC_SDKROOT=/path/to/MacOSX.sdk | ||
| EOF | ||
| } | ||
|
|
||
| run_validation() { | ||
| if [[ "${SYNC_SKIP_TESTS:-0}" != "1" ]]; then | ||
| echo "Running tests..." | ||
| local sdk="${SYNC_SDKROOT:-}" | ||
| if [[ -z "$sdk" && -d /Library/Developer/CommandLineTools/SDKs/MacOSX26.sdk ]]; then | ||
| sdk=/Library/Developer/CommandLineTools/SDKs/MacOSX26.sdk | ||
| fi | ||
| if [[ -n "$sdk" ]]; then | ||
| SDKROOT="$sdk" \ | ||
| CLANG_MODULE_CACHE_PATH="${TMPDIR:-/tmp}/codex-island-module-cache" \ | ||
| ./scripts/run-tests.sh | ||
| else | ||
| CLANG_MODULE_CACHE_PATH="${TMPDIR:-/tmp}/codex-island-module-cache" \ | ||
| ./scripts/run-tests.sh | ||
| fi | ||
| fi | ||
|
|
||
| if [[ "${SYNC_BUILD_APP:-0}" == "1" ]]; then | ||
| echo "Building CodexIsland..." | ||
| ./build.sh | ||
| fi | ||
| } | ||
|
|
||
| case "$ACTION" in | ||
| --help|-h) | ||
| usage | ||
| exit 0 | ||
| ;; | ||
| --abort) | ||
| if git rev-parse -q --verify MERGE_HEAD >/dev/null; then | ||
| git merge --abort | ||
| echo "Upstream merge aborted; the pre-sync branch is still available." | ||
| else | ||
| echo "error: no upstream merge is in progress" >&2 | ||
| exit 1 | ||
| fi | ||
| exit 0 | ||
| ;; | ||
| --continue) | ||
| if ! git rev-parse -q --verify MERGE_HEAD >/dev/null; then | ||
| echo "error: no upstream merge is in progress" >&2 | ||
| exit 1 | ||
| fi | ||
| if [[ -n "$(git diff --name-only --diff-filter=U)" ]]; then | ||
| echo "error: unresolved conflicts remain" >&2 | ||
| git diff --name-only --diff-filter=U >&2 | ||
| exit 1 | ||
| fi | ||
| run_validation | ||
| git commit --no-edit | ||
| echo "Upstream merge completed successfully." | ||
| exit 0 | ||
| ;; | ||
| sync) | ||
| ;; | ||
| *) | ||
| usage >&2 | ||
| exit 2 | ||
| ;; | ||
| esac | ||
|
|
||
| if git rev-parse -q --verify MERGE_HEAD >/dev/null; then | ||
| echo "error: a merge is already in progress; use --continue or --abort" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [[ -n "$(git status --porcelain)" ]]; then | ||
| echo "error: commit or stash local changes before syncing" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| current_branch="$(git symbolic-ref --quiet --short HEAD || true)" | ||
| if [[ -z "$current_branch" ]]; then | ||
| echo "error: switch to your customization branch before syncing" >&2 | ||
| exit 1 | ||
| fi | ||
|
|
||
| echo "Fetching ${UPSTREAM_REMOTE}/${UPSTREAM_BRANCH}..." | ||
| git fetch "$UPSTREAM_REMOTE" "$UPSTREAM_BRANCH" --tags | ||
| target="${UPSTREAM_REMOTE}/${UPSTREAM_BRANCH}" | ||
|
|
||
| if git merge-base --is-ancestor "$target" HEAD; then | ||
| echo "Already up to date with ${target}." | ||
| run_validation | ||
| exit 0 | ||
| fi | ||
|
|
||
| stamp="$(date +%Y%m%d-%H%M%S)" | ||
| short_head="$(git rev-parse --short HEAD)" | ||
| backup_branch="codex/backup-before-upstream-${stamp}-${short_head}" | ||
| git branch "$backup_branch" HEAD | ||
| echo "Backup created: ${backup_branch}" | ||
|
|
||
| if ! git merge --no-ff --no-commit "$target"; then | ||
| cat >&2 <<EOF | ||
|
|
||
| The merge paused because conflicts need review. Your local work is safe. | ||
| Resolve the listed files, stage them with git add, then run: | ||
| ./scripts/sync-upstream.sh --continue | ||
|
|
||
| To restore the pre-merge state, run: | ||
| ./scripts/sync-upstream.sh --abort | ||
|
|
||
| Backup branch: ${backup_branch} | ||
| EOF | ||
| exit 1 | ||
| fi | ||
|
|
||
| if ! run_validation; then | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a clean merge causes Useful? React with 👍 / 👎. |
||
| cat >&2 <<EOF | ||
|
|
||
| Validation failed, so the merge has not been committed. | ||
| Fix the issue and run ./scripts/sync-upstream.sh --continue, | ||
| or run ./scripts/sync-upstream.sh --abort. | ||
| Backup branch: ${backup_branch} | ||
| EOF | ||
| exit 1 | ||
| fi | ||
|
|
||
| git commit --no-edit | ||
| echo "Merged ${target} into ${current_branch}." | ||
| echo "Backup branch: ${backup_branch}" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| #!/bin/bash | ||
|
|
||
| set -u | ||
|
|
||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| cd "$SCRIPT_DIR" || exit 1 | ||
|
|
||
| clear | ||
| echo "========================================" | ||
| echo " CodexIsland 上游同步与本地构建" | ||
| echo "========================================" | ||
| echo | ||
| echo "将会:" | ||
| echo " 1. 获取官方最新版本" | ||
| echo " 2. 创建本地备份分支" | ||
| echo " 3. 合并更新并保留本地功能" | ||
| echo " 4. 运行测试并构建新应用" | ||
| echo | ||
|
|
||
| if SYNC_BUILD_APP=1 ./scripts/sync-upstream.sh; then | ||
| echo | ||
| echo "✓ 处理完成" | ||
| echo | ||
| echo "应用位置:" | ||
| echo "$SCRIPT_DIR/build/CodexIsland.app" | ||
| echo | ||
| echo "可以打开 build 文件夹查看新版本。" | ||
| else | ||
| status=$? | ||
| echo | ||
| echo "✗ 未能自动完成(错误代码:$status)" | ||
| echo | ||
| if git rev-parse -q --verify MERGE_HEAD >/dev/null 2>&1; then | ||
| echo "检测到合并冲突,本地功能没有被覆盖。" | ||
| echo "解决冲突后可执行:" | ||
| echo " ./scripts/sync-upstream.sh --continue" | ||
| echo | ||
| echo "如需取消这次合并:" | ||
| echo " ./scripts/sync-upstream.sh --abort" | ||
| else | ||
| echo "请查看上方提示;项目文件不会被强制覆盖。" | ||
| fi | ||
| fi | ||
|
|
||
| echo | ||
| read -r -p "按 Enter 键关闭窗口…" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If a user stages a conflict resolution and then adjusts it again—especially after a validation failure—
run_validationtests the newer working-tree contents, butgit commit --no-editrecords the older index contents and still reports success. As confirmed bygit commit -h,-a/--allis the option to “commit all changed files”; this call neither uses it nor verifies that the working tree matches the index, so the resulting merge can differ from what passed validation.Useful? React with 👍 / 👎.