name: CI # Runners: uvacompute (https://uvacompute.com) # To enable, set the UVA_RUNNER repo variable to the correct runner label. # runs-on: ${{ vars.UVA_RUNNER || 'ubuntu-latest' }} on: pull_request: branches: [main] push: branches: [main] workflow_dispatch: permissions: contents: write packages: write jobs: validate: name: Validate runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable with: components: clippy - uses: Swatinem/rust-cache@v2 - uses: pnpm/action-setup@v4 with: version: 10 run_install: false - uses: actions/setup-node@v4 with: node-version: 22 cache: pnpm cache-dependency-path: site/pnpm-lock.yaml - name: Install site dependencies run: pnpm --dir site install --frozen-lockfile - name: Install system dependencies run: sudo apt-get update && sudo apt-get install -y libx11-dev libxtst-dev - name: Format check run: make fmt-check - name: Clippy run: make lint - name: Unit tests run: make test-unit - name: Site format check run: make site-format-check integration: name: Integration (Xvfb) runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable - uses: Swatinem/rust-cache@v2 - name: Install system dependencies run: sudo apt-get update && sudo apt-get install -y libx11-dev libxtst-dev xvfb - name: Xvfb integration tests run: make test-integration changes: name: Changes needs: [validate, integration] if: github.event_name != 'pull_request' runs-on: ubuntu-latest outputs: rust: ${{ steps.check.outputs.rust }} version: ${{ steps.version.outputs.version }} tag: ${{ steps.version.outputs.tag }} steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: dorny/paths-filter@v3 id: filter with: filters: | rust: - 'src/**' - 'tests/**' - 'Cargo.toml' - 'Cargo.lock' - 'docker/**' - 'Makefile' - name: Set outputs id: check run: | if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then echo "rust=true" >> "$GITHUB_OUTPUT" else echo "rust=${{ steps.filter.outputs.rust }}" >> "$GITHUB_OUTPUT" fi - name: Calculate next version id: version if: steps.check.outputs.rust == 'true' run: | BASE=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/') IFS='.' read -r MAJOR MINOR PATCH <<< "$BASE" LATEST=$(git tag -l "v${MAJOR}.${MINOR}.*" | sort -V | tail -1) if [ -z "$LATEST" ]; then NEW="$BASE" else LATEST_VER="${LATEST#v}" IFS='.' read -r _ _ LATEST_PATCH <<< "$LATEST_VER" NEW_PATCH=$((LATEST_PATCH + 1)) NEW="${MAJOR}.${MINOR}.${NEW_PATCH}" fi echo "version=${NEW}" >> "$GITHUB_OUTPUT" echo "tag=v${NEW}" >> "$GITHUB_OUTPUT" build: name: Build (${{ matrix.target }}) needs: changes if: github.event_name != 'pull_request' && needs.changes.outputs.rust == 'true' runs-on: ubuntu-latest strategy: fail-fast: true matrix: target: [cargo, docker] steps: - uses: actions/checkout@v4 # --- Cargo steps --- - uses: dtolnay/rust-toolchain@stable if: matrix.target == 'cargo' with: components: clippy - uses: Swatinem/rust-cache@v2 if: matrix.target == 'cargo' - name: Install system dependencies if: matrix.target == 'cargo' run: sudo apt-get update && sudo apt-get install -y libx11-dev libxtst-dev - name: Clippy if: matrix.target == 'cargo' run: cargo clippy -- -D warnings - name: Build if: matrix.target == 'cargo' run: cargo build --release --locked - uses: actions/upload-artifact@v4 if: matrix.target == 'cargo' with: name: deskctl-linux-x86_64 path: target/release/deskctl retention-days: 7 # --- Docker steps --- - uses: docker/setup-buildx-action@v3 if: matrix.target == 'docker' - uses: docker/login-action@v3 if: matrix.target == 'docker' with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - uses: docker/build-push-action@v6 if: matrix.target == 'docker' with: context: . file: docker/Dockerfile push: true tags: | ghcr.io/${{ github.repository }}:latest ghcr.io/${{ github.repository }}:${{ needs.changes.outputs.tag }} cache-from: type=gha cache-to: type=gha,mode=max update-manifests: name: Update Manifests needs: [changes, build] if: github.event_name != 'pull_request' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - uses: dtolnay/rust-toolchain@stable - name: Update version in Cargo.toml run: | CURRENT=$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/') NEW="${{ needs.changes.outputs.version }}" if [ "$CURRENT" != "$NEW" ]; then sed -i "0,/^version = \"${CURRENT}\"/s//version = \"${NEW}\"/" Cargo.toml cargo generate-lockfile fi - name: Commit, tag, and push run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" if ! git diff --quiet; then git add Cargo.toml Cargo.lock git commit -m "release: ${{ needs.changes.outputs.tag }} [skip ci]" fi git tag "${{ needs.changes.outputs.tag }}" git push origin main --tags release: name: Release needs: [changes, build, update-manifests] if: github.event_name != 'pull_request' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/download-artifact@v4 with: name: deskctl-linux-x86_64 path: artifacts/ - name: Create release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | chmod +x artifacts/deskctl mv artifacts/deskctl artifacts/deskctl-linux-x86_64 cd artifacts && sha256sum deskctl-linux-x86_64 > checksums.txt && cd .. gh release create "${{ needs.changes.outputs.tag }}" \ --title "${{ needs.changes.outputs.tag }}" \ --generate-notes \ artifacts/deskctl-linux-x86_64 \ artifacts/checksums.txt