ci.yml

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