Release #8
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 | |
| - 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/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 |