diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a4d2e716..e64f7678 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -1,42 +1,205 @@ +# CI workflow for PIME +# This workflow is split into two jobs: +# 1️⃣ **build** – runs on every push / PR. It builds the project, runs tests, +# uploads unsigned artifacts, and performs test‑only signing (no manual approval). +# 2️⃣ **release** – runs only for tag pushes. It requires the `production` +# environment (manual approval in GitHub) and performs the production signing +# of both binaries and the installer, then creates a GitHub Release. + name: Build on: push: + branches: ['**'] + tags: ['v*'] pull_request: - branches: [main] jobs: + # --------------------------------------------------------------------- + # Build job – runs on every push/PR. Includes test signing only. + # --------------------------------------------------------------------- build: - runs-on: windows-latest + runs-on: windows-2025 + permissions: + id-token: write + contents: write steps: - uses: actions/checkout@v3 with: submodules: 'true' + - name: Use Node.js 21.x uses: actions/setup-node@v4 with: node-version: 21.x + - name: Install Rust uses: dtolnay/rust-toolchain@stable with: targets: i686-pc-windows-msvc + - name: Run Rust tests run: | cd PIMELauncher cargo test --verbose + - name: Use Install NSIS uses: repolevedavaj/install-nsis@v1.2.0 with: nsis-version: 3.08 + - name: Run build.bat env: - Rust_COMPILER: ${{ env.CARGO_HOME }}\bin\rustc.exe + Rust_COMPILER: ${{ env.CARGO_HOME }}\\bin\\rustc.exe + run: | + .\\build.bat + + # --------------------------------------------------------------- + # Upload unsigned binaries – needed for both test and release signing. + # --------------------------------------------------------------- + - name: Upload unsigned binaries + id: upload-unsigned-binaries + uses: actions/upload-artifact@v7 + with: + name: unsigned-binaries + path: | + build/PIMELauncher/PIMELauncher.exe + build/PIMETextService/Release/PIMETextService.dll + build64/PIMETextService/Release/PIMETextService.dll + build_arm64/PIMETextService/Release/PIMETextService.dll + + # --------------------------------------------------------------- + # ----- Test signing (runs on every non‑tag commit) ----- + # Uses the test certificate and does NOT require manual approval. + # --------------------------------------------------------------- + - name: Sign binaries (test) + if: ${{ !startsWith(github.ref, 'refs/tags/') }} + uses: signpath/github-action-submit-signing-request@v2 + with: + api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' + organization-id: '44e7ac31-01b7-47df-8a58-44125a7d21b0' + project-slug: 'PIME' + signing-policy-slug: 'test-signing' + artifact-configuration-slug: 'binaries-zip' + github-artifact-id: '${{ steps.upload-unsigned-binaries.outputs.artifact-id }}' + wait-for-completion: true + output-artifact-directory: 'signed-binaries' + + # --------------------------------------------------------------- + # Upload the signed binaries as an artifact so the release job can use them. + # This step runs on every build (both test and release paths) because the + # `signpath` action always writes to the `signed-binaries` directory. + # --------------------------------------------------------------- + - name: Upload signed binaries + if: always() # ensure the artifact exists even if signing was skipped + uses: actions/upload-artifact@v7 + with: + name: signed-binaries + path: signed-binaries/** + + # --------------------------------------------------------------- + # Replace binaries with the signed versions (test‑signing case). + # This step runs only when we have signed binaries (i.e., after test signing). + # --------------------------------------------------------------- + - name: Replace binaries with signed versions + if: ${{ !startsWith(github.ref, 'refs/tags/') }} run: | - .\build.bat + copy signed-binaries\build\PIMELauncher\PIMELauncher.exe build\PIMELauncher\PIMELauncher.exe + copy signed-binaries\build\PIMETextService\Release\PIMETextService.dll build\PIMETextService\Release\PIMETextService.dll + copy signed-binaries\build64\PIMETextService\Release\PIMETextService.dll build64\PIMETextService\Release\PIMETextService.dll + copy signed-binaries\build_arm64\PIMETextService\Release\PIMETextService.dll build_arm64\PIMETextService\Release\PIMETextService.dll + + # --------------------------------------------------------------- + # Build the installer (used for both test and release builds). + # --------------------------------------------------------------- - name: Build the installer run: | cmd /C "C:\Program Files (x86)\NSIS\Bin\makensis.exe" ".\installer\installer.nsi" - - uses: actions/upload-artifact@v4 + + # --------------------------------------------------------------- + # Upload the unsigned installer – the release job will sign it. + # --------------------------------------------------------------- + - name: Upload unsigned installer + id: upload-unsigned-installer + uses: actions/upload-artifact@v7 with: - name: Installer + name: unsigned-installer path: installer/*.exe + archive: false # Do not zip the NSIS installer. + + # --------------------------------------------------------------------- + # Release job – runs _only_ for tag pushes and requires manual approval. + # --------------------------------------------------------------------- + release: + needs: build + if: startsWith(github.ref, 'refs/tags/') + runs-on: windows-2025 + environment: production # <-- manual approval point + permissions: + id-token: write + contents: write + steps: + - uses: actions/checkout@v3 + with: + submodules: true + + # Download the signed binaries produced by the build job. + - name: Download signed binaries + uses: actions/download-artifact@v4 + with: + name: signed-binaries + path: signed-binaries + + # --------------------------------------------------------------- + # ----- Release signing for binaries (tag only) ----- + # Requires the production environment approval. + # --------------------------------------------------------------- + - name: Sign binaries (release) + uses: signpath/github-action-submit-signing-request@v2 + with: + api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' + organization-id: '44e7ac31-01b7-47df-8a58-44125a7d21b0' + project-slug: 'PIME' + signing-policy-slug: 'release-signing' + artifact-configuration-slug: 'binaries-zip' + github-artifact-id: '${{ steps.upload-unsigned-binaries.outputs.artifact-id }}' + wait-for-completion: true + output-artifact-directory: 'signed-binaries' + + # Replace binaries with the newly signed versions. + - name: Replace binaries with signed versions + run: | + copy signed-binaries\build\PIMELauncher\PIMELauncher.exe build\PIMELauncher\PIMELauncher.exe + copy signed-binaries\build\PIMETextService\Release\PIMETextService.dll build\PIMETextService\Release\PIMETextService.dll + copy signed-binaries\build64\PIMETextService\Release\PIMETextService.dll build64\PIMETextService\Release\PIMETextService.dll + copy signed-binaries\build_arm64\PIMETextService\Release\PIMETextService.dll build_arm64\PIMETextService\Release\PIMETextService.dll + + # --------------------------------------------------------------- + # Download the unsigned installer uploaded by the build job. + # --------------------------------------------------------------- + - name: Download unsigned installer + uses: actions/download-artifact@v4 + with: + name: unsigned-installer + path: unsigned-installer + + # ----- Release installer signing (tag only) ----- + - name: Sign installer + uses: signpath/github-action-submit-signing-request@v2 + with: + api-token: '${{ secrets.SIGNPATH_API_TOKEN }}' + organization-id: '44e7ac31-01b7-47df-8a58-44125a7d21b0' + project-slug: 'PIME' + signing-policy-slug: 'release-signing' + artifact-configuration-slug: 'initial' # single .exe file + github-artifact-id: '${{ steps.upload-unsigned-installer.outputs.artifact-id }}' + wait-for-completion: true + output-artifact-directory: 'signed-installer' + skip-decompress: true # installer exe is not a zip file. + + # ----- Create GitHub Release (tag only) ----- + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: signed-installer/**/*.exe + generate_release_notes: true diff --git a/appveyor.yml b/appveyor.yml index a7498443..79880b6e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -3,7 +3,7 @@ pull_requests: do_not_increment_build_number: true version: "{branch} build {build}" -image: Visual Studio 2022 +image: Visual Studio 2026 init: - git --version @@ -16,6 +16,13 @@ install: - git submodule init - git submodule update + # The appveyor image contains cmake 4.1 only, which doesn't support VS 2016. + # Download cmake 4.3.0 and add it to the PATH. + - appveyor DownloadFile https://cmake.org/files/v4.3/cmake-4.3.0-windows-x86_64.zip -FileName cmake43.zip + - 7z x cmake43.zip -oC:\cmake43 + - set "PATH=C:\cmake43\cmake-4.3.0-windows-x86_64\bin;%PATH%" + - cmake --version # should print 4.3.0 + build_script: - .\build.bat diff --git a/build.bat b/build.bat index 5cbe5255..2b32cfd2 100644 --- a/build.bat +++ b/build.bat @@ -1,10 +1,10 @@ -cmake . -Bbuild -G "Visual Studio 17 2022" -A Win32 -DCMAKE_POLICY_VERSION_MINIMUM=3.5 +cmake . -Bbuild -G "Visual Studio 18 2026" -A Win32 -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cmake --build build --config Release -cmake . -Bbuild64 -G "Visual Studio 17 2022" -A x64 -DCMAKE_POLICY_VERSION_MINIMUM=3.5 +cmake . -Bbuild64 -G "Visual Studio 18 2026" -A x64 -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cmake --build build64 --config Release --target PIMETextService -cmake . -Bbuild_arm64 -G "Visual Studio 17 2022" -A ARM64 -DCMAKE_POLICY_VERSION_MINIMUM=3.5 +cmake . -Bbuild_arm64 -G "Visual Studio 18 2026" -A ARM64 -DCMAKE_POLICY_VERSION_MINIMUM=3.5 cmake --build build_arm64 --config Release --target PIMETextService