Release #15
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: Release | |
| on: | |
| schedule: | |
| - cron: "0 3 * * 1" # every Monday — check for new core binaries | |
| workflow_dispatch: | |
| inputs: | |
| bump: | |
| description: 'Version bump type' | |
| type: choice | |
| options: [patch, minor, major] | |
| default: patch | |
| skip_bump: | |
| description: 'Skip version bump (use current version)' | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: write | |
| # Never run two releases at once (they both bump module.prop). | |
| concurrency: | |
| group: release | |
| cancel-in-progress: false | |
| # Third-party actions are pinned to commit SHAs (with the human-readable tag in a | |
| # trailing comment) so a moved tag cannot silently change what runs with the | |
| # `contents: write` token. Bump the SHA + comment together when upgrading. | |
| jobs: | |
| release: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| fetch-depth: 0 | |
| # Push the version-bump commit under a PAT so it bypasses the `main` | |
| # ruleset (the default GITHUB_TOKEN / github-actions app is not in the | |
| # bypass list and cannot be added on a user-owned repo). Set the | |
| # RELEASE_TOKEN secret to a PAT of a user holding the bypass role; it | |
| # falls back to GITHUB_TOKEN, with which the push step would still be | |
| # rejected by the ruleset. | |
| token: ${{ secrets.RELEASE_TOKEN || github.token }} | |
| persist-credentials: true | |
| - name: Check for changes since last release | |
| id: changes | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| skip=true | |
| # 1. New code commits (docs/ci/chore-only changes do not trigger release) | |
| last_tag=$(git describe --tags --abbrev=0 2>/dev/null || echo "") | |
| has_code_commits=false | |
| if [ -z "$last_tag" ]; then | |
| has_code_commits=true | |
| else | |
| code_commits=$(git log "$last_tag"..HEAD --oneline \ | |
| -- \ | |
| 'module/*.sh' \ | |
| 'module/bin/kasumi-proxyctl' \ | |
| 'module/bin/utils.sh' \ | |
| 'module/webroot/cgi-bin/' \ | |
| 'control-center/src/' \ | |
| 'scripts/fetch-bin.sh' \ | |
| 'scripts/package-release.sh' \ | |
| 2>/dev/null | wc -l) | |
| [ "$code_commits" -gt 0 ] && has_code_commits=true | |
| fi | |
| [ "$has_code_commits" = "true" ] && skip=false | |
| # 2. Upstream binary updates | |
| pinned_xray=$(grep -m1 'XRAY_VERSION=.*:-' scripts/fetch-bin.sh | sed 's/.*:-\([^}"]*\)}.*/\1/') | |
| pinned_t2s=$(grep -m1 'TUN2SOCKS_VERSION=.*:-' scripts/fetch-bin.sh | sed 's/.*:-\([^}"]*\)}.*/\1/') | |
| pinned_sb=$(grep -m1 'SINGBOX_VERSION=.*:-' scripts/fetch-bin.sh | sed 's/.*:-\([^}"]*\)}.*/\1/') | |
| latest_xray=$(gh release view --repo XTLS/Xray-core --json tagName -q .tagName) | |
| latest_t2s=$(gh release view --repo xjasonlyu/tun2socks --json tagName -q .tagName) | |
| latest_sb=$(gh release view --repo SagerNet/sing-box --json tagName -q .tagName) | |
| bins_changed=false | |
| [ "$pinned_xray" != "$latest_xray" ] && { skip=false; bins_changed=true; } | |
| [ "$pinned_t2s" != "$latest_t2s" ] && { skip=false; bins_changed=true; } | |
| [ "$pinned_sb" != "$latest_sb" ] && { skip=false; bins_changed=true; } | |
| if [ "$bins_changed" = "true" ]; then | |
| echo "bump=minor" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "bump=${{ inputs.bump || 'patch' }}" >> "$GITHUB_OUTPUT" | |
| fi | |
| echo "xray_old=$pinned_xray" >> "$GITHUB_OUTPUT" | |
| echo "t2s_old=$pinned_t2s" >> "$GITHUB_OUTPUT" | |
| echo "sb_old=$pinned_sb" >> "$GITHUB_OUTPUT" | |
| echo "skip=$skip" >> "$GITHUB_OUTPUT" | |
| echo "xray_version=$latest_xray" >> "$GITHUB_OUTPUT" | |
| echo "t2s_version=$latest_t2s" >> "$GITHUB_OUTPUT" | |
| echo "sb_version=$latest_sb" >> "$GITHUB_OUTPUT" | |
| - name: Setup Bun | |
| if: steps.changes.outputs.skip != 'true' | |
| uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2 | |
| with: | |
| bun-version: latest | |
| - name: Cache Bun dependencies | |
| if: steps.changes.outputs.skip != 'true' | |
| uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 | |
| with: | |
| path: ~/.bun/install/cache | |
| key: bun-${{ runner.os }}-${{ hashFiles('control-center/bun.lock') }} | |
| restore-keys: bun-${{ runner.os }}- | |
| - name: Setup Go | |
| if: steps.changes.outputs.skip != 'true' | |
| uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 | |
| with: | |
| go-version: '1.26' | |
| cache: false | |
| - name: Cache Go build & modules | |
| if: steps.changes.outputs.skip != 'true' | |
| uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4 | |
| with: | |
| path: | | |
| ~/.cache/go-build | |
| ~/go/pkg/mod | |
| key: go-${{ runner.os }}-geodat2srs | |
| restore-keys: go-${{ runner.os }}- | |
| - name: Setup NDK | |
| if: steps.changes.outputs.skip != 'true' | |
| id: setup-ndk | |
| uses: nttld/setup-ndk@ed92fe6cadad69be94a966a7ee3271275e62f779 # v1 | |
| with: | |
| # Mirror flake.nix NDK 28.0.13004108 (== r28). | |
| ndk-version: r28 | |
| - name: Clone geodat2srs | |
| if: steps.changes.outputs.skip != 'true' | |
| run: git clone https://github.com/loss-and-quick/geodat2srs.git $HOME/geodat2srs | |
| - name: Install UI dependencies | |
| if: steps.changes.outputs.skip != 'true' | |
| working-directory: control-center | |
| run: bun install --frozen-lockfile | |
| - name: Lint & test | |
| if: steps.changes.outputs.skip != 'true' | |
| working-directory: control-center | |
| run: | | |
| bun run check | |
| bun run check:i18n | |
| bun run test | |
| - name: Bump version | |
| if: steps.changes.outputs.skip != 'true' | |
| id: bump | |
| run: | | |
| if [ "${{ inputs.skip_bump }}" = "true" ]; then | |
| version=$(grep -m1 '^version=' module/module.prop | cut -d= -f2) | |
| else | |
| version=$(scripts/bump-version.sh ${{ inputs.bump || 'patch' }}) | |
| fi | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| - name: Build release zip | |
| if: steps.changes.outputs.skip != 'true' | |
| env: | |
| NDK_ROOT: ${{ steps.setup-ndk.outputs.ndk-path }} | |
| XRAY_VERSION: ${{ steps.changes.outputs.xray_version }} | |
| TUN2SOCKS_VERSION: ${{ steps.changes.outputs.t2s_version }} | |
| SINGBOX_VERSION: ${{ steps.changes.outputs.sb_version }} | |
| run: scripts/package-release.sh | |
| - name: Generate update.json | |
| if: steps.changes.outputs.skip != 'true' | |
| run: scripts/gen-update-json.sh | |
| - name: Generate changelog | |
| if: steps.changes.outputs.skip != 'true' | |
| env: | |
| VERSION: ${{ steps.bump.outputs.version }} | |
| XRAY_OLD: ${{ steps.changes.outputs.xray_old }} | |
| XRAY_NEW: ${{ steps.changes.outputs.xray_version }} | |
| T2S_OLD: ${{ steps.changes.outputs.t2s_old }} | |
| T2S_NEW: ${{ steps.changes.outputs.t2s_version }} | |
| SB_OLD: ${{ steps.changes.outputs.sb_old }} | |
| SB_NEW: ${{ steps.changes.outputs.sb_version }} | |
| run: | | |
| scripts/gen-changelog.sh \ | |
| "$VERSION" "$XRAY_OLD" "$XRAY_NEW" "$T2S_OLD" "$T2S_NEW" "$SB_OLD" "$SB_NEW" | |
| - name: Commit version bump | |
| if: steps.changes.outputs.skip != 'true' | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add module/module.prop update.json CHANGELOG.md | |
| # The version/changelog may already be committed (a hand-prepared | |
| # skip_bump release, or a re-run) — don't fail when there is nothing new. | |
| if git diff --cached --quiet; then | |
| echo "nothing to commit — version, update.json and changelog already current" | |
| else | |
| git commit -m "chore(release): ${{ steps.bump.outputs.version }}" | |
| git push | |
| fi | |
| - name: Create GitHub Release | |
| if: steps.changes.outputs.skip != 'true' | |
| uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2 | |
| with: | |
| tag_name: ${{ steps.bump.outputs.version }} | |
| target_commitish: ${{ github.ref_name }} | |
| name: Kasumi Proxy ${{ steps.bump.outputs.version }} | |
| files: build/kasumi-proxy-${{ steps.bump.outputs.version }}.zip | |
| generate_release_notes: true |