Repository navigation
chore: bump version to 0.9.0+2026101101 #397
Workflow file for this run
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: build | |
| on: | |
| push: | |
| branches: | |
| - '**' | |
| tags: | |
| - 'v*' | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/v') }} | |
| env: | |
| IS_STABLE: ${{ !contains(github.ref, '-') }} | |
| FLUTTER_VERSION: '3.47.6' | |
| GO_VERSION: '1.27.1' | |
| NDK_VERSION: r28c | |
| jobs: | |
| dart: | |
| name: Dart | |
| # A private copy pays for its Actions minutes, so it runs the checks only when | |
| # started by hand. | |
| if: &checks github.event_name == 'workflow_dispatch' || !github.event.repository.private | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| submodules: true | |
| - name: Test git hooks | |
| run: bash tool/hooks/test.sh | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: plugins/rust_api/rust | |
| cache-directories: .dart_tool/hooks_runner | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - name: Install dependencies | |
| run: flutter pub get | |
| - name: Check format | |
| run: dart format --output=none --set-exit-if-changed lib test tool plugins setup.dart | |
| - name: Analyze | |
| run: flutter analyze --no-fatal-infos | |
| - name: Skip the Go core build hook | |
| run: | | |
| yq -i '.hooks.user_defines.setup.build_assets = false' pubspec.yaml | |
| - name: Verify changelog | |
| if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') | |
| run: dart run tool/changelog.dart verify | |
| - name: Run tests | |
| run: flutter test --reporter expanded --coverage | |
| - name: Check coverage | |
| run: dart run tool/check_coverage.dart coverage/lcov.info 75 | |
| plugins: | |
| name: Plugins | |
| if: *checks | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - name: Validate local Flutter packages | |
| run: bash tool/check_plugins.sh | |
| - name: Validate setup hooks package | |
| working-directory: plugins/setup/setup_hooks | |
| run: | | |
| dart pub get | |
| dart analyze | |
| dart test | |
| desktop: | |
| name: Desktop ${{ matrix.platform }} | |
| if: *checks | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux | |
| os: ubuntu-latest | |
| - platform: windows | |
| os: windows-2022 | |
| - platform: macos | |
| os: macos-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache-dependency-path: core/go.sum | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: desktop-${{ matrix.platform }} | |
| workspaces: | | |
| services/helper | |
| plugins/rust_api/rust | |
| cache-directories: .dart_tool/hooks_runner | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - name: Install Linux build dependencies | |
| if: matrix.platform == 'linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y ninja-build libgtk-3-dev libayatana-appindicator3-dev libsecret-1-dev | |
| - name: Setup Xcode | |
| if: matrix.platform == 'macos' | |
| run: | | |
| sudo xcode-select -s /Applications/Xcode_26.3.app || sudo xcode-select -s /Applications/Xcode_26.2.app | |
| xcodebuild -version | |
| - name: Enable git long paths (Windows) | |
| if: matrix.platform == 'windows' | |
| run: git config --global core.longpaths true | |
| - name: Install dependencies | |
| run: flutter pub get | |
| # Compiles the desktop runners and the native plugin code that only the | |
| # tagged release matrix built before; the bundle itself is discarded. | |
| - name: Build debug bundle | |
| run: flutter build ${{ matrix.platform }} --debug | |
| go: | |
| name: Go core | |
| if: *checks | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache-dependency-path: core/go.sum | |
| - name: Validate Go core wrapper | |
| working-directory: core | |
| env: | |
| CGO_ENABLED: 0 | |
| run: | | |
| if ! compgen -G '*_test.go' > /dev/null; then | |
| echo 'No Go tests found in core/; the test step would pass vacuously.' >&2 | |
| exit 1 | |
| fi | |
| test -z "$(gofmt -l ./*.go ./cmd ./mobile ./platform ./tun)" || { | |
| gofmt -l ./*.go ./cmd ./mobile ./platform ./tun >&2 | |
| exit 1 | |
| } | |
| go test -count=1 . | |
| go vet . ./cmd/... | |
| GOOS=linux go vet ./platform | |
| - name: Validate the Android core library | |
| working-directory: core | |
| env: | |
| CGO_ENABLED: 0 | |
| run: | | |
| tags="$(sed -n 's/^tags: *//p' ../build_config.yaml)" | |
| test -n "$tags" || { echo 'Could not read tags from build_config.yaml' >&2; exit 1; } | |
| GOOS=android GOARCH=arm64 go vet "-tags=$tags" . ./mobile ./tun ./platform | |
| android: | |
| name: Android unit tests | |
| if: *checks | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache-dependency-path: core/go.sum | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - name: Install dependencies | |
| run: flutter pub get | |
| - name: Setup NDK | |
| uses: nttld/setup-ndk@v1 | |
| id: ndk | |
| with: | |
| ndk-version: ${{ env.NDK_VERSION }} | |
| link-to-sdk: true | |
| - name: Setup Java | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: '17' | |
| - name: Setup Gradle | |
| uses: gradle/actions/setup-gradle@v6 | |
| - name: Run Android unit tests | |
| working-directory: android | |
| env: | |
| ANDROID_NDK_HOME: ${{ steps.ndk.outputs.ndk-path }} | |
| run: | | |
| { | |
| echo "flutter.sdk=$FLUTTER_ROOT" | |
| echo "sdk.dir=$ANDROID_HOME" | |
| } > local.properties | |
| wrapper="$FLUTTER_ROOT/bin/cache/artifacts/gradle_wrapper" | |
| test -d "$wrapper" || flutter precache | |
| cp -R "$wrapper/." . | |
| chmod +x gradlew | |
| # No JVM unit test loads the Core or the Flutter build, but `:core` compiles against | |
| # the gomobile AAR, so one ABI of it is built. | |
| ./gradlew :common:testDebugUnitTest :service:testDebugUnitTest :app:testDebugUnitTest \ | |
| -Ptarget-platform=android-arm64 \ | |
| -x :app:compileFlutterBuildDebug -x :app:copyFlutterAssetsDebug | |
| rust: | |
| name: Rust | |
| if: *checks | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: | | |
| services/helper | |
| plugins/rust_api/rust | |
| - name: Check format | |
| run: | | |
| cargo fmt --manifest-path services/helper/Cargo.toml -- --check | |
| cargo fmt --manifest-path plugins/rust_api/rust/Cargo.toml -- --check | |
| - name: Run tests | |
| run: | | |
| cargo test --manifest-path services/helper/Cargo.toml | |
| cargo test --manifest-path plugins/rust_api/rust/Cargo.toml | |
| windows-helper-test: | |
| name: Windows helper test | |
| if: *checks | |
| runs-on: windows-2022 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: services/helper | |
| - name: Check format | |
| run: cargo fmt --manifest-path services/helper/Cargo.toml -- --check | |
| - name: Run Windows service tests | |
| run: cargo test --manifest-path services/helper/Cargo.toml --features windows-service | |
| build: | |
| # Releases publish where the release links point: the public repository. | |
| if: github.repository == 'chen08209/FlClash' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') | |
| needs: [ dart, plugins, go, android, rust, windows-helper-test ] | |
| runs-on: ${{ matrix.os }} | |
| strategy: | |
| matrix: | |
| include: | |
| - platform: android | |
| os: ubuntu-latest | |
| - platform: windows | |
| os: Windows-2022 | |
| arch: amd64 | |
| - platform: linux | |
| os: ubuntu-22.04 | |
| arch: amd64 | |
| - platform: macos | |
| os: macos-15-intel | |
| arch: amd64 | |
| - platform: macos | |
| os: macos-latest | |
| arch: arm64 | |
| - platform: windows | |
| os: windows-11-arm | |
| arch: arm64 | |
| - platform: linux | |
| os: ubuntu-24.04-arm | |
| arch: arm64 | |
| steps: | |
| - name: Setup rust | |
| if: startsWith(matrix.os, 'windows-11-arm') | |
| shell: pwsh | |
| run: | | |
| Invoke-WebRequest -Uri "https://win.rustup.rs/aarch64" -OutFile rustup-init.exe | |
| .\rustup-init.exe -y --default-toolchain stable | |
| $cargoPath = "$env:USERPROFILE\.cargo\bin" | |
| Add-Content $env:GITHUB_PATH $cargoPath | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Setup Android Signing | |
| if: startsWith(matrix.platform,'android') | |
| run: | | |
| echo "${{ secrets.KEYSTORE }}" | base64 --decode > android/app/keystore.jks | |
| echo "${{ secrets.SERVICE_JSON }}" | base64 --decode > android/app/google-services.json | |
| { | |
| echo "keyAlias=${{ secrets.KEY_ALIAS }}" | |
| echo "storePassword=${{ secrets.STORE_PASSWORD }}" | |
| echo "keyPassword=${{ secrets.KEY_PASSWORD }}" | |
| } >> android/local.properties | |
| - name: Setup Go | |
| uses: actions/setup-go@v5 | |
| with: | |
| go-version: ${{ env.GO_VERSION }} | |
| cache-dependency-path: core/go.sum | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| key: ${{ matrix.platform }}-${{ matrix.arch || 'all' }} | |
| workspaces: services/helper | |
| cache-directories: .dart_tool/hooks_runner | |
| - name: Setup Gradle | |
| if: startsWith(matrix.platform,'android') | |
| uses: gradle/actions/setup-gradle@v6 | |
| - name: Enable git long paths (Windows) | |
| if: startsWith(matrix.os, 'windows') | |
| run: git config --global core.longpaths true | |
| # Stable publishes no Windows or Linux arm64 archive; master makes the action | |
| # clone the SDK at the pinned tag and let it fetch the host's own Dart SDK. | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: master | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - name: Setup Xcode | |
| if: startsWith(matrix.platform,'macos') | |
| run: | | |
| sudo xcode-select -s /Applications/Xcode_26.3.app || sudo xcode-select -s /Applications/Xcode_26.2.app | |
| xcodebuild -version | |
| - name: Setup NDK | |
| if: startsWith(matrix.platform,'android') | |
| uses: nttld/setup-ndk@v1 | |
| id: build-ndk | |
| with: | |
| ndk-version: ${{ env.NDK_VERSION }} | |
| add-to-path: true | |
| link-to-sdk: true | |
| - name: Get Flutter Dependency | |
| run: | | |
| flutter --version | |
| flutter pub get | |
| # See .agents/flutter-upgrade.md before bumping FLUTTER_VERSION. | |
| - name: Disable Impeller on Intel macOS | |
| if: matrix.platform == 'macos' && matrix.arch == 'amd64' | |
| run: plutil -replace FLTEnableImpeller -bool NO macos/Runner/Info.plist | |
| - name: Setup | |
| env: | |
| ANDROID_NDK_HOME: ${{ steps.build-ndk.outputs.ndk-path }} | |
| run: dart setup.dart ${{ matrix.platform }} ${{ env.IS_STABLE == 'true' && '--env stable' || '' }} -v | |
| - name: Upload | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: artifact-${{ matrix.platform }}${{ matrix.arch && format('-{0}', matrix.arch) }} | |
| path: ./dist | |
| overwrite: true | |
| upload: | |
| permissions: | |
| contents: write | |
| needs: [ build ] | |
| runs-on: ubuntu-latest | |
| services: | |
| telegram-bot-api: | |
| image: aiogram/telegram-bot-api:latest | |
| env: | |
| TELEGRAM_API_ID: ${{ secrets.TELEGRAM_API_ID }} | |
| TELEGRAM_API_HASH: ${{ secrets.TELEGRAM_API_HASH }} | |
| ports: | |
| - 8081:8081 | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Download | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: ./dist/ | |
| pattern: artifact-* | |
| merge-multiple: true | |
| - name: Setup Flutter | |
| uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| flutter-version: ${{ env.FLUTTER_VERSION }} | |
| cache: true | |
| - name: Install dependencies | |
| run: flutter pub get | |
| - name: Skip native build hooks | |
| run: | | |
| yq -i '.hooks.user_defines.setup.build_assets = false | .hooks.user_defines.rust_api.build_assets = false' pubspec.yaml | |
| - name: Generate release notes | |
| shell: bash | |
| env: | |
| IS_STABLE: ${{ env.IS_STABLE }} | |
| TAG: ${{ github.ref_name }} | |
| run: | | |
| target=() | |
| if [[ "$IS_STABLE" == 'true' ]]; then | |
| target=(--tag "$TAG") | |
| else | |
| dart run tool/changelog.dart build --unreleased | |
| fi | |
| dart run tool/changelog.dart render release "${target[@]}" --out release.md | |
| dart run tool/changelog.dart render telegram "${target[@]}" --out telegram.md | |
| - name: Push to telegram | |
| env: | |
| TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }} | |
| TAG: ${{ github.ref_name }} | |
| RUN_ID: ${{ github.run_id }} | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install requests | |
| python release_telegram.py | |
| - name: Patch release.md | |
| run: | | |
| version=$(echo "${{ github.ref_name }}" | sed 's/^v//') | |
| sed "s|VERSION|$version|g" ./.github/release_template.md >> release.md | |
| - name: Generate sha256 | |
| if: ${{ env.IS_STABLE == 'true' }} | |
| run: | | |
| cd ./dist | |
| sha256sum ./* > SHA256SUMS | |
| - name: Release | |
| if: ${{ env.IS_STABLE == 'true' }} | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: ./dist/* | |
| body_path: './release.md' | |
| - name: Create Homebrew Cask Source Dir | |
| if: ${{ env.IS_STABLE == 'true' }} | |
| run: | | |
| version=$(echo "${{ github.ref_name }}" | sed 's/^v//') | |
| arm_sha=$(sha256sum "./dist/FlClash-${version}-macos-arm64.dmg" | awk '{print $1}') | |
| amd_sha=$(sha256sum "./dist/FlClash-${version}-macos-amd64.dmg" | awk '{print $1}') | |
| mkdir -p ./brew/Casks | |
| sed \ | |
| -e "s|VERSION|$version|g" \ | |
| -e "s|ARM_SHA256|$arm_sha|g" \ | |
| -e "s|AMD_SHA256|$amd_sha|g" \ | |
| ./.github/homebrew_cask_template.rb > ./brew/Casks/flclash.rb | |
| - name: Push to Homebrew tap | |
| if: ${{ env.IS_STABLE == 'true' }} | |
| uses: cpina/github-action-push-to-another-repository@v1.7.2 | |
| env: | |
| SSH_DEPLOY_KEY: ${{ secrets.HOMEBREW_SSH_DEPLOY_KEY }} | |
| with: | |
| source-directory: ./brew/ | |
| destination-github-username: chen08209 | |
| destination-repository-name: homebrew-tap | |
| user-name: 'chen08029' | |
| user-email: 'chen08209@gmail.com' | |
| target-branch: main | |
| commit-message: Update Homebrew cask from ${{ github.ref_name }} | |
| target-directory: / | |
| - name: Create Fdroid Source Dir | |
| if: ${{ env.IS_STABLE == 'true' }} | |
| run: | | |
| mkdir -p ./tmp | |
| cp ./dist/*android-arm64-v8a* ./tmp/ || true | |
| echo "Files copied successfully" | |
| - name: Push to fdroid repo | |
| if: ${{ env.IS_STABLE == 'true' }} | |
| uses: cpina/github-action-push-to-another-repository@v1.7.2 | |
| env: | |
| SSH_DEPLOY_KEY: ${{ secrets.SSH_DEPLOY_KEY }} | |
| with: | |
| source-directory: ./tmp/ | |
| destination-github-username: chen08209 | |
| destination-repository-name: FlClash-fdroid-repo | |
| user-name: 'chen08029' | |
| user-email: 'chen08209@gmail.com' | |
| target-branch: main | |
| commit-message: Update from ${{ github.ref_name }} | |
| target-directory: /tmp/ |