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@v6
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@v6
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@v6
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@v6
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: npx docusaurus build
108
109 snap:
110 runs-on: ubuntu-latest
111 steps:
112 - uses: actions/checkout@v6
113
114 - name: Validate snapcraft.yaml
115 run: |
116 sudo snap install snapcraft --classic
117 # Verify snapcraft can parse the project file
118 snapcraft list-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@v6
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@v6
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@v6
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@v6
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