diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f3d7cbe --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,53 @@ +name: CI + +on: + push: + tags-ignore: ["v*"] + pull_request: + +jobs: + smoke-test: + name: Smoke (${{ matrix.os }} / py${{ matrix.python-version }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + python-version: ["3.10", "3.11"] + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements.txt + + - name: Compile smoke + run: | + python - <<'PY' + import compileall + import pathlib + + files = ["main.py", "setup.py"] + for f in files: + ok = compileall.compile_file(f, force=True, quiet=1) + if not ok: + raise SystemExit(f"compile failed: {f}") + + if not compileall.compile_dir("src", force=True, quiet=1): + raise SystemExit("compile failed: src/") + + print("compile smoke ok") + PY + + - name: CLI smoke + run: | + python main.py --help + python main.py --version diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..e63f70e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,97 @@ +name: Release + +on: + push: + tags: + - "v*" + workflow_dispatch: + inputs: + release_tag: + description: "Tag name to publish (example: v1.2.0). Leave empty for non-publishing build." + required: false + type: string + publish: + description: "Publish GitHub Release" + required: false + default: false + type: boolean + make_public: + description: "Make release public immediately (false = hidden draft)" + required: false + default: false + type: boolean + +permissions: + contents: write + +jobs: + build-binaries: + name: Build ${{ matrix.target }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: windows-latest + target: windows-x64 + - os: ubuntu-latest + target: linux-x64 + - os: macos-13 + target: macos-x64 + - os: macos-14 + target: macos-arm64 + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.11" + + - name: Install build dependencies + run: | + python -m pip install --upgrade pip + python -m pip install -r requirements.txt pyinstaller + + - name: Build standalone binary + run: pyinstaller --noconfirm --clean --onefile --name MasterHttpRelayVPN --paths src main.py + + - name: Package release bundle + env: + TARGET: ${{ matrix.target }} + run: python scripts/build_release_bundle.py + + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: release-${{ matrix.target }} + path: release-assets/* + + publish-release: + name: Publish GitHub Release + needs: [build-binaries] + runs-on: ubuntu-latest + if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && github.event.inputs.publish == 'true' && startsWith(github.event.inputs.release_tag, 'v')) + + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: release-assets + + - name: Flatten artifact directories + run: | + mkdir -p final-assets + find release-assets -type f -exec cp {} final-assets/ \; + ls -lah final-assets + + - name: Create GitHub release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ startsWith(github.ref, 'refs/tags/') && github.ref_name || github.event.inputs.release_tag }} + files: final-assets/* + generate_release_notes: true + prerelease: false + draft: ${{ github.event_name != 'workflow_dispatch' || github.event.inputs.make_public != 'true' }}