-
Notifications
You must be signed in to change notification settings - Fork 277
Expand file tree
/
Copy pathMakefile
More file actions
829 lines (733 loc) · 31.7 KB
/
Makefile
File metadata and controls
829 lines (733 loc) · 31.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
# Makefile for gh-aw Go project
# Variables
BINARY_NAME=gh-aw
# Add .exe extension on Windows
ifeq ($(OS),Windows_NT)
BINARY_NAME := gh-aw.exe
endif
VERSION ?= $(shell git describe --tags --always --dirty)
DOCKER_IMAGE=ghcr.io/github/gh-aw
DOCKER_PLATFORMS=linux/amd64,linux/arm64
# Build flags
LDFLAGS=-ldflags "-s -w -X main.version=$(VERSION)"
# Default target
.PHONY: all
all: build
# Build the binary, run make deps before this
.PHONY: build
build: sync-action-pins sync-action-scripts
go build $(LDFLAGS) -o $(BINARY_NAME) ./cmd/gh-aw
# Build for all platforms
.PHONY: build-all
build-all: build-linux build-darwin build-windows build-android
.PHONY: build-linux
build-linux:
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build $(LDFLAGS) -o $(BINARY_NAME)-linux-amd64 ./cmd/gh-aw
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build $(LDFLAGS) -o $(BINARY_NAME)-linux-arm64 ./cmd/gh-aw
.PHONY: build-darwin
build-darwin:
GOOS=darwin GOARCH=amd64 go build $(LDFLAGS) -o $(BINARY_NAME)-darwin-amd64 ./cmd/gh-aw
GOOS=darwin GOARCH=arm64 go build $(LDFLAGS) -o $(BINARY_NAME)-darwin-arm64 ./cmd/gh-aw
.PHONY: build-windows
build-windows:
GOOS=windows GOARCH=amd64 go build $(LDFLAGS) -o $(BINARY_NAME)-windows-amd64.exe ./cmd/gh-aw
.PHONY: build-android
build-android:
CGO_ENABLED=0 GOOS=android GOARCH=arm64 go build $(LDFLAGS) -o $(BINARY_NAME)-android-arm64 ./cmd/gh-aw
# Build WebAssembly module for browser usage
# Optionally runs wasm-opt (from Binaryen) if available for ~8% size reduction
.PHONY: build-wasm
build-wasm:
GOOS=js GOARCH=wasm go build -ldflags="-w -s" -o gh-aw.wasm ./cmd/gh-aw-wasm
@if command -v wasm-opt >/dev/null 2>&1; then \
echo "Running wasm-opt -Oz (size optimization)..."; \
BEFORE=$$(wc -c < gh-aw.wasm); \
wasm-opt -Oz --enable-bulk-memory gh-aw.wasm -o gh-aw.opt.wasm && \
mv gh-aw.opt.wasm gh-aw.wasm; \
AFTER=$$(wc -c < gh-aw.wasm); \
echo "✓ wasm-opt: $$BEFORE → $$AFTER bytes"; \
else \
echo "⚠ wasm-opt not found, skipping optimization (install binaryen for ~8% size reduction)"; \
fi
@echo "✓ Built gh-aw.wasm ($$(du -h gh-aw.wasm | cut -f1))"
@echo " Copy wasm_exec.js from: $$(go env GOROOT)/lib/wasm/wasm_exec.js (or misc/wasm/ for Go <1.24)"
# Test the code (runs both unlabelled unit tests and integration tests and long tests)
.PHONY: test
test: test-unit test-integration
# Test unit tests only (excludes labelled integration tests and long tests)
.PHONY: test-unit
test-unit:
go test -v -parallel=4 -timeout=10m -run='^Test' ./... -short
.PHONY: test-integration
test-integration:
go test -v -parallel=4 -timeout=10m -run='^Test' ./... -short
# Update golden test files
.PHONY: update-golden
update-golden:
@echo "Updating golden test files..."
go test -v ./pkg/console -run='^TestGolden_' -update
# Wasm golden tests — compare wasm (string API) compiler output against golden files
.PHONY: test-wasm-golden
test-wasm-golden:
@echo "Running wasm golden tests (Go string API path)..."
go test -v -timeout=5m -run='^TestWasmGolden_' ./pkg/workflow
# Update wasm golden files from current string API output
.PHONY: update-wasm-golden
update-wasm-golden:
@echo "Updating wasm golden test files..."
go test -v -timeout=5m -run='^TestWasmGolden_' ./pkg/workflow -update
# Build wasm and run Node.js golden comparison test
.PHONY: test-wasm
test-wasm: build-wasm
@echo "Running wasm binary golden tests (Node.js)..."
node scripts/test-wasm-golden.mjs
# Test specific integration test groups (matching CI workflow)
.PHONY: test-integration-compile
test-integration-compile:
go test -v -timeout=3m -tags 'integration' -run 'TestCompile|TestPoutine' ./pkg/cli
.PHONY: test-integration-mcp-playwright
test-integration-mcp-playwright:
go test -v -timeout=3m -tags 'integration' -run 'TestMCPInspectPlaywright' ./pkg/cli
.PHONY: test-integration-mcp-other
test-integration-mcp-other:
go test -v -timeout=3m -tags 'integration' -run 'TestMCPAdd|TestMCPInspectGitHub|TestMCPServer|TestMCPConfig' ./pkg/cli
.PHONY: test-integration-logs
test-integration-logs:
go test -v -timeout=3m -tags 'integration' -run 'TestLogs|TestFirewall|TestNoStopTime|TestLocalWorkflow' ./pkg/cli
.PHONY: test-integration-workflow
test-integration-workflow:
go test -v -timeout=3m -tags 'integration' ./pkg/workflow ./cmd/gh-aw
.PHONY: test-perf
test-perf:
go test -v -count=1 -timeout=3m -tags 'integration' -run='^Test' ./... | tee /tmp/gh-aw/test-output.log; \
EXIT_CODE=$$?; \
echo ""; \
echo "=== SLOWEST TESTS ==="; \
grep -E "^\s*--- (PASS|FAIL):" /tmp/gh-aw/test-output.log | \
grep -E "\([0-9]+\.[0-9]+s\)" | \
sed 's/.*\(Test[^ ]*\).* (\([0-9]*\.[0-9]*s\)).*/\2 \1/' | \
sort -nr | \
head -10; \
rm -f /tmp/gh-aw/test-output.log; \
exit $$EXIT_CODE
# Run benchmarks for performance testing
.PHONY: bench
bench:
@echo "Running benchmarks..."
go test -bench=. -benchmem -benchtime=3x -run=^$$ ./pkg/... | tee bench_results.txt
# Run only critical performance benchmarks for daily monitoring
.PHONY: bench-performance
bench-performance:
@echo "Running critical performance benchmarks..."
@echo "This includes: CompileSimpleWorkflow, CompileComplexWorkflow, CompileMCPWorkflow,"
@echo " CompileMemoryUsage, ParseWorkflow, Validation, YAMLGeneration"
@go test -bench='Benchmark(CompileSimpleWorkflow|CompileComplexWorkflow|CompileMCPWorkflow|CompileMemoryUsage|ParseWorkflow|Validation|YAMLGeneration)$$' \
-benchmem -benchtime=3x -run=^$$ ./pkg/workflow | tee bench_performance.txt
@echo ""
@echo "Also running CLI helper benchmarks..."
@go test -bench='Benchmark(ExtractWorkflowNameFromFile|FindIncludesInContent)$$' \
-benchmem -benchtime=3x -run=^$$ ./pkg/cli >> bench_performance.txt
@echo ""
@echo "Performance benchmark results saved to bench_performance.txt"
# Run benchmarks with more iterations for comparison (saves to separate file)
.PHONY: bench-compare
bench-compare:
@echo "Running benchmarks with more iterations for comparison..."
go test -bench=. -benchmem -benchtime=100x -run=^$$ ./pkg/... | tee bench_compare.txt
@echo "Comparison results saved to bench_compare.txt"
@echo "Compare with: benchstat bench_results.txt bench_compare.txt"
# Run memory profiling benchmarks
.PHONY: bench-memory
bench-memory:
@echo "Running memory profiling benchmarks..."
go test -bench=. -benchmem -memprofile=mem.prof -cpuprofile=cpu.prof -benchtime=10x -run=^$$ ./pkg/workflow
@echo "Memory profile saved to mem.prof, CPU profile saved to cpu.prof"
@echo "View with: go tool pprof -http=:8080 mem.prof"
# Run fuzz tests
.PHONY: fuzz
fuzz:
@echo "Running fuzz tests for 30 seconds..."
go test -fuzz=FuzzParseFrontmatter -fuzztime=30s ./pkg/parser/
go test -fuzz=FuzzExpressionParser -fuzztime=30s ./pkg/workflow/
# Run security regression tests
.PHONY: test-security
test-security:
@echo "Running security regression tests..."
go test -v -timeout=3m -run '^TestSecurity' ./pkg/workflow/... ./pkg/cli/...
@echo "Running security fuzz test seed corpus..."
go test -v -timeout=3m -run '^FuzzYAML|^FuzzTemplate|^FuzzInput|^FuzzNetwork|^FuzzSafeJob' ./pkg/workflow/...
@echo "✓ Security regression tests passed"
# Security scanning with gosec, govulncheck, and trivy
.PHONY: security-scan
security-scan: security-gosec security-govulncheck security-trivy
@echo "✓ All security scans completed"
.PHONY: security-gosec
security-gosec:
@echo "Running gosec security scanner..."
@command -v gosec >/dev/null || go install github.com/securego/gosec/v2/cmd/gosec@v2.23.0
@# Exclusions configured in .golangci.yml (linters-settings.gosec.exclude)
@# Keep this list in sync with .golangci.yml for consistency
@GOPATH=$$(go env GOPATH); \
PATH="$$GOPATH/bin:$$PATH" gosec -fmt=json -out=gosec-report.json -stdout -exclude-generated -track-suppressions \
-exclude=G101,G115,G204,G602,G301,G302,G304,G306 \
./...
@echo "✓ Gosec scan complete (results in gosec-report.json)"
.PHONY: security-govulncheck
security-govulncheck:
@echo "Running govulncheck..."
@command -v govulncheck >/dev/null || go install golang.org/x/vuln/cmd/govulncheck@latest
govulncheck ./...
@echo "✓ Govulncheck complete"
.PHONY: security-trivy
security-trivy:
@echo "Running trivy filesystem scan..."
@if command -v trivy >/dev/null 2>&1; then \
trivy fs --severity HIGH,CRITICAL .; \
else \
echo "⚠ Trivy not installed. Install with: brew install trivy (macOS) or see https://aquasecurity.github.io/trivy/latest/getting-started/installation/"; \
fi
@echo "✓ Trivy scan complete"
# Test JavaScript files
.PHONY: test-js
test-js: build-js
cd actions/setup/js && npm run test:js -- --no-file-parallelism
# Install JavaScript dependencies
.PHONY: deps-js
deps-js: check-node-version
cd actions/setup/js && npm ci
.PHONY: build-js
build-js: deps-js
cd actions/setup/js && npm run typecheck
# Bundle JavaScript files with local requires
.PHONY: bundle-js
bundle-js:
@echo "Building bundle-js tool..."
@go build -o bundle-js ./cmd/bundle-js
@echo "✓ bundle-js tool built"
@echo "To bundle a JavaScript file: ./bundle-js <input-file> [output-file]"
# Test all code (Go, JavaScript, and wasm golden)
.PHONY: test-all
test-all: test test-js test-wasm-golden
# Run tests with coverage
.PHONY: test-coverage
test-coverage:
go test -v -count=1 -timeout=3m -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# Clean build artifacts
.PHONY: clean
clean:
@echo "Cleaning build artifacts..."
@# Remove main binary and platform-specific binaries
rm -f $(BINARY_NAME) $(BINARY_NAME)-*
@# Remove bundle-js binary
rm -f bundle-js
@# Remove coverage files
rm -f coverage.out coverage.html
@# Remove benchmark results and profiling data
rm -f bench_results.txt bench_compare.txt mem.prof cpu.prof
@# Remove SBOM files
rm -f sbom.spdx.json sbom.cdx.json
@# Remove security scan reports
rm -f gosec-report.json gosec-results.sarif govulncheck-results.sarif trivy-results.sarif
@# Remove downloaded logs (but keep .gitignore)
@if [ -d .github/aw/logs ]; then \
find .github/aw/logs -type f ! -name '.gitignore' -delete 2>/dev/null || true; \
find .github/aw/logs -type d -empty -delete 2>/dev/null || true; \
fi
@# Remove installed gh extension if it exists
@if [ -d "$$HOME/.local/share/gh/extensions/gh-aw" ]; then \
echo "Removing installed gh-aw extension..."; \
gh extension remove gh-aw 2>/dev/null || rm -rf "$$HOME/.local/share/gh/extensions/gh-aw"; \
fi
@# Clean documentation artifacts
@rm -rf docs/dist docs/.astro 2>/dev/null || true
@# Clean Go build cache, module cache, and test cache
go clean -cache -modcache -testcache
@echo "✓ Clean complete"
# Docker targets
.PHONY: docker-build
docker-build: build-linux
@echo "Building Docker image..."
@if ! command -v docker >/dev/null 2>&1; then \
echo "Error: Docker is not installed."; \
exit 1; \
fi
@# Build for linux/amd64 by default for local testing
docker build -t $(DOCKER_IMAGE):$(VERSION) \
--build-arg BINARY=$(BINARY_NAME)-linux-amd64 \
-f Dockerfile .
@docker tag $(DOCKER_IMAGE):$(VERSION) $(DOCKER_IMAGE):latest
@echo "✓ Docker image built: $(DOCKER_IMAGE):$(VERSION)"
@echo "✓ Docker image tagged: $(DOCKER_IMAGE):latest"
.PHONY: docker-build-multiarch
docker-build-multiarch: build-linux
@echo "Building multi-architecture Docker image..."
@if ! command -v docker >/dev/null 2>&1; then \
echo "Error: Docker is not installed."; \
exit 1; \
fi
@# Check if buildx is available
@if ! docker buildx version >/dev/null 2>&1; then \
echo "Error: Docker buildx is not available."; \
echo "Install with: docker buildx install"; \
exit 1; \
fi
@# Create buildx builder if it doesn't exist
@docker buildx create --use --name gh-aw-builder 2>/dev/null || docker buildx use gh-aw-builder
@# Build for multiple platforms
docker buildx build --platform $(DOCKER_PLATFORMS) \
-t $(DOCKER_IMAGE):$(VERSION) \
-t $(DOCKER_IMAGE):latest \
-f Dockerfile \
--push .
@echo "✓ Multi-architecture Docker image built and pushed"
.PHONY: docker-test
docker-test:
@echo "Testing Docker image..."
@docker run --rm $(DOCKER_IMAGE):$(VERSION) --version
@docker run --rm $(DOCKER_IMAGE):$(VERSION) --help
@echo "✓ Docker image test passed"
.PHONY: docker-push
docker-push:
@echo "Pushing Docker image to registry..."
@docker push $(DOCKER_IMAGE):$(VERSION)
@docker push $(DOCKER_IMAGE):latest
@echo "✓ Docker images pushed"
.PHONY: docker-clean
docker-clean:
@echo "Cleaning Docker images..."
@docker rmi $(DOCKER_IMAGE):$(VERSION) 2>/dev/null || true
@docker rmi $(DOCKER_IMAGE):latest 2>/dev/null || true
@echo "✓ Docker images cleaned"
# Actions management targets
.PHONY: actions-build
actions-build:
@echo "Building all actions..."
@go run ./internal/tools/actions-build build
.PHONY: actions-validate
actions-validate:
@echo "Validating action.yml files..."
@go run ./internal/tools/actions-build validate
.PHONY: actions-clean
actions-clean:
@echo "Cleaning action artifacts..."
@go run ./internal/tools/actions-build clean
.PHONY: generate-action-metadata
generate-action-metadata:
@echo "Generating action metadata..."
@go run ./internal/tools/generate-action-metadata generate
# Check Node.js version
.PHONY: check-node-version
check-node-version:
@if ! command -v node >/dev/null 2>&1; then \
echo "Error: Node.js is not installed."; \
echo ""; \
echo "This project requires Node.js 20 or higher."; \
echo "Please install Node.js 20+ and try again."; \
echo ""; \
echo "For installation instructions, see:"; \
echo " https://github.com/github/gh-aw/blob/main/CONTRIBUTING.md#prerequisites"; \
exit 1; \
fi; \
NODE_VERSION=$$(node --version); \
NODE_VERSION_NUM=$$(echo "$$NODE_VERSION" | sed 's/v//'); \
NODE_MAJOR=$$(echo "$$NODE_VERSION_NUM" | cut -d. -f1); \
if [ "$$NODE_MAJOR" -lt 20 ]; then \
echo "Error: Node.js version $$NODE_VERSION is not supported."; \
echo ""; \
echo "This project requires Node.js 20 or higher."; \
echo "Your current version: $$NODE_VERSION"; \
echo ""; \
echo "Please upgrade Node.js and try again."; \
echo ""; \
echo "For installation instructions, see:"; \
echo " https://github.com/github/gh-aw/blob/main/CONTRIBUTING.md#prerequisites"; \
exit 1; \
fi; \
echo "✓ Node.js version check passed ($$NODE_VERSION)"
.PHONY: tools
tools: ## Install build-time tools from tools.go
@echo "Installing build tools..."
@go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.11
@go install github.com/securego/gosec/v2/cmd/gosec@v2.23.0
@go install golang.org/x/tools/gopls@v0.21.1
@go install golang.org/x/vuln/cmd/govulncheck@v1.1.4
@echo "✓ Tools installed successfully"
# Install golangci-lint binary (avoiding GPL dependencies in go.mod)
# Downloads pre-built binary from GitHub releases
.PHONY: install-golangci-lint
install-golangci-lint:
@echo "Installing golangci-lint binary..."
@GOLANGCI_LINT_VERSION="v2.8.0"; \
GOPATH=$$(go env GOPATH); \
GOOS=$$(go env GOOS); \
GOARCH=$$(go env GOARCH); \
BINARY_NAME="golangci-lint"; \
if [ "$$GOOS" = "windows" ]; then \
BINARY_NAME="golangci-lint.exe"; \
fi; \
if [ -x "$$GOPATH/bin/$$BINARY_NAME" ]; then \
INSTALLED_VERSION=$$("$$GOPATH/bin/$$BINARY_NAME" version --short 2>/dev/null || echo "unknown"); \
if [ "$$INSTALLED_VERSION" = "$${GOLANGCI_LINT_VERSION#v}" ]; then \
echo "✓ golangci-lint $$GOLANGCI_LINT_VERSION already installed"; \
exit 0; \
fi; \
fi; \
DOWNLOAD_URL="https://github.com/golangci/golangci-lint/releases/download/$$GOLANGCI_LINT_VERSION/golangci-lint-$${GOLANGCI_LINT_VERSION#v}-$$GOOS-$$GOARCH.tar.gz"; \
TEMP_DIR=$$(mktemp -d); \
trap "rm -rf $$TEMP_DIR" EXIT; \
echo "Downloading golangci-lint $$GOLANGCI_LINT_VERSION for $$GOOS/$$GOARCH..."; \
if curl -sSL "$$DOWNLOAD_URL" | tar -xz -C "$$TEMP_DIR"; then \
mkdir -p "$$GOPATH/bin"; \
mv "$$TEMP_DIR"/golangci-lint-*/$$BINARY_NAME "$$GOPATH/bin/$$BINARY_NAME"; \
chmod +x "$$GOPATH/bin/$$BINARY_NAME"; \
echo "✓ golangci-lint $$GOLANGCI_LINT_VERSION installed to $$GOPATH/bin/$$BINARY_NAME"; \
else \
echo "Error: Failed to download golangci-lint from $$DOWNLOAD_URL"; \
exit 1; \
fi
# License compliance checking
.PHONY: license-check
license-check: ## Check dependency licenses for compliance
@echo "Checking dependency licenses..."
@command -v go-licenses >/dev/null || go install github.com/google/go-licenses@latest
@go-licenses check --disallowed_types=forbidden,reciprocal,restricted,unknown ./...
@echo "✓ License check passed"
.PHONY: license-report
license-report: ## Generate CSV license report
@echo "Generating license report..."
@command -v go-licenses >/dev/null || go install github.com/google/go-licenses@latest
@go-licenses csv ./... > licenses.csv 2>&1 || true
@echo "✓ Report saved to licenses.csv"
# Install dependencies
.PHONY: deps
deps: check-node-version
go mod download
go mod tidy
cd actions/setup/js && npm ci
# Install development tools (including linter)
.PHONY: deps-dev
deps-dev: check-node-version deps tools install-golangci-lint download-github-actions-schema
@echo "✓ Development dependencies installed"
# Download GitHub Actions workflow schema for embedded validation
.PHONY: download-github-actions-schema
download-github-actions-schema:
@echo "Downloading GitHub Actions workflow schema..."
@mkdir -p pkg/workflow/schemas
@curl -s -o pkg/workflow/schemas/github-workflow.json \
"https://raw.githubusercontent.com/SchemaStore/schemastore/master/src/schemas/json/github-workflow.json"
@echo "Formatting schema with prettier..."
@cd actions/setup/js && npm run format:schema >/dev/null 2>&1
@$(MAKE) patch-github-actions-schema
@echo "✓ Downloaded and formatted GitHub Actions schema to pkg/workflow/schemas/github-workflow.json"
# Patch the GitHub Actions workflow schema with custom permissions not yet in SchemaStore.
# This must be run after download-github-actions-schema to preserve local additions.
.PHONY: patch-github-actions-schema
patch-github-actions-schema:
@echo "Patching GitHub Actions schema with copilot-requests permission..."
@tmpfile=$$(mktemp) && \
jq '.definitions["permissions-event"].properties["copilot-requests"] = {"type": "string", "enum": ["write", "none"]}' \
pkg/workflow/schemas/github-workflow.json > "$$tmpfile" && \
mv "$$tmpfile" pkg/workflow/schemas/github-workflow.json
@cd actions/setup/js && npm run format:schema >/dev/null 2>&1
@echo "✓ Patched GitHub Actions schema with copilot-requests permission"
# Run linter (full repository scan)
.PHONY: golint
golint:
@GOPATH=$$(go env GOPATH); \
if command -v golangci-lint >/dev/null 2>&1 || [ -x "$$GOPATH/bin/golangci-lint" ]; then \
PATH="$$GOPATH/bin:$$PATH" golangci-lint run; \
else \
echo "golangci-lint is not installed. Run 'make deps-dev' to install dependencies."; \
exit 1; \
fi
# Run incremental linter (only changed files since BASE_REF)
# This provides 50-75% faster linting on PRs by only checking changed files
# Configuration optimizations in .golangci.yml:
# - timeout: 5m prevents hanging
# - modules-download-mode: readonly uses cached modules
# Usage: make golint-incremental BASE_REF=origin/main
.PHONY: golint-incremental
golint-incremental:
@GOPATH=$$(go env GOPATH); \
if ! command -v golangci-lint >/dev/null 2>&1 && [ ! -x "$$GOPATH/bin/golangci-lint" ]; then \
echo "golangci-lint is not installed. Run 'make deps-dev' to install dependencies."; \
exit 1; \
fi
@if [ -z "$(BASE_REF)" ]; then \
echo "Error: BASE_REF not set. Use: make golint-incremental BASE_REF=origin/main"; \
exit 1; \
fi
@echo "Running incremental lint against $(BASE_REF)..."
@GOPATH=$$(go env GOPATH); \
PATH="$$GOPATH/bin:$$PATH" golangci-lint run --new-from-rev=$(BASE_REF)
# Validate compiled workflow lock files using Docker-based actionlint
# Uses the same Docker integration as 'make actionlint'
.PHONY: validate-workflows
validate-workflows: build
@echo "Validating compiled workflow lock files..."
./$(BINARY_NAME) compile --actionlint
# Run actionlint on all workflow files
.PHONY: actionlint
actionlint: build
@echo "Validating workflows with actionlint..."
./$(BINARY_NAME) compile --actionlint
# Format code
.PHONY: fmt
fmt: fmt-go fmt-cjs fmt-json
@echo "✓ Code formatted successfully"
.PHONY: fmt-go
fmt-go:
@echo "→ Formatting Go code..."
@go fmt ./...
@echo "✓ Go code formatted"
# Format JavaScript (.cjs and .js) and JSON files in actions/setup/js directory
.PHONY: fmt-cjs
fmt-cjs:
@echo "→ Formatting JavaScript files..."
@cd actions/setup/js && npm run format:cjs --silent >/dev/null 2>&1
@npx prettier --write 'scripts/**/*.js' --ignore-path .prettierignore --log-level=error 2>&1
@echo "✓ JavaScript files formatted"
# Format JSON files in pkg directory (excluding actions/setup/js, which is handled by npm script)
.PHONY: fmt-json
fmt-json:
@echo "→ Formatting JSON files..."
@cd actions/setup/js && npm run format:pkg-json --silent >/dev/null 2>&1
@echo "✓ JSON files formatted"
# Check formatting
.PHONY: fmt-check
fmt-check:
@GOPATH=$$(go env GOPATH); \
if command -v golangci-lint >/dev/null 2>&1 || [ -x "$$GOPATH/bin/golangci-lint" ]; then \
diff_output=$$(PATH="$$GOPATH/bin:$$PATH" golangci-lint fmt --diff 2>&1); \
if [ -n "$$diff_output" ]; then \
echo "Code is not formatted. Run 'make fmt' to fix."; \
exit 1; \
fi; \
else \
echo "golangci-lint is not installed. Run 'make deps-dev' to install dependencies."; \
exit 1; \
fi
# Check JavaScript (.cjs and .js) and JSON file formatting in actions/setup/js directory
.PHONY: fmt-check-cjs
fmt-check-cjs:
cd actions/setup/js && npm run lint:cjs
npx prettier --check 'scripts/**/*.js' --ignore-path .prettierignore
# Check JSON file formatting in pkg directory (excluding actions/setup/js, which is handled by npm script)
.PHONY: fmt-check-json
fmt-check-json:
@if ! cd actions/setup/js && npm run check:pkg-json 2>&1 | grep -q "All matched files use Prettier code style"; then \
echo "JSON files are not formatted. Run 'make fmt-json' to fix."; \
exit 1; \
fi
# Lint JavaScript (.cjs and .js) and JSON files in actions/setup/js directory
.PHONY: lint-cjs
lint-cjs: fmt-check-cjs
@echo "✓ JavaScript formatting validated"
# Lint JSON files in pkg directory (excluding actions/setup/js, which is handled by npm script)
.PHONY: lint-json
lint-json: fmt-check-json
@echo "✓ JSON formatting validated"
# Lint error messages for quality compliance
.PHONY: lint-errors
lint-errors:
@echo "Running error message quality linter..."
@go run scripts/lint_error_messages.go
# Check file sizes and function counts
.PHONY: check-file-sizes
check-file-sizes:
@bash scripts/check-file-sizes.sh
# Validate all project files
.PHONY: lint
lint: fmt-check fmt-check-json lint-cjs golint
@echo "✓ All validations passed"
# Install the binary locally
.PHONY: install
install: build
gh extension remove gh-aw || true
gh extension install .
# Generate schema documentation
.PHONY: generate-schema-docs
generate-schema-docs:
node scripts/generate-schema-docs.js
# Generate agent factory documentation page
.PHONY: generate-agent-factory
generate-agent-factory:
node scripts/generate-agent-factory.js
# Build slides with Marp
.PHONY: build-slides
build-slides:
@echo "Building slides with Marp..."
@cd docs && npx @marp-team/marp-cli ../slides/index.md --html --allow-local-files -o public/slides/gh-aw.html
@echo "✓ Slides built to docs/public/slides/gh-aw.html"
# Documentation targets
.PHONY: deps-docs
deps-docs: check-node-version
@echo "Installing documentation dependencies..."
@cd docs && npm ci
@echo "✓ Documentation dependencies installed"
.PHONY: build-docs
build-docs: deps-docs
@echo "Building Astro documentation..."
@cd docs && npm run build
@echo "✓ Documentation built to docs/dist"
.PHONY: dev-docs
dev-docs: deps-docs
@echo "Starting Astro development server..."
@cd docs && npm run dev
.PHONY: preview-docs
preview-docs: build-docs
@echo "Starting Astro preview server..."
@cd docs && npm run preview
.PHONY: clean-docs
clean-docs:
@echo "Cleaning documentation artifacts..."
@rm -rf docs/dist docs/node_modules docs/.astro
@echo "✓ Documentation artifacts cleaned"
# Sync templates from .github to pkg/cli/templates
# Sync action pins from .github/aw to pkg/workflow/data
.PHONY: sync-action-pins
sync-action-pins:
@echo "Syncing actions-lock.json from .github/aw to pkg/workflow/data/action_pins.json..."
@if [ -f .github/aw/actions-lock.json ]; then \
cp .github/aw/actions-lock.json pkg/workflow/data/action_pins.json; \
echo "✓ Action pins synced successfully"; \
else \
echo "⚠ Warning: .github/aw/actions-lock.json does not exist yet"; \
fi
# Sync action scripts
.PHONY: sync-action-scripts
sync-action-scripts:
@echo "Syncing install-gh-aw.sh to actions/setup-cli/install.sh..."
@cp install-gh-aw.sh actions/setup-cli/install.sh
@chmod +x actions/setup-cli/install.sh
@echo "✓ Action scripts synced successfully"
# Recompile all workflow files
.PHONY: recompile
recompile: build
./$(BINARY_NAME) init --codespaces
./$(BINARY_NAME) compile --validate --verbose --purge --stats
# ./$(BINARY_NAME) compile --dir pkg/cli/workflows --validate --verbose --purge
# Apply automatic fixes to workflow files
.PHONY: fix
fix: build
./$(BINARY_NAME) fix --write
# Generate Dependabot manifests for npm dependencies
.PHONY: dependabot
dependabot: build
./$(BINARY_NAME) compile --dependabot --verbose
# Update GitHub Actions and workflows, then sync action pins and rebuild
.PHONY: update
update: build
./$(BINARY_NAME) update
$(MAKE) sync-action-pins
$(MAKE) build
# Run development server
.PHONY: dev
dev: build
./$(BINARY_NAME)
.PHONY: watch
watch: build
./$(BINARY_NAME) compile --watch
.PHONY: pull-main
pull-main:
@echo "check on main branch"
@git checkout main
@echo "Check out branch is clean"
@git diff --quiet || (echo "Error: Working directory is not clean. Please commit or stash changes before pulling." && exit 1)
@echo "Pulling latest changes..."
@git pull
# Generate Software Bill of Materials (SBOM)
.PHONY: sbom
sbom:
@if ! command -v syft >/dev/null 2>&1; then \
echo "Error: syft is not installed."; \
echo ""; \
echo "Install syft to generate SBOMs:"; \
echo " curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin"; \
echo ""; \
echo "Or visit: https://github.com/anchore/syft#installation"; \
exit 1; \
fi
@echo "Generating SBOM in SPDX format..."
syft packages . -o spdx-json=sbom.spdx.json
@echo "Generating SBOM in CycloneDX format..."
syft packages . -o cyclonedx-json=sbom.cdx.json
@echo "✓ SBOM files generated: sbom.spdx.json, sbom.cdx.json"
# Agent should run this task before finishing its turns
.PHONY: agent-finish
agent-finish: deps-dev fmt lint build test-all fix recompile dependabot generate-schema-docs generate-agent-factory security-scan
@echo "Agent finished tasks successfully."
# Help target
.PHONY: help
help:
@echo "Available targets:"
@echo " build - Build the binary for current platform"
@echo " build-awmg - Build the awmg (MCP gateway) binary for current platform"
@echo " build-all - Build binaries for all platforms (gh-aw and awmg)"
@echo " test - Run Go tests (unit + integration)"
@echo " test-unit - Run Go unit tests only (faster)"
@echo " test-security - Run security regression tests"
@echo " test-js - Run JavaScript tests"
@echo " test-all - Run all tests (Go, JavaScript, and wasm golden)"
@echo " test-wasm-golden - Run wasm golden tests (Go string API path)"
@echo " test-wasm - Build wasm and run Node.js golden comparison test"
@echo " update-wasm-golden - Regenerate wasm golden files from current compiler output"
@echo " test-coverage - Run tests with coverage report"
@echo " bench - Run benchmarks for performance testing"
@echo " bench-compare - Run benchmarks with more iterations (for benchstat comparison)"
@echo " bench-memory - Run memory profiling benchmarks with pprof output"
@echo " fuzz - Run fuzz tests for 30 seconds"
@echo " bundle-js - Build JavaScript bundler tool (./bundle-js <input> [output])"
@echo " clean - Clean build artifacts"
@echo " docker-build - Build Docker image locally (linux/amd64)"
@echo " docker-build-multiarch - Build multi-architecture Docker image (linux/amd64, linux/arm64)"
@echo " docker-test - Test Docker image functionality"
@echo " docker-push - Push Docker images to registry"
@echo " docker-clean - Remove local Docker images"
@echo " actions-build - Build all custom GitHub Actions from source"
@echo " actions-validate - Validate action.yml files"
@echo " actions-clean - Clean action build artifacts"
@echo " generate-action-metadata - Generate action.yml and README.md from JavaScript modules"
@echo " tools - Install build-time tools from tools.go"
@echo " license-check - Check dependency licenses for compliance"
@echo " license-report - Generate CSV license report"
@echo " deps - Install dependencies"
@echo " deps-dev - Install development dependencies (includes tools)"
@echo " check-node-version - Check Node.js version (20 or higher required)"
@echo " golint - Run golangci-lint (full repository scan)"
@echo " golint-incremental - Run golangci-lint incrementally (only changed files, requires BASE_REF)"
@echo " lint - Run linter"
@echo " fmt - Format code"
@echo " fmt-cjs - Format JavaScript (.cjs and .js) and JSON files in actions/setup/js"
@echo " fmt-json - Format JSON files in pkg directory (excluding actions/setup/js)"
@echo " fmt-check - Check code formatting"
@echo " fmt-check-cjs - Check JavaScript (.cjs) and JSON file formatting in actions/setup/js"
@echo " fmt-check-json - Check JSON file formatting in pkg directory (excluding actions/setup/js)"
@echo " lint-cjs - Lint JavaScript (.cjs) and JSON files in actions/setup/js"
@echo " lint-json - Lint JSON files in pkg directory (excluding actions/setup/js)"
@echo " lint-errors - Lint error messages for quality compliance"
@echo " security-scan - Run all security scans (gosec, govulncheck, trivy)"
@echo " security-gosec - Run gosec Go security scanner"
@echo " security-govulncheck - Run govulncheck for known vulnerabilities"
@echo " security-trivy - Run trivy filesystem scanner"
@echo " actionlint - Validate workflows with actionlint (depends on build)"
@echo " validate-workflows - Validate compiled workflow lock files (depends on build)"
@echo " install - Install binary locally"
@echo " sync-action-pins - Sync actions-lock.json from .github/aw to pkg/workflow/data (runs automatically during build)"
@echo " sync-action-scripts - Sync install-gh-aw.sh to actions/setup-cli/install.sh (runs automatically during build)"
@echo " update - Update GitHub Actions and workflows, sync action pins, and rebuild binary"
@echo " fix - Apply automatic codemod-style fixes to workflow files (depends on build)"
@echo " recompile - Recompile all workflow files (runs init, depends on build)"
@echo " dependabot - Generate Dependabot manifests for npm dependencies in workflows"
@echo " generate-schema-docs - Generate frontmatter full reference documentation from JSON schema"
@echo " generate-agent-factory - Generate agent factory documentation page"
@echo " build-slides - Build slides with Marp to docs/public/slides/gh-aw.html"
@echo " deps-docs - Install Astro documentation dependencies"
@echo " build-docs - Build Astro documentation to docs/dist"
@echo " dev-docs - Start Astro development server for live preview"
@echo " preview-docs - Preview built documentation with Astro"
@echo " clean-docs - Clean documentation artifacts (dist, node_modules, .astro)"
@echo " agent-finish - Complete validation sequence (build, test, fix, recompile, fmt, lint, security-scan)"
@echo " sbom - Generate SBOM in SPDX and CycloneDX formats (requires syft)"
@echo " help - Show this help message"