Added in ci-cd deploy & discord bot tweaks (#11) #50
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 & Release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - master | |
| - ci-cd | |
| pull_request: | |
| branches: | |
| - main | |
| - master | |
| - ci-cd | |
| jobs: | |
| # ── Read variables from vars.yml ──────────────────────────────────── | |
| read-vars: | |
| name: Read Variables | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.parse.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Parse vars.yml | |
| id: parse | |
| run: | | |
| version=$(grep 'name: tk_version' vars.yml -A1 | grep 'value:' | awk '{print $2}') | |
| echo "version=$version" >> "$GITHUB_OUTPUT" | |
| echo "Version: $version" | |
| # ── Build Flutter web client ──────────────────────────────────────── | |
| build-web-client: | |
| name: Build Web Client | |
| needs: [read-vars] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| - name: Generate Flutter Icons | |
| working-directory: client | |
| run: dart run flutter_launcher_icons | |
| - name: Build Flutter web (release) | |
| working-directory: client | |
| run: flutter build web --release --wasm --no-web-resources-cdn | |
| - name: Upload web client artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: web-client | |
| path: client/build/web/ | |
| retention-days: 1 | |
| # ── Build server binaries ─────────────────────────────────────────── | |
| build-server: | |
| name: Build Server (${{ matrix.name }}) | |
| needs: [read-vars, build-web-client] | |
| strategy: | |
| matrix: | |
| include: | |
| - name: linux-x86_64 | |
| runner: ubuntu-latest | |
| target: x86_64-unknown-linux-musl | |
| artifact: timekeeper-server-linux-x86_64 | |
| archive: tar.gz | |
| - name: windows-x86_64 | |
| runner: ubuntu-latest | |
| target: x86_64-pc-windows-gnu | |
| artifact: timekeeper-server-windows-x86_64 | |
| archive: zip | |
| - name: macos-x86_64 | |
| runner: macos-latest | |
| target: x86_64-apple-darwin | |
| artifact: timekeeper-server-macos-x86_64 | |
| archive: tar.gz | |
| - name: macos-aarch64 | |
| runner: macos-latest | |
| target: aarch64-apple-darwin | |
| artifact: timekeeper-server-macos-aarch64 | |
| archive: tar.gz | |
| runs-on: ${{ matrix.runner }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Protoc | |
| uses: arduino/setup-protoc@v3 | |
| with: | |
| repo-token: ${{ secrets.GITHUB_TOKEN }} | |
| - uses: actions-rust-lang/setup-rust-toolchain@v1 | |
| with: | |
| target: ${{ matrix.target }} | |
| # Linux-specific: install musl toolchain | |
| - name: Install musl tools | |
| if: matrix.target == 'x86_64-unknown-linux-musl' | |
| run: sudo apt-get update && sudo apt-get install -y musl-tools | |
| # Windows cross-compile: install mingw-w64 | |
| - name: Install mingw-w64 | |
| if: matrix.target == 'x86_64-pc-windows-gnu' | |
| run: sudo apt-get update && sudo apt-get install -y gcc-mingw-w64-x86-64 | |
| # Build the server | |
| - name: Build server (release) | |
| run: cargo build --release --target ${{ matrix.target }} | |
| # Download the web client artifact | |
| - name: Download web client | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: web-client | |
| path: staging/client/build/web | |
| # Prepare the release archive | |
| - name: Prepare archive (tar.gz) | |
| if: matrix.archive == 'tar.gz' | |
| run: | | |
| mkdir -p staging | |
| cp target/${{ matrix.target }}/release/main staging/server | |
| chmod +x staging/server | |
| cd staging | |
| tar -czf ../${{ matrix.artifact }}.tar.gz . | |
| - name: Prepare archive (zip) | |
| if: matrix.archive == 'zip' | |
| run: | | |
| mkdir -p staging | |
| cp target/${{ matrix.target }}/release/main.exe staging/server.exe | |
| cd staging | |
| zip -r ../${{ matrix.artifact }}.zip . | |
| - name: Upload release artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: ${{ matrix.artifact }}.${{ matrix.archive }} | |
| retention-days: 5 | |
| # ── Build client desktop & Android ────────────────────────────────── | |
| build-client: | |
| name: Build Client (${{ matrix.name }}) | |
| needs: [read-vars] | |
| strategy: | |
| matrix: | |
| include: | |
| - name: linux-x86_64 | |
| runner: ubuntu-latest | |
| build-cmd: linux | |
| artifact: timekeeper-client-linux-x86_64 | |
| artifact-path: client/build/linux/x64/release/bundle | |
| archive: tar.gz | |
| - name: windows-x86_64 | |
| runner: windows-latest | |
| build-cmd: windows | |
| artifact: timekeeper-client-windows-x86_64 | |
| artifact-path: client/build/windows/x64/runner/Release | |
| archive: zip | |
| - name: macos-x86_64 | |
| runner: macos-latest | |
| build-cmd: macos | |
| artifact: timekeeper-client-macos-x86_64 | |
| artifact-path: client/build/macos/Build/Products/Release | |
| archive: zip | |
| - name: macos-aarch64 | |
| runner: macos-latest | |
| build-cmd: macos | |
| artifact: timekeeper-client-macos-aarch64 | |
| artifact-path: client/build/macos/Build/Products/Release | |
| archive: zip | |
| - name: android | |
| runner: ubuntu-latest | |
| build-cmd: apk | |
| artifact: timekeeper-client-android | |
| artifact-path: client/build/app/outputs/flutter-apk/app-release.apk | |
| archive: none | |
| runs-on: ${{ matrix.runner }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: subosito/flutter-action@v2 | |
| with: | |
| channel: stable | |
| # Android needs Java | |
| - name: Setup Java | |
| if: matrix.build-cmd == 'apk' | |
| uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: "17" | |
| # Linux desktop needs build dependencies | |
| - name: Install Linux dependencies | |
| if: matrix.build-cmd == 'linux' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libstdc++-12-dev | |
| - name: Generate Flutter Icons | |
| working-directory: client | |
| run: dart run flutter_launcher_icons | |
| - name: Build client (release) | |
| working-directory: client | |
| run: flutter build ${{ matrix.build-cmd }} --release | |
| # Archive: tar.gz (Linux) | |
| - name: Prepare archive (tar.gz) | |
| if: matrix.archive == 'tar.gz' | |
| run: | | |
| cd ${{ matrix.artifact-path }} | |
| tar -czf ${{ github.workspace }}/${{ matrix.artifact }}.tar.gz . | |
| # Archive: zip (Windows/macOS) | |
| - name: Prepare archive (zip - Unix) | |
| if: matrix.archive == 'zip' && runner.os != 'Windows' | |
| run: | | |
| cd "${{ matrix.artifact-path }}" | |
| zip -r "${{ github.workspace }}/${{ matrix.artifact }}.zip" . | |
| - name: Prepare archive (zip - Windows) | |
| if: matrix.archive == 'zip' && runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| Compress-Archive -Path "${{ matrix.artifact-path }}\*" -DestinationPath "${{ github.workspace }}\${{ matrix.artifact }}.zip" | |
| # Upload archived artifact | |
| - name: Upload artifact (archived) | |
| if: matrix.archive != 'none' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: ${{ matrix.artifact }}.${{ matrix.archive }} | |
| retention-days: 5 | |
| # Upload APK directly (no archive needed) | |
| - name: Upload artifact (apk) | |
| if: matrix.archive == 'none' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.artifact }} | |
| path: ${{ matrix.artifact-path }} | |
| retention-days: 5 | |
| # ── Deploy to production server ────────────────────────────────────── | |
| deploy: | |
| name: Deploy | |
| needs: [build-server, build-web-client] | |
| if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/ci-cd') | |
| runs-on: ubuntu-latest | |
| environment: production | |
| steps: | |
| - name: Download server artifact | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: timekeeper-server-linux-x86_64 | |
| - name: Extract server binary | |
| run: | | |
| tar -xzf timekeeper-server-linux-x86_64.tar.gz | |
| ls -la | |
| - name: Download web client | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: web-client | |
| path: client/build/web | |
| - name: Display downloaded files | |
| run: | | |
| ls -la | |
| ls -la client/build/web | |
| # Join Tailscale network | |
| - name: Tailscale | |
| uses: tailscale/github-action@v4 | |
| with: | |
| oauth-client-id: ${{ secrets.GRIM_TS_OAUTH_CLIENT_ID }} | |
| oauth-secret: ${{ secrets.GRIM_TS_OAUTH_SECRET }} | |
| tags: tag:ci | |
| - name: Stop server service | |
| uses: appleboy/ssh-action@v1.0.3 | |
| with: | |
| host: ${{ secrets.SSH_HOST }} | |
| username: ${{ secrets.SSH_USERNAME }} | |
| key: ${{ secrets.SSH_PRIVATE_KEY }} | |
| port: ${{ secrets.SSH_PORT }} | |
| script: | | |
| systemctl stop server | |
| - name: Deploy to server | |
| uses: appleboy/scp-action@v1 | |
| with: | |
| host: ${{ secrets.SSH_HOST }} | |
| username: ${{ secrets.SSH_USERNAME }} | |
| key: ${{ secrets.SSH_PRIVATE_KEY }} | |
| port: ${{ secrets.SSH_PORT }} | |
| source: "server,client" | |
| target: "/root/" | |
| overwrite: true | |
| - name: Configure and restart server | |
| uses: appleboy/ssh-action@v1.0.3 | |
| with: | |
| host: ${{ secrets.SSH_HOST }} | |
| username: ${{ secrets.SSH_USERNAME }} | |
| key: ${{ secrets.SSH_PRIVATE_KEY }} | |
| port: ${{ secrets.SSH_PORT }} | |
| script: | | |
| chmod +x /root/server | |
| cat > /etc/systemd/system/server.service << 'SVCEOF' | |
| [Unit] | |
| Description=TimeKeeper Server | |
| After=network.target | |
| [Service] | |
| Type=simple | |
| WorkingDirectory=/root | |
| ExecStart=/root/server | |
| Restart=always | |
| RestartSec=10 | |
| Environment="RUST_LOG=info" | |
| [Install] | |
| WantedBy=default.target | |
| SVCEOF | |
| systemctl daemon-reload | |
| systemctl restart server | |
| systemctl status server | |
| # ── Create GitHub Release ─────────────────────────────────────────── | |
| release: | |
| name: Create Release | |
| needs: [read-vars, build-server, build-client] | |
| if: github.event_name == 'push' && (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || github.ref == 'refs/heads/ci-cd') | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| pattern: timekeeper-* | |
| - name: List artifacts | |
| run: find artifacts -type f | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| tag_name: v${{ needs.read-vars.outputs.version }} | |
| name: TimeKeeper v${{ needs.read-vars.outputs.version }} | |
| draft: true | |
| prerelease: false | |
| files: | | |
| artifacts/**/* |