Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,31 @@ jobs:
cache: true

- run: go vet ./...
- run: go test -race ./...
- name: test with race detector and coverage
run: go test -race -coverprofile=coverage.out -covermode=atomic ./...

- name: report coverage summary
run: ./scripts/coverage-summary.sh coverage.out

- name: upload coverage to Codecov
uses: codecov/codecov-action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: ./coverage.out
fail_ci_if_error: false

- name: generate html coverage report
run: go tool cover -html=coverage.out -o coverage.html

- name: upload coverage artifacts
uses: actions/upload-artifact@v4
with:
name: coverage-report
path: |
coverage.out
coverage.html
retention-days: 14

- run: make build

- name: validate the sample event
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Thumbs.db
/dist/
*.test
*.out
coverage.html

# goreleaser build output
dist/
Expand Down
1 change: 1 addition & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Two cases:
## Tests

- `go test ./...` runs the unit tests. Add new tests next to the package they cover.
- `make test-coverage` runs the suite with the race detector, generates `coverage.out`, and prints a per-package statement coverage summary. `make coverage-html` generates a browser-viewable report at `coverage.html`.
- Tests should not require network, Docker, or a running CTFd. If you need fixtures, put them under `internal/<pkg>/testdata/`.
- For interactive prompts (e.g., `cmd/init.go`), inject test input via the `promptIn` variable — see `cmd/init_test.go` for the pattern.
- The sample event under `examples/sample-event/` is the integration fixture; CI uses it directly.
Expand Down
10 changes: 9 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ LDFLAGS := -X github.com/MicroClub-USTHB/mctf-cli/cmd.version=$(VERSION) \
-X github.com/MicroClub-USTHB/mctf-cli/cmd.commit=$(COMMIT) \
-X github.com/MicroClub-USTHB/mctf-cli/cmd.date=$(DATE)

.PHONY: build test test-integration lint tidy run clean schemas man
.PHONY: build test test-coverage coverage-html test-integration lint tidy run clean schemas man

build: schemas
go build -ldflags "$(LDFLAGS)" -o mctf .
Expand All @@ -28,6 +28,14 @@ schemas:
test:
go test ./...

test-coverage:
go test -race -coverprofile=coverage.out -covermode=atomic ./...
@./scripts/coverage-summary.sh coverage.out

coverage-html: test-coverage
go tool cover -html=coverage.out -o coverage.html
@echo "HTML coverage report written to coverage.html"

# Integration tests (gated by the `integration` build tag). Boots a real
# sshd container + exercises the SSH runner end-to-end. Requires docker
# daemon + ssh/scp/ssh-keygen on PATH; skips gracefully otherwise.
Expand Down
2 changes: 1 addition & 1 deletion docs/BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Open work organized by size. Each line is intentionally GitHub-issue-shaped: tit
## CI / quality

- **golangci-lint** in CI (`go vet` is currently the only static check).
- **Coverage reporting** — `go test -coverprofile` upload to Codecov / similar.
- ~~**Coverage reporting** — `go test -coverprofile` upload to Codecov / similar.~~ **Shipped:** CI runs atomic coverprofile, reports step summary, uploads to Codecov + artifacts, with local `make test-coverage`.
- **Fuzz tests** for the manifest loader and the compose port parser.
- **End-to-end integration test** — sample-event fixture: validate → generate → build → scan → deploy → solve → down. Real docker daemon, gated on an `e2e` build tag.

Expand Down
68 changes: 68 additions & 0 deletions scripts/coverage-summary.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
#!/usr/bin/env bash
set -euo pipefail

# scripts/coverage-summary.sh
# Parses Go coverprofile and generates a Markdown summary table for GitHub Actions step summary
# and terminal output.

COV_FILE="${1:-coverage.out}"

if [ ! -f "$COV_FILE" ]; then
echo "Error: coverage profile '$COV_FILE' not found" >&2
exit 1
fi

TOTAL=$(go tool cover -func="$COV_FILE" | grep "^total:" | awk '{print $NF}')

PKG_ROWS=$(awk '
NR > 1 {
split($1, parts, "/")
pkg = ""
for (i = 4; i < length(parts); i++) {
if (pkg != "") pkg = pkg "/" parts[i]
else pkg = parts[i]
}
if (pkg == "") {
if (length(parts) == 4) pkg = "."
else pkg = parts[4]
}
stmts = $2 + 0
count = $3 + 0
pkg_stmts[pkg] += stmts
if (count > 0) {
pkg_covered[pkg] += stmts
}
}
END {
for (p in pkg_stmts) {
if (pkg_stmts[p] == 0) continue
pct = (pkg_covered[p] / pkg_stmts[p]) * 100
status = "LOW"
if (pct >= 70.0) status = "GOOD"
else if (pct >= 30.0) status = "WARN"
printf "| `%s` | %.1f%% | %s |\n", p, pct, status
}
}
' "$COV_FILE" | sort)

SUMMARY_MD=$(cat <<EOF
## Go Test Coverage Report

**Overall Statement Coverage:** \`$TOTAL\`

| Package | Coverage | Status |
| :--- | :---: | :---: |
$PKG_ROWS

*Thresholds: GOOD &ge; 70% | WARN 30%–69% | LOW &lt; 30%*
EOF
)

# Output to stdout
echo "$SUMMARY_MD"

# If running in GitHub Actions, append to GITHUB_STEP_SUMMARY
if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "$SUMMARY_MD" >> "$GITHUB_STEP_SUMMARY"
fi
Loading