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.2"
 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.2"
 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  mod-tidy:
 62    runs-on: ubuntu-latest
 63    steps:
 64      - uses: actions/checkout@v6
 65
 66      - name: Set up Go
 67        uses: actions/setup-go@v6
 68        with:
 69          go-version: "1.26.2"
 70
 71      - name: Check go.mod and go.sum are tidy
 72        run: |
 73          go mod tidy
 74          if ! git diff --quiet go.mod go.sum; then
 75            echo "::error::go.mod or go.sum are not tidy. Run 'go mod tidy' and commit the changes."
 76            git diff go.mod go.sum
 77            exit 1
 78          fi
 79
 80  website:
 81    runs-on: ubuntu-latest
 82    defaults:
 83      run:
 84        working-directory: docs
 85    steps:
 86      - uses: actions/checkout@v6
 87
 88      - name: Set up Node.js
 89        uses: actions/setup-node@v6
 90        with:
 91          node-version: "24"
 92          cache: npm
 93          cache-dependency-path: docs/package-lock.json
 94
 95      - name: Install dependencies
 96        run: npm ci
 97
 98      - name: Build
 99        run: npx docusaurus build
100
101  snap:
102    runs-on: ubuntu-latest
103    steps:
104      - uses: actions/checkout@v6
105
106      - name: Validate snapcraft.yaml
107        run: |
108          sudo snap install snapcraft --classic
109          # Verify snapcraft can parse the project file
110          snapcraft list-plugins
111          # Validate YAML structure and required fields
112          python3 << 'PYEOF'
113          import yaml, sys
114
115          with open("snapcraft.yaml") as f:
116              snap = yaml.safe_load(f)
117
118          errors = []
119          for field in ("name", "base", "summary", "description", "parts"):
120              if field not in snap:
121                  errors.append(f"Missing required field: {field}")
122
123          if "apps" in snap:
124              for app_name, app in snap["apps"].items():
125                  if "command" not in app:
126                      errors.append(f"App '{app_name}' missing 'command'")
127
128          if "parts" in snap:
129              for part_name, part in snap["parts"].items():
130                  if "plugin" not in part and "override-build" not in part:
131                      errors.append(f"Part '{part_name}' missing 'plugin' or 'override-build'")
132
133          if errors:
134              for e in errors:
135                  print(f"::error::{e}", file=sys.stderr)
136              sys.exit(1)
137
138          print("snapcraft.yaml is valid.")
139          PYEOF
140
141  flatpak:
142    runs-on: ubuntu-latest
143    steps:
144      - uses: actions/checkout@v6
145
146      - name: Install dependencies
147        run: |
148          sudo apt-get update
149          sudo apt-get install -y python3-pip
150          pip3 install PyYAML
151
152      - name: Validate Flatpak manifest YAML
153        run: python3 -c "import yaml, sys; yaml.safe_load(open('com.floatpane.matcha.yaml'))"
154
155      - name: Check Flatpak manifest structure
156        run: |
157          python3 << 'EOF'
158          import yaml, sys
159
160          with open("com.floatpane.matcha.yaml") as f:
161              manifest = yaml.safe_load(f)
162
163          errors = []
164          for field in ("id", "runtime", "runtime-version", "sdk", "command", "modules"):
165              if field not in manifest:
166                  errors.append(f"Missing required field: {field}")
167
168          if "modules" in manifest:
169              for mod in manifest["modules"]:
170                  if "name" not in mod:
171                      errors.append(f"Module missing 'name' field: {mod}")
172                  if "sources" not in mod and "buildsystem" not in mod:
173                      errors.append(f"Module '{mod.get('name', '?')}' missing 'sources' or 'buildsystem'")
174
175          if errors:
176              for e in errors:
177                  print(f"::error::{e}", file=sys.stderr)
178              sys.exit(1)
179
180          print("Flatpak manifest is valid.")
181          EOF
182
183  nix:
184    runs-on: ubuntu-latest
185    steps:
186      - uses: actions/checkout@v6
187
188      - name: Install Nix
189        uses: cachix/install-nix-action@v31
190        with:
191          nix_path: nixpkgs=channel:nixpkgs-unstable
192
193      - name: Check flake
194        run: nix flake check --no-build
195
196  lua-plugins:
197    runs-on: ubuntu-latest
198    steps:
199      - uses: actions/checkout@v6
200
201      - name: Install Lua
202        run: sudo apt-get update && sudo apt-get install -y lua5.4
203
204      - name: Check Lua syntax
205        run: |
206          failed=0
207          for f in plugins/*.lua; do
208            if ! luac -p "$f" 2>&1; then
209              echo "::error file=$f::Syntax error in $f"
210              failed=1
211            fi
212          done
213          exit $failed
214
215  goreleaser:
216    runs-on: ubuntu-latest
217    steps:
218      - uses: actions/checkout@v6
219        with:
220          fetch-depth: 0
221
222      - name: Set up Go
223        uses: actions/setup-go@v6
224        with:
225          go-version: "1.26.2"
226
227      - name: Install GoReleaser
228        uses: goreleaser/goreleaser-action@v7
229        with:
230          install-only: true
231
232      - name: Validate release config
233        run: goreleaser check -f .goreleaser.yml
234
235      - name: Validate nightly config
236        run: goreleaser check -f .goreleaser.nightly.yml