diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..ef54d17 --- /dev/null +++ b/README.en.md @@ -0,0 +1,336 @@ +# GitHub Toolkit + +
+ ð¡ïž Production-Ready GitHub Fork Safety Maintenance & Release Asset Synchronization Toolkit
+ Zero external dependencies · Defense-in-depth safety guardrails · Automatic restore points · Release asset mirroring & smart latest.json rewriting
+
+ ç®äœäžæ | English +
+ +--- + +## Why GitHub Toolkit? + +When maintaining open-source forks for internal customizations, security hardening, custom CI builds, or domestic network mirrors, developers and platform teams frequently encounter critical challenges: + +- **GitHub's native "Sync fork" lacks safety guardrails**: GitHub's web UI blindly executes a merge. If upstream gets wiped, compromised, or mistakenly deletes core directories (e.g., `.github/`, `README`, or `LICENSE`), native sync propagates the disaster directly into your fork, destroying your customizations. +- **No recovery checkpoint**: Native synchronization directly overwrites the default branch without creating a backup, leaving recovery dependent on searching through Git reflogs. +- **Release assets are completely left behind**: Git only synchronizes code commits, never GitHub Releases. When upstream publishes new installer packages (`.exe`, `.dmg`, `.tar.gz`, `.deb`), your fork's releases remain empty. Client auto-updaters relying on `latest.json` continue pointing to upstream URLs instead of your mirror. +- **Third-party Marketplace Actions carry severe supply-chain risks**: Most community fork-sync actions require personal access tokens (PAT) with broad repository write permissions, exposing organizations to credential leakage and supply chain attacks. + +**GitHub Toolkit** is engineered to eliminate these pain points. Built with 100% Python standard library and the official GitHub CLI (`gh`), it delivers defense-in-depth safety circuit breakers, full-batch non-mutating preflight checks, automated moving restore points (`backup/pre-sync`), release asset mirroring, and smart `latest.json` URL rewriting with checksum manifest synchronization. + +--- + +## Feature Comparison Matrix + +| Feature | GitHub Web "Sync fork" | Community Marketplace Actions | GitHub Toolkit | +| :--- | :---: | :---: | :---: | +| **Batch Multi-Fork Discovery** | â Manual click per repo | â Configured per repo | â **Automatic concurrent account discovery** | +| **Upstream Wipeout Protection** | â Blind merge | â None | â **Immediate abort if files drop < 50%** | +| **Mass-Deletion Protection** | â Uncapped | â Uncapped | â **Dynamic deletion budget ceiling** | +| **Critical Path Deletion Guard** | â None | â None | â **Guards `.github/`, `README`, `LICENSE`** | +| **API Truncation Guard** | â None | â None | â **Aborts on 300-entry compare payload** | +| **Automatic Restore Checkpoint** | â None | â None | â **Refreshes `backup/pre-sync` before write** | +| **Full-Batch Preflight Validation** | â None | â None | â **Any failure halts the entire batch** | +| **Release Asset Mirroring** | â None | â None | â **Mirrors binaries, signatures & manifests** | +| **`latest.json` URL Rewriting** | â None | â None | â **Rewrites download URLs to fork domain** | +| **Checksum Manifest Recalculation** | â None | â None | â **Recalculates SHA256/512 and uploads bundle** | +| **Proven Mirror Asset Pruning** | â None | â None | â **Safely prunes old mirrors, retains custom assets** | +| **Supply Chain Safety** | Official GitHub feature | Untrusted 3rd-party images/scripts | â **100% Python stdlib + official `gh` CLI** | + +--- + +## Safe Sync Pipeline Architecture + +Every default branch synchronization strictly follows a six-stage defensive pipeline: + +```text + ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ + â 1. Fresh Runtime Discovery â + â Fetches forks, upstreams, and default branches live â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 2. Full-Batch Preflight Check â + â Simulates all safety checks before any writes start â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 3. Defense-in-Depth Safety Guardrails â + â ⢠Upstream file count < 50% of fork â Safety abort â + â ⢠Deletions > dynamic budget (5 + files/10) â Abort â + â ⢠Deletion of .github/, README, LICENSE â Abort â + â ⢠Compare diff reaches 300 entries â Truncate abort â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 4. Moving Restore Point Checkpoint â + â Forces backup/pre-sync branch to current fork HEAD â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 5. Merge Upstream & Convergence Verification â + â Calls merge-upstream, re-checks behind_by == 0 â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 6. Release Asset Convergence â + â Mirrors binaries, rewrites latest.json, updates â + â checksums, and safely prunes proven mirror assets â + ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ +``` + +--- + +## 30-Second Quick Start + +### 1. Prerequisites + +Requires Python 3.11+ and the official [GitHub CLI (`gh`)](https://cli.github.com/): + +```powershell +# Windows users can install via winget +winget install --id GitHub.cli --source winget + +# Authenticate GitHub account +gh auth login +``` + +> **Credential Precedence**: In CI/automation environments, `GH_TOKEN` takes precedence over `GITHUB_TOKEN`. For local interactive use, the CLI transparently uses your `gh auth login` keychain. Tokens are never logged or stored in plain text. + +### 2. Essential Commands + +#### â List All Fork Repositories and Status (Read-Only) + +```powershell +# Format output as clean console table +python list-forks.py + +# Output structured JSON (for automation pipelines or dashboards) +python list-forks.py --json +``` + +Example output: + +```text +Fork repos for your-name (3 total): + +Discovery: live_github_api /user/repos at 2026-10-25T12:00:00Z (repos=12, forks=3) + +Repository Branch Upstream Behind Workflow +------------------------------------------------------------------------------------------------------- +my-awesome-fork main upstream-org/my-awesome-fork 2 Installed +devtools-mirror master original/devtools-mirror 0 Missing +cockpit-custom main cockpit-project/cockpit Unknown Installed +``` + +#### â¡ Dry-Run Preview + +Always preview planned changes before applying real writes: + +```powershell +# Preview sync for all forks in the account +python sync-forks.py --dry-run + +# Preview sync for a single repository +python sync-forks.py my-awesome-fork --dry-run +``` + +#### ⢠Execute Safe Synchronization + +```powershell +# Synchronize all forks +python sync-forks.py + +# Synchronize specific forks (accepts repo-name or owner/repo-name) +python sync-forks.py my-awesome-fork other-owner/another-fork +``` + +#### ⣠Batch Install or Update Sync Workflows + +Deploy or non-destructively upgrade managed `sync-fork.yml` workflows across all forks: + +```powershell +# Preview workflow changes +python sync-forks.py --add-workflow --dry-run + +# Apply workflow installation +python sync-forks.py --add-workflow +``` + +#### †Audit Scheduled Workflow Readiness & Secrets + +```powershell +python sync-forks.py --verify-schedule +``` + +#### ⥠Mirror and Reconcile Release Assets + +```powershell +# Audit release mirror differences (read-only) +python sync-forks.py --verify-releases + +# Dry-run asset reconciliation +python sync-forks.py --sync-releases --dry-run + +# Apply release synchronization +python sync-forks.py --sync-releases my-awesome-fork +``` + +--- + +## Command-Line Reference + +### 1. `list-forks.py` + +| Flag | Description | +| :--- | :--- | +| *(none)* | Print table of all account forks, upstream delta, and workflow status | +| `--json` | Emit machine-readable JSON including auth principal, discovery metadata, and per-repo rows | +| `-h, --help` | Display command help | + +> **Strict State Integrity**: When API limits or permissions prevent verification, the tool reports `Unknown` with precise error diagnostics rather than falsely claiming `Missing`. + +### 2. `sync-forks.py` + +| Option / Flag | Category | Description | +| :--- | :---: | :--- | +| `[repo-name ...]` | Target Selection | Specify one or more repositories (`repo` or `owner/repo`), deduplicated preserving order; omit to target all forks | +| `--dry-run` | Simulation | Execute all real API discovery and safety checks without modifying GitHub state | +| `--add-workflow` | Workflow Deployment | Create or update `.github/workflows/sync-fork.yml` across targeted forks | +| `--verify-schedule` | Audit | Verify workflow installation, `SYNC_PAT` secret presence, and scheduled run histories | +| `--verify-releases` | Audit | Compare upstream vs fork stable release assets and retention policies | +| `--sync-releases` | Reconciliation | Mirror stable binaries, rewrite `latest.json`, and prune proven old mirror assets | +| `--force` | Force Override | Bypass safety checks or force workflow rewrite (requires explicit confirmation env var) | +| `--json` | Output Control | Emit detailed JSON report with run summary, preflight status, and per-repo results | +| `-h, --help` | Help | Display CLI help and examples | + +### 3. Force Write Acknowledgement (`--force`) + +To prevent catastrophic accidental writes, real mutating runs using `--force` require explicit environment acknowledgement: + +```powershell +# PowerShell +$env:SYNC_FORKS_FORCE_ACK = "I_UNDERSTAND" +python sync-forks.py --force + +# Windows CMD +set SYNC_FORKS_FORCE_ACK=I_UNDERSTAND +python sync-forks.py --force + +# Linux / macOS Bash +SYNC_FORKS_FORCE_ACK=I_UNDERSTAND python3 sync-forks.py --force +``` + +### 4. Exit Code Contract + +Scripts strictly adhere to deterministic exit codes for reliable CI/CD pipeline integration: + +- `0`: Operation succeeded, or no changes required. +- `1`: CLI unavailable, invalid credentials, GitHub API error, or CLI argument syntax error; also returned if `list-forks.py` encountered incomplete repo checks. +- `3`: Safety circuit breaker triggered, or read-only audit discovered pending actions requiring manual or mutating follow-up. + +--- + +## Release Asset Synchronization & Rewriting + +Modern desktop applications (e.g., built with Tauri or Electron) rely on GitHub Releases for binary distribution and automatic updates. Standard Git forks only sync code branches, leaving release mirrors empty. + +`--sync-releases` provides a complete, automated mirroring solution: + +```text +Upstream Release (v1.2.0) Fork Release (v1.2.0) + âââ app-setup.exe âââ Mirror ââââââ⺠âââ app-setup.exe + âââ app-setup.dmg âââ Mirror ââââââ⺠âââ app-setup.dmg + âââ latest.json âââ Rewrite âââââ⺠âââ latest.json (URL rewritten to Fork repository) + âââ SHA256SUMS.txt âââ Recalculate â⺠âââ SHA256SUMS.txt (Manifest updated with new hash) +``` + +1. **Whitelisted Asset Matching**: Matches binary installers (`.exe`, `.msi`, `.deb`, `.rpm`, `.appimage`, `.dmg`, `.pkg`, `.zip`, `.tar.gz`), signatures (`.sig`, `.minisig`), and checksum manifests (`sha256sums*`, `sha512sums*`, `latest.json`). +2. **`latest.json` URL Rewriting**: Automatically rewrites upstream release download URLs to point to your fork repository. +3. **Manifest Recalculation**: Automatically updates `SHA256SUMS.txt` or `SHA512SUMS.txt` with the newly computed digest for `latest.json`. +4. **Atomic Bundle Upload**: Uploads `latest.json` and checksum manifests together to avoid windowed verification failures. +5. **Asset Name Sanitation**: Rejects unsafe names containing path separators (`/`, `\`), NUL bytes (`\0`), directory traversal (`..`), or leading flag hyphens (`-`). +6. **Safe Mirror Pruning**: Prunes only assets rigorously proven to be upstream mirrors (matching name + digest or name + size). **Custom tags and user-uploaded fork assets are never touched.** + +--- + +## GitHub Actions Automated Operations + +The repository includes three complementary GitHub Actions workflows: + +- **`ci.yml`**: Runs all 58 unit tests on push and pull requests in < 0.1s. +- **`auto-setup-forks.yml`**: Runs weekly on Sunday and on template updates to automatically deploy `sync-fork.yml` to all current and newly created forks. +- **`integration-api-smoke.yml`**: Runs weekly on Monday using dedicated read-only credentials to verify live GitHub API compatibility. + +### Repository Secrets Configuration + +Configure these repository secrets for automated maintenance: + +| Secret Name | Required | Description | +| :--- | :---: | :--- | +| `SYNC_PAT` | Yes | Personal Access Token with `repo` and `workflow` scopes, used to commit workflow files and synchronize forks | +| `INTEGRATION_GH_TOKEN` | Optional | Dedicated read-only token for API smoke testing | +| `INTEGRATION_EXPECTED_LOGIN` | Optional | Guard against token principal mismatches | +| `INTEGRATION_TARGET_REPO` | Optional | Specific target fork repository name for dry-run smoke checks | + +--- + +## Disaster Recovery & Rollback Guide + +If an upstream repository suffered corruption that bypassed safety rules (or if `--force` was used), restore your fork within seconds: + +```bash +# 1. Navigate to your local fork directory +cd path/to/your-fork + +# 2. Fetch the automatic backup checkpoint branch +git fetch origin backup/pre-sync + +# 3. Inspect commits in the backup branch +git log -n 5 origin/backup/pre-sync + +# 4. Reset default branch to pre-sync state +git checkout main +git reset --hard origin/backup/pre-sync + +# 5. Force-push to restore remote fork state +git push origin main --force +``` + +--- + +## Development & Testing + +Run the full unit test suite locally (zero third-party dependencies, runs in ~0.08s): + +```powershell +python -m unittest -q test_toolkit.py +``` + +Test coverage highlights: +- GitHub CLI detection and timeout error classification +- Credential resolution and concurrent upstream parent discovery +- Workflow template rendering and drift detection +- 50% file drop, deletion volume limit, and critical file deletion circuit breakers +- Compare 300-entry API truncation protection and moving restore point updates +- Force confirmation environment variable enforcement +- Release asset filtering, URL rewriting, and checksum recalculation +- Mirror provenance validation and safe asset pruning boundaries + +--- + +## License + +Distributed under the [MIT License](https://opensource.org/licenses/MIT). Issues and Pull Requests are warmly welcome! diff --git a/README.md b/README.md index aed28cc..cd8ebec 100644 --- a/README.md +++ b/README.md @@ -1,110 +1,335 @@ # GitHub Toolkit -äžäžªäŸèµ Python æ ååºäž GitHub CLI ç fork 绎æ€å·¥å ·ãå®åªåäžä»¶äºïŒ +
+ ð¡ïž ç产级 GitHub Fork å®å
šç»Žæ€äž Release èµäº§èªåšå忥å¥ä»¶
+ é¶ç¬¬äžæ¹äŸèµ · 纵深é²åŸ¡å®å
šçæ · èªåšå建æ¢å€ç¹ · Release èµäº§éåäž latest.json æºèœæ¹å
+
+ ç®äœäžæ | English +
+ +--- + +## 䞺ä»ä¹éèŠ GitHub ToolkitïŒ + +åšæ¥åžžåŒåäžäŒäžåºç¡è®Ÿæœç»Žæ€äžïŒæä»¬ç»åžžéèŠ Fork åŒæºé¡¹ç®çšäºå éšå®å¶ãå®å šå åºãå®å¶æå»ºææäŸçœç»éåãç¶èç»Žæ€æ°å䞪 Fork åŸåŸé¢äžŽééçç¹ïŒ + +- **GitHub åççœé¡µåæ¥ïŒSync ForkïŒéæ£æå€§**ïŒå®æ¹ Web UI æ¯ç²ç®åå¹¶ãè¥äžæžžä»åºééæ¶ææž 空ïŒWipeïŒãæ¶ææšéå°é»è®€åæ¯ãæå€è¯¯å æä»¶ïŒåŠå é€äº `.github/`ã`README` æ `LICENSE`ïŒïŒåç忥äŒçŽæ¥å°çŸéŸåæ¥è³äœ ç ForkïŒæ¯æææç§¯çޝã +- **猺ä¹çæ¬æ¢å€ä¿é**ïŒåçåå¹¶çŽæ¥èŠçé»è®€åæ¯ïŒäžæŠåºé®é¢åªèœåš reflog äžå€§æµ·æéã +- **Release äºè¿å¶èµäº§å®å šäžåæ¥**ïŒGit åªåæ¥ä»£ç æäº€ïŒäžäŒåæ¥ Releasesãäžæžžååžäºææ°ç `.exe`ã`.dmg`ã`.tar.gz` çå®è£ å ïŒäœ ç Fork Release äŸç¶ç©ºç©ºåŠä¹ïŒå®¢æ·ç«¯èªåšæŽæ°äŸèµç `latest.json` äŸç¶ç¡¬çŒç æåå€éšäžæžžå°åã +- **ç¬¬äžæ¹ Marketplace Actions äŸåºéŸé£é©é«**ïŒåžé¢äžç fork-sync Action å€ç±äžªäººç»Žæ€ïŒéèŠæäºææçåæé PATïŒååšäž¥éç忮倿³äžäŸåºéŸææ¯é£é©ã + +**GitHub Toolkit** äžäžºè§£å³è¿äºé®é¢è讟计ïŒåºäº 100% Python æ ååºäžå®æ¹ GitHub CLI æå»ºïŒæäŸå€å±é²åŸ¡æ§å®å šçæãå šæ¹æ¬¡æ åå ¥ Preflight 颿Œãèªåšå€ä»œæ¢å€ç¹ãRelease èµäº§åæ¥éå以å `latest.json` URL æ¹åäžååžæž åèåšæŽæ°ã + +--- + +## æ žå¿ç¹æ§å¯¹æ¯ + +| åèœç¹æ§ | GitHub çœé¡µ Sync Fork | åžžè§ç¬¬äžæ¹ Action | GitHub Toolkit | +| :--- | :---: | :---: | :---: | +| **å€ä»æ¹éåç°äžç¶æäžè§** | â ä» èœé䞪ç¹å» | â ééä»é 眮 | â **èªåšå¹¶ååç°å šèŽŠå· Fork** | +| **æž ç©ºäžå åºçæä¿æ€** | â ç²ç®åå¹¶ | â æ ä¿æ€ | â **æä»¶æ°çªé 50% ç«å³çæ** | +| **倧æ¹é误å ä¿æ€** | â æ éå¶ | â æ éå¶ | â **åšæå é€é¢ç®äžéæŠæª** | +| **å ³é®è·¯åŸè¯¯å ä¿æ€** | â æ æŠæª | â æ æŠæª | â **ä¿æ€ `.github/`ã`README` ç** | +| **API æªæééžæŠæª** | â æ æ ¡éª | â æ æ ¡éª | â **Compare 蟟 300 æ¡èªåšæŠæª** | +| **忥åèªåšå建æ¢å€ç¹** | â æ å€ä»œ | â æ å€ä»œ | â **åå ¥åæŽæ° `backup/pre-sync`** | +| **å šæ¹æ¬¡ Preflight 颿Œ** | â äžæ¯æ | â äžæ¯æ | â **ä»»äžç®æ åŒåžžå³æŽæ¹äžæ¢** | +| **Release äºè¿å¶éå忥** | â äžæ¯æ | â äžæ¯æ | â **忥å®è£ å ãçŸåäžæ ¡éªæä»¶** | +| **`latest.json` èªåšæŽæ°æ¹å** | â äžæ¯æ | â äžæ¯æ | â **æ¹åäžèœœ URL 䞺 Fork å°å** | +| **æ ¡éªæž åèåšéç®** | â äžæ¯æ | â äžæ¯æ | â **èªåšæŽæ° SHA256/512 å¹¶ååäžäŒ ** | +| **æ§éåèµäº§å®å šæž ç** | â äžæ¯æ | â äžæ¯æ | â **ä» æž çå·²è¯éåïŒä¿çèªå®ä¹èµäº§** | +| **äŸèµå®å šæ§** | 宿¹æå¡ | äŸèµç¬¬äžæ¹éå/èæ¬ | â **100% Python æ ååº + 宿¹ `gh`** | + +--- + +## å®å šåæ¥æµæ°Žçº¿æ¶æ + +æ¯äžæ¬¡é»è®€åæ¯åæ¥åäž¥æ ŒéµåŸªå éé²åŸ¡æ§æµæ°Žçº¿ïŒ + +```text + ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ + â 1. è¿è¡æ¶åšæåç° (Fresh Discovery) â + â éè¿ GitHub API 宿¶è·å Fork äžäžæžžé»è®€åæ¯äžå æ°æ® â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 2. å šæ¹æ¬¡ Preflight 颿Œæ£æ¥ â + â åšäº§çä»»äœåæäœåïŒå¯¹ç®æ ä»åºå®ææ åå ¥å®å šæ¯å¯¹ â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 3. 纵深é²åŸ¡å®å šçæ (Safety Guardrails) â + â â¢ äžæžžæä»¶æ° < Fork 50% â çæäžæ â + â â¢ è¯¯å æä»¶æ° > åšæé é¢ (5 + Fork/10) â çæäžæ â + â ⢠å é€ .github/ãREADMEãLICENSE çå ³é®è·¯åŸ â çæ â + â ⢠GitHub Compare å·®åŒèŸŸ 300 æ¡çäŒŒæªæ â çæ â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 4. èªåšåå»ºç§»åšæ¢å€ç¹ (Restore Point) â + â åšçå® Merge ä¹åïŒèªåšæŽæ°åæ¯ backup/pre-sync â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 5. äžæžžåå¹¶äžæ¶æå€æ ž (Merge & Convergence Verification)â + â è°çš merge-upstreamïŒå次æ¯å¯¹ç¡®ä¿ behind_by == 0 â + ââââââââââââââââââââââââââââ¬ââââââââââââââââââââââââââââââ + â + ââââââââââââââââââââââââââââŒââââââââââââââââââââââââââââââ + â 6. Release èµäº§éåäžæž ç (Release Convergence) â + â æåæ°å®è£ å ãæ¹å latest.jsonãéç®æèŠãæž çæ§éå â + ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ +``` -- `list-forks.py`ïŒåªè¯»ååºåœå莊å·ç forkãäžæžžå·®åŒå忥 workflow ç¶æïŒAPI æ æ³ç¡®è®€æ¶æç¡®æ¥å `Unknown`ïŒäžäŒªè£ æ `Missing`ã -- `sync-forks.py`ïŒdry-run æåæ¥ forkïŒå¹¶åšçå®é»è®€åæ¯åå ¥åå建 `backup/pre-sync`ã -- `sync-forks.py --verify-schedule`ïŒåªè¯»æ žå¯¹ workflow æš¡æ¿ã`SYNC_PAT` äžèªç¶å®æ¶è¿è¡ç¶æã -- `sync-forks.py --verify-releases/--sync-releases`ïŒæ žå¯¹ææ¶æææ°çš³å®çèµäº§ã +--- -ä»åºç¶æãé»è®€åæ¯ãäžæžžå讀è¯ååšè¿è¡æ¶ä» GitHub è·åïŒREADME äžä¿åæè¿æçæåå¿«ç §ã +## 30 ç§å¿«éäžæ -## åå€ +### 1. ç¯å¢åå€ -éèŠ Python 3.11+ äž [GitHub CLI](https://cli.github.com/)ãWindows å¯è¿è¡ïŒ +æ¬å·¥å ·ä» äŸèµ Python 3.11+ å宿¹ [GitHub CLI (`gh`)](https://cli.github.com/)ïŒ ```powershell +# Windows çšæ·å¯éè¿ winget äžé®å®è£ GitHub CLI winget install --id GitHub.cli --source winget + +# ç»åœ GitHub 莊å·ïŒå®ææ¬å°è®€è¯ïŒ gh auth login ``` -èªåšåäŒå äœ¿çš `GH_TOKEN`ïŒå ¶æ¬¡ `GITHUB_TOKEN`ïŒæ¬å°äº€äºå¯äœ¿çš `gh auth login`ãèæ¬äžäŒè¯»åæä¿åææå¯ç ã +> **åæ®äŒå 级**ïŒèªåšåç¯å¢äŒå 读åç¯å¢åé `GH_TOKEN`ïŒå ¶æ¬¡ `GITHUB_TOKEN`ïŒæ¬å°ç»ç«¯èªåšå€çš `gh auth login` åæ®ãå·¥å ·å šçšäžè¯»åãäžæå°ãäžæä¹ åææå¯ç ã -## åžžçšåœä»€ +### 2. æ žå¿æäœåœä»€ + +#### â æ¥çåœåææ Fork ç¶æïŒåªè¯»ïŒ ```powershell -# åªè¯»ç¶æ +# æå°æ ŒåŒåç»ç«¯è¡šæ Œ python list-forks.py + +# è·åç»æå JSONïŒäŸèæ¬éææçæ§æ¥å ¥ïŒ python list-forks.py --json +``` + +ç»ç«¯å°æž æ°å±ç€ºä»åºåã忝ãäžæžžæºãèœåæäº€æ°ïŒBehindïŒã以å忥 Workflow å®è£ ç¶æïŒ + +```text +Fork repos for your-name (3 total): + +Discovery: live_github_api /user/repos at 2026-10-25T12:00:00Z (repos=12, forks=3) -# å é¢è§ïŒå忥 +Repository Branch Upstream Behind Workflow +------------------------------------------------------------------------------------------------------- +my-awesome-fork main upstream-org/my-awesome-fork 2 Installed +devtools-mirror master original/devtools-mirror 0 Missing +cockpit-custom main cockpit-project/cockpit Unknown Installed +``` + +#### â¡ æš¡æé¢è§ïŒDry-RunïŒ + +åšçå®åå ¥åïŒåŒºçå»ºè®®å æ§è¡ `--dry-run` é¢è§åæŽïŒ + +```powershell +# æš¡æå šèŽŠå·å šéš Fork 忥 python sync-forks.py --dry-run -python sync-forks.py repo-name --dry-run + +# æš¡æå䞪ä»åºåæ¥ +python sync-forks.py my-awesome-fork --dry-run +``` + +#### ⢠æ§è¡å®å šåæ¥ + +```powershell +# åæ¥å šéš Fork python sync-forks.py -# å®è£ ææŽæ°æ¯äžª fork ç weekly sync-fork.yml +# 忥æå® ForkïŒæ¯æå䞪æå€äžªïŒäŒ name æ owner/nameïŒ +python sync-forks.py my-awesome-fork other-owner/another-fork +``` + +#### ⣠æ¹éå®è£ / æŽæ°èªåšåæ¥å·¥äœæµ + +äžºææ Fork æ¹ééšçœ²ææ æåçº§åæ§ç `sync-fork.yml`ïŒæ¯åšå®æ¶è¿è¡äžæ¯ææåšè§ŠåïŒïŒ + +```powershell +# å é¢è§åŸ å®è£ /åŸ æŽæ°å衚 python sync-forks.py --add-workflow --dry-run + +# çå®éšçœ² python sync-forks.py --add-workflow +``` -# åªè¯»æ žå¯¹ workflowãsecret å宿¶è¿è¡å¥åº·åºŠ -python sync-forks.py --verify-schedule --json +#### †巡æ£å®æ¶å·¥äœæµäž Secret å¥åº·åºŠ -# çš³å®çèµäº§åªè¯»æ žå¯¹äžæ¶æ -python sync-forks.py --verify-releases --json -python sync-forks.py --sync-releases --dry-run --json -python sync-forks.py --sync-releases repo-name +```powershell +python sync-forks.py --verify-schedule ``` -ä»åºåæ°å¯å `name` æ `owner/name`ãå€äžªä»åºäŒå»éå¹¶ä¿æèŸå ¥é¡ºåºã +#### ⥠Release èµäº§éåäžæž ç -## å®å šè¯ä¹ +```powershell +# ä» æ žå¯¹èµäº§å·®åŒïŒåªè¯»ïŒ +python sync-forks.py --verify-releases + +# æš¡ææ§è¡èµäº§æ¶æ +python sync-forks.py --sync-releases --dry-run -é»è®€åæ¯åæ¥éµåŸªåºå®é¡ºåºïŒ +# ç宿§è¡èµäº§æ¶æ +python sync-forks.py --sync-releases my-awesome-fork +``` -1. ä» GitHub API fresh discover fork äžäžæžžé»è®€åæ¯ã -2. å³äœ¿äœ¿çš `--dry-run`ïŒä¹äŒçå®è¯»åå¹¶æ¯èŸ fork/upstream æä»¶æ°éäžå é€å 容ïŒdry-run æ¬èº«äžå GitHubãæªæŸåŒäœ¿çš `--dry-run` æ¶ïŒå·¥å ·ä¹äŒå å¯¹å šéšç®æ å®æåæ ·çæ åå ¥ preflightïŒä»»äžç®æ 倱莥æå®å šé»æïŒæŽæ¹ apply éœäžäŒåŒå§ã -3. äžæžžæä»¶æ°äœäº fork ç 50%ãå 逿件æ°è¿å€§ãcompare æä»¶åè¡šèŸŸå° 300 æ¡èå¯èœæªæïŒæå é€ `.github/`ã`README.md`ã`LICENSE` çå ³é®è·¯åŸæ¶äžæ¢ã -4. çå®åæ¥åæåœå fork HEAD åå ¥ç§»åšæ¢å€åæ¯ `backup/pre-sync`ã -5. è°çš GitHub `merge-upstream`ïŒéåéæ°æ¯èŸå¹¶ç¡®è®€ fork äžåèœåïŒæ æ³å€æ žæ¶æå®å šé»æè¿åïŒäžæåå ¥ååºå€æšäžºå·²æ¶æã +--- -`--dry-run` äžå GitHubïŒäœäŒæ§è¡å¿ èŠçå®å š API 读åã`--force` äŒç»è¿éšåå®å 𿣿¥ïŒå æ€çå®åå ¥è¿å¿ é¡»æŸåŒç¡®è®€ïŒ +## æš¡åäžåœä»€å šéåè + +### 1. `list-forks.py` + +| åæ° | 诎æ | +| :--- | :--- | +| *(æ åæ°)* | ç»ç«¯è¡šæ ŒèŸåºå šèŽŠå· Fork ç¶æãèœåæäº€æ°å Workflow å®è£ ç¶æ | +| `--json` | èŸåºæºåšå¯è¯»çç»æå JSONïŒå å«è®€è¯èº«ä»œãDiscovery è¯æ®äžéä»æç» | +| `-h, --help` | æŸç€ºåž®å©ä¿¡æ¯ | + +> **ç¶æäž¥è°šæ§ä¿é**ïŒè¥å API éå¶ææéé®é¢æ æ³ç¡®è®€ç¶æïŒèæ¬æç¡®è¿å `Unknown` å¹¶éåžŠè¯æåå ïŒç»äžå°æªç¥ç¶æäŒªè£ 䞺 `Missing`ã + +### 2. `sync-forks.py` + +| åæ° / é项 | æš¡åŒåç±» | åèœè¯Žæ | +| :--- | :---: | :--- | +| `[repo-name ...]` | ç®æ éæ© | æå®äžäžªæå€äžªä»åºïŒ`repo` æ `owner/repo`ïŒïŒèªåšå»éå¹¶ä¿æé¡ºåºïŒçç¥åå€çå šéš Fork | +| `--dry-run` | æš¡ææ§è¡ | 宿Žè¿è¡çå® API 读åäžå®å šæ¯å¯¹è§åïŒäžäº§çä»»äœ GitHub åå ¥ | +| `--add-workflow` | å·¥äœæµåå | åšç®æ Fork äžåå»ºææŽæ° `.github/workflows/sync-fork.yml` | +| `--verify-schedule` | åªè¯»å®¡è®¡ | å·¡æ£å Fork ç Workflow å®è£ ç¶æã`SYNC_PAT` å¯é¥é 眮åæè¿å®æ¶è¿è¡åå² | +| `--verify-releases` | åªè¯»å®¡è®¡ | 对æ¯äžæžžäž Fork ææ°çš³å®çèµäº§å·®åŒäžä¿ççç¥ | +| `--sync-releases` | èµäº§æ¶æ | éåææ°çš³å®çå®è£ å ãæ¹å `latest.json` å¹¶æž çæ§çæ¬äžæžžéå | +| `--force` | åŒºå¶æš¡åŒ | ç»è¿éšåå®å šéå¶æåŒºå¶éåå·¥äœæµæš¡æ¿ïŒçå®åå ¥éäºæ¬¡ç¡®è®€ïŒ | +| `--json` | èŸåºæ§å¶ | æå°å å«è¿è¡æèŠãåçœ®æ£æ¥ç»æäžéä»æäœæç»ç JSON | +| `-h, --help` | åž®å©ä¿¡æ¯ | æå°å®æŽçåœä»€è¡äœ¿çšè¯Žæ | + +### 3. 区å¶åå ¥äºæ¬¡ç¡®è®€æºå¶ïŒ`--force`ïŒ + +䞺äºé²æ¢èªåšåæµæ°Žçº¿ææè¯¯é æäžå¯éç ŽåïŒåœäœ¿çš `--force` äžæ¶åçå®è¿ç«¯åå ¥æ¶ïŒå¿ é¡»æŸåŒé 眮ç¯å¢åéç¡®è®€ïŒ ```powershell +# PowerShell $env:SYNC_FORKS_FORCE_ACK = "I_UNDERSTAND" python sync-forks.py --force + +# Windows CMD +set SYNC_FORKS_FORCE_ACK=I_UNDERSTAND +python sync-forks.py --force + +# Linux / macOS Bash +SYNC_FORKS_FORCE_ACK=I_UNDERSTAND python3 sync-forks.py --force +``` + +### 4. éåºç å¥çºŠïŒExit CodesïŒ + +èæ¬åš CLI äžäž¥æ ŒéµåŸªä»¥äžéåºç è§èïŒæ¹äŸ¿ CI/CD æµæ°Žçº¿éæïŒ + +- `0`ïŒæäœæåïŒææ éè¿è¡ä»»äœåå ¥åšäœã +- `1`ïŒCLI 猺倱ãåæ®æ æãGitHub API çœç»éè¯¯ïŒæåæ°è¯æ³è§£æé误ïŒè¥ `list-forks.py` ååšä»»äžä»ç¶ææªèœæå确讀ïŒä¹è¿å 1ã +- `3`ïŒå®å šé²æ€è§åè§Šåçæé»æïŒæåªè¯»å·¡æ£åç°ååšéèŠäººå·¥ä»å ¥/å€ççåŸ å项ã + +--- + +## Release èµäº§åæ¥äžæºèœæ¹å诊解 + +讞å€ç°ä»£åŒæºæ¡é¢åºçšïŒåŠ TauriãElectron æå»ºç客æ·ç«¯ïŒäŸèµ GitHub Releases è¿è¡ååäžèªåšæŽæ°ãæ®éç Git Fork åªèœåæ¥æºç åæ¯ïŒæ æ³éå Releaseã + +`--sync-releases` é对è¿äžåºæ¯æäŸäºç«¯å°ç«¯çéåè§£å³æ¹æ¡ïŒ + +```text +äžæžž Release (v1.2.0) Fork Release (v1.2.0) + âââ app-setup.exe âââ 忥éå âââ⺠âââ app-setup.exe + âââ app-setup.dmg âââ 忥éå âââ⺠âââ app-setup.dmg + âââ latest.json âââ æºèœæ¹å âââ⺠âââ latest.json (URL æ¹å䞺 Fork éŸæ¥) + âââ SHA256SUMS.txt âââ èåšæŽæ° âââ⺠âââ SHA256SUMS.txt (éæ°è®¡ç®æ ¡éªåŒ) ``` -äžèŠåšæ¥å¿ãåœä»€è®°åœæä»åºæä»¶äžæå° tokenã +1. **çœååèµäº§ç²Ÿåå¹é **ïŒè¯å« `.exe`ã`.msi`ã`.deb`ã`.rpm`ã`.appimage`ã`.dmg`ã`.pkg`ã`.zip`ã`.tar.gz` çå®è£ å ïŒ`.sig`ã`.minisig` çŸåïŒä»¥åååžæž åäž `latest.json`ã +2. **`latest.json` èªåšæ¹å**ïŒè§£æ JSON å 容ïŒèªåšå°äžèœœå°åä» upstream åååçŒæ¹å䞺åœå fork ä»åºçäžèœœå°åã +3. **æ ¡éªæž åèåšéç®**ïŒè¥å å å« `SHA256SUMS.txt` æ `SHA512SUMS.txt`ïŒèªåšè®¡ç®æ° `latest.json` çææ°ååžå¹¶æ¿æ¢å¯¹åºè¡ã +4. **å æ°æ®ååäžäŒ **ïŒå° `latest.json` äžæ ¡éªæž åäœäžºåäžæ¹æ¬¡å æ°æ® bundle äžäŒ ïŒé¿å å åæä»¶äžäŒ æ¶å·®é ææ ¡éªå€±èŽ¥ã +5. **èµäº§åç§°å®å šæž æŽ**ïŒäž¥çŠå å«è·¯åŸåé笊ïŒ`/`ã`\`ïŒãNUL å笊ãç¶ç®åœééžïŒ`..`ïŒæ CLI åæ°åçŒïŒ`-`ïŒçåŒåžžæä»¶åã +6. **å·²è¯æéåæž ççç¥**ïŒåœäžæžžååžæŽé«çæ¬æ¶ïŒä» æž çéè¿âå tagãååäžçžå digest/sizeâ䞥å¯è¯ææ¥èªäžæžžçæ§éåèµäº§ïŒ**ç»å¯¹äžäŒå é€çšæ·åš Fork äžèªè¡äžäŒ ç䞪æ§åèµäº§æèªå®ä¹ Tag**ã + +--- + +## GitHub Actions èªåšåè¿ç»Ž -## Release æ¶æ +æ¬é¡¹ç®èªåžŠäžå¥äºè¡¥ç GitHub Actions å·¥äœæµïŒå¯çŽæ¥æ¥å ¥æç»äº€ä»æµçšïŒ -åœäžæžžææ°çš³å®çå å«å®è£ å ãçŸåãæ ¡éªæä»¶æ `latest.json` æ¶ïŒ`--sync-releases` å¯ïŒ +- **`ci.yml`**ïŒåšä»£ç æäº€æ PR æ¶èªåšè¿è¡å šéš 58 项åå æµè¯ã +- **`auto-setup-forks.yml`**ïŒæ¯åšæ¥å®æ¶èªåšæ«æå šèŽŠå·ïŒè¥åç°äºæ°å建ç ForkïŒæ `sync-forks.py` æš¡æ¿åçå级ïŒå°èªåšäžºææ Fork å®è£ /æŽæ°ææ°ç `sync-fork.yml` åæ¥æµæ°Žçº¿ã +- **`integration-api-smoke.yml`**ïŒæ¯åšäžäœ¿çšåªè¯»åæ®é对çå® GitHub API è¿è¡åçæµè¯ïŒå·¡æ£æ¥å£å Œå®¹æ§äžç»æäœååã -- åš fork å建æè¡¥éœå tag ççš³å®çèµäº§ïŒ -- æ `latest.json` äžèœœå°åæ¹åå° forkïŒå¹¶åæ¥æŽæ° `SHA256SUMS.txt`ïŒ -- å° `latest.json` äž SHA-256/SHA-512 æž åäœäžºäžäžªå æ°æ® bundle èŠçäžäŒ ïŒé¿å åªçŒºå ¶äžäžäžªæä»¶æ¶çäžäžå¹é æ ¡éªåŒïŒ -- æç»å å«è·¯åŸåé笊ãNUL æ CLI é项åçŒçåŒåžžäžæžžèµäº§åïŒé¿å ééžäžŽæ¶ç®åœææ¹ååæ°è§£æïŒ -- åªå é€èœå€çšå tagãåååçžå digestïŒæ digest æ¶äœ¿çšçžå sizeïŒè¯ææ¥èªäžæžžçæ§çš³å®çéåèµäº§ïŒfork èªæ tag/èµäº§é»è®€ä¿çã +### ä»åº Secret é 眮 -没æå®è£ èµäº§çäžæžžæ `source_only_release_notes` è·³è¿ãæ¬å° release ååœä»€å次æé¿çåŸ 10 åéïŒçæç workflow job æé¿ 30 åéïŒæ§è¡åšäŒåšåå ¥åéæ°æ žå¯¹ïŒæªæ¶ææ¶è¿å safety ç¶æïŒäžæéšåæåæ¥åäžºå®æã +åšè¿è¡èªåšåè¿ç»Žæµæ°Žçº¿æ¶ïŒæéé çœ®ä»¥äž GitHub Actions SecretsïŒ -## èŸåºäžéåºç +| Secret åç§° | å¿ é¡» | äœçšäžæé诎æ | +| :--- | :---: | :--- | +| `SYNC_PAT` | æ¯ | å ·å€ `repo` äž `workflow` æéç Personal Access TokenïŒçšäºåå Fork æäº€å·¥äœæµæä»¶åæ§è¡è·šä»åæ¥ | +| `INTEGRATION_GH_TOKEN` | åŠ | çšäº API åçæµè¯çäžçšåªè¯» Token | +| `INTEGRATION_EXPECTED_LOGIN` | åŠ | çšäºåçæµè¯æ ¡éª Token æå±èŽŠå·äž»äœïŒé²æ¢åæ®éé | +| `INTEGRATION_TARGET_REPO` | åŠ | åçæµè¯æ¶å¯éé对çæå®æµè¯ Fork ä»åºå šå | -`--json` èŸåºå å«è®€è¯æ¥æºãfresh discovery è¯æ®ãéä»ç»æå summaryãçš³å®é误ç çšäºåºå CLIã讀è¯ãçœç»/API ååç°å€±èŽ¥ã +--- -- `0`ïŒæåææ éåšäœã -- `1`ïŒCLIã讀è¯ãAPI ææ§è¡é误ïŒ`list-forks.py` ä»»äžä»ç¶ææ æ³ç¡®è®€æ¶ä¹è¿å 1ïŒå¹¶åš JSON äžä¿çéä»é误ã -- `3`ïŒå®å 𿣿¥é»æïŒæåªè¯»æ žå¯¹åç°éèŠäººå·¥/åå ¥åšäœã +## çŸéŸæ¢å€æå -## GitHub Actions +åŠæäžæžžä»åºåçéå€§ç Žåäžæªè¢«é²æ€è§åæŠæªïŒæäœ¿çšäº `--force`ïŒïŒæšå¯ä»¥åå©èªåšåå»ºçæ¢å€åæ¯è¿è¡äžé®ç§çº§åéïŒ -- `ci.yml`ïŒpush/PR åªè¿è¡äžå¥è¡äžºæµè¯ïŒäžéå€å®è£ lint/type/benchmark å·¥å ·ã -- `auto-setup-forks.yml`ïŒå®æ¶äžºæ° fork å®è£ ææŽæ°åæ¥ workflowïŒ`main` äžæš¡æ¿å®ç°ååæ¶ä¹äŒç«å³æåœ±ïŒäž concurrency 鲿¢å®è£ ä»»å¡å¹¶åãmanaged æä»¶äžåœåæš¡æ¿äžå®å šäžèŽæ¶äŒæ¶æïŒé¿å ä¿çæªå管æ¥éª€ã -- `integration-api-smoke.yml`ïŒäœ¿çšç¬ç«åªè¯»åæ®è¿è¡æè GitHub API äž»éŸïŒå æ¬ `--verify-schedule` äž release æ žå¯¹ïŒå®æ¯è¿è¥æ£æ¥ïŒäžæ¯æ¯æ¬¡æ¬å°çŒç éšçŠã +```bash +# 1. 忢尿¬å° Fork ä»åºç®åœ +cd path/to/your-fork -ä»åº SecretïŒ +# 2. ä»è¿ç«¯æåèªåšçæçæ¢å€åæ¯ +git fetch origin backup/pre-sync -- `SYNC_PAT`ïŒå®è£ fork workflowïŒä»¥å fork workflow èªèº«åæ¥æéæéã -- `INTEGRATION_GH_TOKEN`ïŒintegration smoke çåªè¯» tokenã -- `INTEGRATION_EXPECTED_LOGIN`ïŒçšäºé»æ token äž»äœéé ã -- `INTEGRATION_TARGET_REPO`ïŒå¯éïŒåªéªè¯äžäžªæå® fork çåæ°è·¯åŸã +# 3. æ£æ¥å€ä»œç¹çç¶æäžæäº€è®°åœ +git log -n 5 origin/backup/pre-sync -## åŒåéªè¯ +# 4. å°é»è®€åæ¯ç¡¬é眮å°åæ¥åçå®å šç¶æ +git checkout main +git reset --hard origin/backup/pre-sync -æ¬å°äž CI 䜿çšåäžæ¡æäœå ååœä»€ïŒ +# 5. åŒºå¶æšéå° Fork è¿ç«¯å®ææ¢å€ +git push origin main --force +``` + +--- + +## æ¬å°åŒåäžæµè¯ + +è¿è¡å®æŽçåå æµè¯å¥ä»¶ïŒæ å€éšäŸèµïŒèæ¶éåžž < 0.1 ç§ïŒïŒ ```powershell python -m unittest -q test_toolkit.py ``` -æµè¯èŠç讀è¯/API é误ãfork åç°ãå šæ¹æ¬¡ preflightãdry-runãå é€ä¿æ€ãæ¢å€ç¹ãforce acknowledgementãschedule readinessãJSON é误å release æ¥æºè¯æ/å®å šç»æãåªæåºç°å¯å€ç°çç¬ç«å€±èŽ¥æ¶æå¢å é对æ§éªè¯ïŒäžç»Žæ€éä»»å¡è¯æ®æä»¶ãåæ benchmark æéå€ contract suiteã +æµè¯éæ¶µçïŒ +- GitHub CLI æ¢æµäžè¶ æ¶åŒåžžåç±» +- åè¯è§£æäžå¹¶åäžæžžç¶ä»åç° +- å·¥äœæµæš¡æ¿æž²æäžæ ææŽæ°æ¯å¯¹ +- 50% æä»¶éª€éã倧æ¹éå é€äžå ³é®æä»¶å é€çææŠæª +- Compare 300 æ¡ API æªæé²æ€äžæ¢å€ç¹ç»Žæ€ +- 区å¶åå ¥ç¡®è®€ç¯å¢åéæŠæª +- Release èµäº§çœååè¿æ»€ãURL æ¹åäž SHA256 èåšéç® +- æ¥æºè¯æé忝坹äžå®å šæž ç蟹ç + +--- + +## 讞å¯è¯ + +æ¬é¡¹ç®åºäº [MIT 讞å¯è¯](https://opensource.org/licenses/MIT) åŒæºãæ¬¢è¿æäº€ Issue æ Pull Request å ±åå®åïŒ