ci.yml

  1name: CI
  2
  3on:
  4  push:
  5    branches: [master, release/v1]
  6  pull_request:
  7    branches: [master, release/v1]
  8  merge_group:
  9
 10jobs:
 11  build:
 12    runs-on: ${{ matrix.os }}
 13    strategy:
 14      matrix:
 15        os: [ubuntu-latest, windows-latest, macos-latest]
 16    steps:
 17      - uses: actions/checkout@v7
 18
 19      - name: Set up Go
 20        uses: actions/setup-go@v6
 21        with:
 22          go-version: "1.26.4"
 23
 24      - name: Install system dependencies
 25        if: runner.os == 'Linux'
 26        run: sudo apt-get update && sudo apt-get install -y libpcsclite-dev
 27
 28      - name: Tidy modules
 29        run: go mod tidy
 30
 31      - name: Test
 32        run: go test -v ./...
 33
 34      - name: Build
 35        run: go build -v ./...
 36
 37  lint:
 38    runs-on: ubuntu-latest
 39    steps:
 40      - uses: actions/checkout@v7
 41
 42      - name: Set up Go
 43        uses: actions/setup-go@v6
 44        with:
 45          go-version: "1.26.4"
 46
 47      - name: Install system dependencies
 48        run: sudo apt-get update && sudo apt-get install -y libpcsclite-dev
 49
 50      - name: Check formatting
 51        run: |
 52          unformatted=$(gofmt -l .)
 53          if [ -n "$unformatted" ]; then
 54            echo "::error::The following files are not formatted with gofmt:"
 55            echo "$unformatted"
 56            exit 1
 57          fi
 58
 59      - name: Vet
 60        run: go vet ./...
 61
 62      - name: golangci-lint
 63        uses: golangci/golangci-lint-action@v9
 64        with:
 65          version: v2.12.2
 66          args: --timeout=10m --build-tags=integration
 67          only-new-issues: false
 68
 69  mod-tidy:
 70    runs-on: ubuntu-latest
 71    steps:
 72      - uses: actions/checkout@v7
 73
 74      - name: Set up Go
 75        uses: actions/setup-go@v6
 76        with:
 77          go-version: "1.26.4"
 78
 79      - name: Check go.mod and go.sum are tidy
 80        run: |
 81          go mod tidy
 82          if ! git diff --quiet go.mod go.sum; then
 83            echo "::error::go.mod or go.sum are not tidy. Run 'go mod tidy' and commit the changes."
 84            git diff go.mod go.sum
 85            exit 1
 86          fi
 87
 88  website:
 89    runs-on: ubuntu-latest
 90    defaults:
 91      run:
 92        working-directory: docs
 93    steps:
 94      - uses: actions/checkout@v7
 95
 96      - name: Set up Node.js
 97        uses: actions/setup-node@v6
 98        with:
 99          node-version: "24"
100          cache: npm
101          cache-dependency-path: docs/package-lock.json
102
103      - name: Install dependencies
104        run: npm ci
105
106      - name: Build
107        run: npm run build
108
109  snap:
110    runs-on: ubuntu-latest
111    steps:
112      - uses: actions/checkout@v7
113
114      - name: Validate snapcraft.yaml
115        run: |
116          sudo snap install snapcraft --classic
117          # Verify snapcraft can parse the project file
118          snapcraft plugins
119          # Validate YAML structure and required fields
120          python3 << 'PYEOF'
121          import yaml, sys
122
123          with open("snapcraft.yaml") as f:
124              snap = yaml.safe_load(f)
125
126          errors = []
127          for field in ("name", "base", "summary", "description", "parts"):
128              if field not in snap:
129                  errors.append(f"Missing required field: {field}")
130
131          if "apps" in snap:
132              for app_name, app in snap["apps"].items():
133                  if "command" not in app:
134                      errors.append(f"App '{app_name}' missing 'command'")
135
136          if "parts" in snap:
137              for part_name, part in snap["parts"].items():
138                  if "plugin" not in part and "override-build" not in part:
139                      errors.append(f"Part '{part_name}' missing 'plugin' or 'override-build'")
140
141          if errors:
142              for e in errors:
143                  print(f"::error::{e}", file=sys.stderr)
144              sys.exit(1)
145
146          print("snapcraft.yaml is valid.")
147          PYEOF
148
149  flatpak:
150    runs-on: ubuntu-latest
151    steps:
152      - uses: actions/checkout@v7
153
154      - name: Install dependencies
155        run: |
156          sudo apt-get update
157          sudo apt-get install -y python3-pip
158          pip3 install PyYAML
159
160      - name: Validate Flatpak manifest YAML
161        run: python3 -c "import yaml, sys; yaml.safe_load(open('com.floatpane.matcha.yaml'))"
162
163      - name: Check Flatpak manifest structure
164        run: |
165          python3 << 'EOF'
166          import yaml, sys
167
168          with open("com.floatpane.matcha.yaml") as f:
169              manifest = yaml.safe_load(f)
170
171          errors = []
172          for field in ("id", "runtime", "runtime-version", "sdk", "command", "modules"):
173              if field not in manifest:
174                  errors.append(f"Missing required field: {field}")
175
176          if "modules" in manifest:
177              for mod in manifest["modules"]:
178                  if "name" not in mod:
179                      errors.append(f"Module missing 'name' field: {mod}")
180                  if "sources" not in mod and "buildsystem" not in mod:
181                      errors.append(f"Module '{mod.get('name', '?')}' missing 'sources' or 'buildsystem'")
182
183          if errors:
184              for e in errors:
185                  print(f"::error::{e}", file=sys.stderr)
186              sys.exit(1)
187
188          print("Flatpak manifest is valid.")
189          EOF
190
191  nix:
192    runs-on: ubuntu-latest
193    steps:
194      - uses: actions/checkout@v7
195
196      - name: Install Nix
197        uses: cachix/install-nix-action@v31
198        with:
199          nix_path: nixpkgs=channel:nixpkgs-unstable
200
201      - name: Check flake
202        run: nix flake check --no-build
203
204  lua-plugins:
205    runs-on: ubuntu-latest
206    steps:
207      - uses: actions/checkout@v7
208
209      - name: Install Lua
210        run: sudo apt-get update && sudo apt-get install -y lua5.4
211
212      - name: Check Lua syntax
213        run: |
214          failed=0
215          for f in plugins/*.lua; do
216            if ! luac -p "$f" 2>&1; then
217              echo "::error file=$f::Syntax error in $f"
218              failed=1
219            fi
220          done
221          exit $failed
222
223  goreleaser:
224    runs-on: ubuntu-latest
225    steps:
226      - uses: actions/checkout@v7
227        with:
228          fetch-depth: 0
229
230      - name: Set up Go
231        uses: actions/setup-go@v6
232        with:
233          go-version: "1.26.4"
234
235      - name: Install GoReleaser
236        uses: goreleaser/goreleaser-action@v7
237        with:
238          install-only: true
239
240      - name: Validate release config
241        run: goreleaser check -f .goreleaser.yml
242
243      - name: Validate nightly config
244        run: goreleaser check -f .goreleaser.nightly.yml