diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..9813658 --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,47 @@ +# SPDX-FileCopyrightText: Copyright 2026 SAP SE or an SAP affiliate company +# +# SPDX-License-Identifier: Apache-2.0 +--- +name: CI + +"on": + push: + branches: [main] + pull_request: + +permissions: + contents: read + +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: golangci/golangci-lint-action@1e7e51e771db61008b38414a730f564565cf7c20 # v9 + with: + version: v2.10 + args: ./internal/common/... ./operators/c5c3/... ./operators/keystone/... + + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 + with: + go-version-file: go.work + - name: Run unit tests + run: make test + + test-integration: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 + with: + go-version-file: go.work + - name: Run integration tests + run: make test-integration diff --git a/.golangci.yml b/.golangci.yml index 7109c34..c45bf9d 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,26 +1,24 @@ +version: "2" + run: timeout: 5m linters: + default: none enable: - govet - errcheck - staticcheck - unused - - gosimple - ineffassign - - typecheck - gocritic - -issues: - exclude-rules: - - path: "zz_generated.*\\.go$" - linters: - - govet - - errcheck - - staticcheck - - unused - - gosimple - - ineffassign - - typecheck - - gocritic + exclusions: + rules: + - path: "zz_generated.*\\.go$" + linters: + - govet + - errcheck + - staticcheck + - unused + - ineffassign + - gocritic diff --git a/.planwerk/features/CC-0003-a003-add-minimal-github-actions-ci-workflow.json b/.planwerk/progress/CC-0003-a003-add-minimal-github-actions-ci-workflow.json similarity index 95% rename from .planwerk/features/CC-0003-a003-add-minimal-github-actions-ci-workflow.json rename to .planwerk/progress/CC-0003-a003-add-minimal-github-actions-ci-workflow.json index 02669b3..004cccb 100644 --- a/.planwerk/features/CC-0003-a003-add-minimal-github-actions-ci-workflow.json +++ b/.planwerk/progress/CC-0003-a003-add-minimal-github-actions-ci-workflow.json @@ -2,8 +2,8 @@ "feature_id": "CC-0003", "title": "A003: Add minimal GitHub Actions CI workflow", "slug": "a003-add-minimal-github-actions-ci-workflow", - "status": "prepared", - "phase": null, + "status": "processing", + "phase": "improving", "summary": "", "description": "**Size:** πŸ”§ small\n**Category:** infrastructure\n**Priority:** medium\n\n## Summary\n\nCreate a GitHub Actions CI workflow (`.github/workflows/ci.yaml`) that runs three parallel jobs β€” `lint`, `test`, and `test-integration` β€” on every PR and push to `main`. The workflow uses Go workspace mode via `go.work`, includes concurrency control to cancel superseded runs, and depends on the Makefile and Go workspace scaffolded by CC-0001.\n\n## Scope\n\n**Included:**\n- `.github/workflows/ci.yaml` with triggers on `push` to `main` and `pull_request`\n- `lint` job using `golangci/golangci-lint-action` against the Go workspace root\n- `test` job running `make test` (unit tests)\n- `test-integration` job running `make test-integration` (envtest-based integration tests)\n- `actions/setup-go` with Go version read from `go.mod` and module caching\n- SPDX license header (matching existing `reuse.yaml` / `deploy-docs.yaml` conventions)\n- `permissions: contents: read` (least privilege, matching `reuse.yaml`)\n- Concurrency group `${{ github.ref }}-${{ github.workflow }}` with `cancel-in-progress: true` (matching `mega-linter.yml` pattern)\n\n**Excluded (with rationale):**\n- Container image builds β€” CC-0007, separate workflow\n- Helm chart packaging/push β€” S017/S018, YAGNI until charts exist\n- E2E/Chainsaw tests β€” S018, requires kind cluster setup, not part of minimal CI\n- Code coverage reporting/thresholds β€” S018, YAGNI for the minimal CI gate\n- Branch protection rule configuration β€” repo setting, not a workflow file\n- Matrix builds per operator module β€” Makefile abstracts this via `OPERATORS` variable; Go workspace mode with `go.work` provides single cache/download\n\n## Visualization\n\n```mermaid\nflowchart TD\n trigger[\"Push to main / PR\"]\n\n trigger --> lint\n trigger --> test\n trigger --> integ\n\n subgraph lint[\"lint\"]\n L1[\"actions/checkout@v4\"] --> L2[\"actions/setup-go\"]\n L2 --> L3[\"golangci-lint-action\"]\n end\n\n subgraph test[\"test\"]\n T1[\"actions/checkout@v4\"] --> T2[\"actions/setup-go\"]\n T2 --> T3[\"make test\"]\n end\n\n subgraph integ[\"test-integration\"]\n I1[\"actions/checkout@v4\"] --> I2[\"actions/setup-go\"]\n I2 --> I3[\"make test-integration\"]\n end\n\n lint --> merge[\"PR Merge Gate\"]\n test --> merge\n integ --> merge\n```\n\n```mermaid\nsequenceDiagram\n participant Dev as Developer\n participant GH as GitHub\n participant CI as CI Workflow\n participant Lint as lint job\n participant Test as test job\n participant Integ as test-integration job\n\n Dev->>GH: Push / Open PR\n GH->>CI: Trigger ci.yaml\n par All jobs run in parallel\n CI->>Lint: golangci-lint-action\n CI->>Test: make test\n CI->>Integ: make test-integration\n end\n Lint-->>CI: pass/fail\n Test-->>CI: pass/fail\n Integ-->>CI: pass/fail\n CI-->>GH: All checks status\n GH-->>Dev: PR status update\n```\n\n## Key Components\n\n- **`.github/workflows/ci.yaml`** β€” Single workflow file with 3 parallel jobs. Follows existing conventions: SPDX header (`Copyright 2026 SAP SE or an SAP affiliate company`), `\"on\"` quoting, `ubuntu-latest`, `permissions: contents: read`. Uses `.yaml` extension matching `reuse.yaml` and `deploy-docs.yaml`\n- **`lint` job** β€” Uses `golangci/golangci-lint-action` (handles installation, caching, version pinning); targets the Go workspace root. No separate `actions/setup-go` needed β€” the action handles Go setup internally\n- **`test` job** β€” `actions/setup-go` with `go-version-file: go.mod` + module caching, then `make test`. Relies on CC-0001 Makefile iterating over `OPERATORS`\n- **`test-integration` job** β€” Same Go setup as `test`, then `make test-integration`. May require envtest binaries β€” depends on whether CC-0001's Makefile handles `setup-envtest` download within the target or needs a separate `make install-test-deps` step first\n- **Concurrency group** β€” `${{ github.ref }}-${{ github.workflow }}` with `cancel-in-progress: true`, mirroring `mega-linter.yml:32-34`\n- **Dependency** β€” Hard dependency on CC-0001 (Go workspace, Makefile targets, `.golangci.yml`) and CC-0002 (test infrastructure for `test-integration` to be meaningful)", "stories": [ @@ -322,6 +322,7 @@ "title": "Create `.github/workflows/ci.yaml` with SPDX header (Copyright 2026 SAP SE or an SAP affiliate company, Apache-2.0), `---` separator, workflow name `CI`, quoted `\"on\"` triggers (push branches: [main] + pull_request), top-level `permissions: contents: read`, concurrency group `${{ github.ref }}-${{ github.workflow }}` with cancel-in-progress: true (REQ-001, REQ-006, REQ-007, REQ-008)", "level": 1, "estimate_minutes": 15, + "status": "done", "requirements": [ "REQ-001", "REQ-006", @@ -334,6 +335,7 @@ "title": "Add `lint` job to ci.yaml β€” runs-on: ubuntu-latest, step 1: actions/checkout@v4, step 2: golangci/golangci-lint-action@v9 with `version: v2.10` pinned. No separate actions/setup-go step (action handles Go setup internally). No `needs:` key. (REQ-002, REQ-005)", "level": 1, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-002", "REQ-005" @@ -344,6 +346,7 @@ "title": "Add `test` job to ci.yaml β€” runs-on: ubuntu-latest, step 1: actions/checkout@v4, step 2: actions/setup-go@v5 with `go-version-file: go.work` (module caching enabled by default), step 3: name 'Run unit tests' with `run: make test`. No `needs:` key. (REQ-003, REQ-005)", "level": 1, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-003", "REQ-005" @@ -354,6 +357,7 @@ "title": "Add `test-integration` job to ci.yaml β€” runs-on: ubuntu-latest, step 1: actions/checkout@v4, step 2: actions/setup-go@v5 with `go-version-file: go.work` (identical to test job), step 3: name 'Run integration tests' with `run: make test-integration`. No `needs:` key. (REQ-004, REQ-005)", "level": 1, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-004", "REQ-005" @@ -364,6 +368,7 @@ "title": "Validate complete ci.yaml YAML syntax and GitHub Actions workflow schema correctness β€” valid `on`/`jobs`/`steps` structure, no YAML parsing errors, all action references use valid `owner/repo@version` format (REQ-001)", "level": 2, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-001" ] @@ -373,6 +378,7 @@ "title": "Verify SPDX header matches deploy-docs.yaml exactly: first line `# SPDX-FileCopyrightText: Copyright 2026 SAP SE or an SAP affiliate company`, second line `#`, third line `# SPDX-License-Identifier: Apache-2.0`, followed by `---` separator (REQ-008)", "level": 2, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-008" ] @@ -382,6 +388,7 @@ "title": "Verify concurrency group key is exactly `${{ github.ref }}-${{ github.workflow }}` with `cancel-in-progress: true`, matching mega-linter.yml lines 32-34 character-for-character (REQ-006)", "level": 2, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-006" ] @@ -391,6 +398,7 @@ "title": "Verify lint job has only 2 steps (checkout + golangci-lint-action), no actions/setup-go step, no working-directory override, and golangci-lint-action targets the workspace root implicitly (REQ-002)", "level": 2, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-002" ] @@ -400,6 +408,7 @@ "title": "Verify test and test-integration jobs both use `go-version-file: go.work` (not hardcoded `go-version:`), and that actions/setup-go module caching is not explicitly disabled (default cache: true) (REQ-003, REQ-004)", "level": 2, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-003", "REQ-004" @@ -410,6 +419,7 @@ "title": "Verify all three jobs (lint, test, test-integration) have no `needs:` key β€” confirming they run in parallel with no inter-job dependencies (REQ-005)", "level": 2, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-005" ] @@ -419,6 +429,7 @@ "title": "Add reference documentation for CI workflow: file location (.github/workflows/ci.yaml), trigger events, job descriptions (lint/test/test-integration), Go setup convention (go-version-file: go.work), concurrency behavior, dependency on CC-0001 Makefile targets and .golangci.yml (REQ-001 to REQ-008)", "level": 3, "estimate_minutes": 20, + "status": "done", "requirements": [ "REQ-001", "REQ-002", @@ -435,6 +446,7 @@ "title": "Cross-reference implementation against feature scope checklist β€” verify all 'Included' items present (triggers, lint, test, test-integration, setup-go, SPDX, permissions, concurrency) and all 'Excluded' items absent (no image builds, no helm, no E2E/Chainsaw, no coverage, no branch protection, no matrix builds) (all REQs)", "level": 3, "estimate_minutes": 10, + "status": "done", "requirements": [ "REQ-001", "REQ-002", @@ -590,8 +602,14 @@ "prepared": { "github_account": "berendt", "timestamp": "2026-02-22T22:51:47.893430" + }, + "processing": { + "github_account": "berendt", + "timestamp": "2026-03-01T09:29:26.354834" } }, + "github_pr": "https://github.com/C5C3/forge/pull/3", + "pr_number": 3, "execution_history": [ { "run_id": "e5b09a22-e1b5-4eda-9353-41e58bf3f3b2", @@ -606,6 +624,50 @@ "status": "done" } ] + }, + { + "run_id": "bfd8923c-7c70-46f8-9569-cf0e41335bc2", + "timestamp": "2026-03-01T09:45:06.550519", + "total_duration": 807.3583419322968, + "status": "completed", + "timings": [ + { + "name": "Level 1 (4 tasks)", + "duration": 105.38839960098267, + "type": "level", + "status": "done" + }, + { + "name": "Level 2 (6 tasks)", + "duration": 66.77299308776855, + "type": "level", + "status": "done" + }, + { + "name": "Level 3 (2 tasks)", + "duration": 198.62502026557922, + "type": "level", + "status": "done" + }, + { + "name": "[CC-0003] Code Review", + "duration": 156.1170859336853, + "type": "review", + "status": "done" + }, + { + "name": "[CC-0003] Improvements", + "duration": 146.03618097305298, + "type": "improve", + "status": "done" + }, + { + "name": "[CC-0003] Simplify", + "duration": 134.41866207122803, + "type": "simplify", + "status": "done" + } + ] } ] } \ No newline at end of file diff --git a/.planwerk/reviews/CC-0003-a003-add-minimal-github-actions-ci-workflow-review-1.json b/.planwerk/reviews/CC-0003-a003-add-minimal-github-actions-ci-workflow-review-1.json new file mode 100644 index 0000000..61148c9 --- /dev/null +++ b/.planwerk/reviews/CC-0003-a003-add-minimal-github-actions-ci-workflow-review-1.json @@ -0,0 +1,69 @@ +{ + "feature_id": "CC-0003", + "title": "A003: Add minimal GitHub Actions CI workflow", + "date": "2026-03-01", + "verdict": "APPROVED", + "summary": "Minimal GitHub Actions CI workflow implemented as a single `.github/workflows/ci.yaml` file with three parallel jobs (lint, test, test-integration). Follows all specified conventions: SPDX header, quoted `\"on\"`, `permissions: contents: read`, concurrency group matching mega-linter.yml. Reference documentation added at `docs/ci-workflow.md`. All plan tasks (1.1-1.4, 2.1-2.6, 3.1-3.2) are fulfilled. No excluded scope items present.", + "tests_checklist": [ + {"item": "YAML syntax validated (yaml.safe_load parses without error)", "checked": true}, + {"item": "GitHub Actions schema structure validated (name, on, permissions, concurrency, jobs keys present and correct)", "checked": true}, + {"item": "All three jobs verified parallel (no `needs:` keys)", "checked": true}, + {"item": "Action versions validated (checkout@v4, golangci-lint-action@v9 with v2.10, setup-go@v5)", "checked": true}, + {"item": "go-version-file: go.work confirmed (not hardcoded go-version)", "checked": true}, + {"item": "Module caching not explicitly disabled (actions/setup-go default cache: true)", "checked": true} + ], + "code_quality_checklist": [ + {"item": "Follows existing project conventions (SPDX header, .yaml extension, quoted on)", "checked": true}, + {"item": "Minimal and focused β€” 46 lines, no unnecessary configuration", "checked": true}, + {"item": "No dead code or commented-out sections", "checked": true}, + {"item": "Clear step naming (Run unit tests, Run integration tests)", "checked": true}, + {"item": "File location matches project structure (.github/workflows/)", "checked": true} + ], + "security_checklist": [ + {"item": "Least-privilege permissions: top-level `contents: read` only", "checked": true}, + {"item": "No job-level permission overrides", "checked": true}, + {"item": "No secrets referenced or hardcoded", "checked": true}, + {"item": "No workflow_dispatch trigger (prevents unauthorized manual runs)", "checked": true}, + {"item": "Actions pinned to major versions (@v4, @v9, @v5)", "checked": true} + ], + "architecture_checklist": [ + {"item": "Solution is minimal β€” three jobs, no complex dependencies or matrix builds", "checked": true}, + {"item": "Delegates to Makefile targets (test, test-integration) β€” no duplicated build logic", "checked": true}, + {"item": "Uses go.work for Go version (single source of truth)", "checked": true}, + {"item": "Concurrency group scoped per-branch per-workflow", "checked": true} + ], + "dry_yagni_checklist": [ + {"item": "No duplicated configuration across jobs (only necessary per-job setup)", "checked": true}, + {"item": "No excluded scope items present (no image builds, helm, E2E, coverage, matrix)", "checked": true}, + {"item": "No future-proofing or over-engineering", "checked": true} + ], + "fail_fast_checklist": [ + {"item": "Concurrency cancel-in-progress cancels superseded runs immediately", "checked": true}, + {"item": "Jobs run in parallel for fastest feedback", "checked": true} + ], + "defensive_checklist": [ + {"item": "Permissions restricted to minimum required (contents: read)", "checked": true}, + {"item": "No external inputs or user-controlled parameters in workflow", "checked": true} + ], + "security_findings": [], + "architecture_findings": [], + "issues_found": [ + { + "id": "NOTE-1", + "severity": "info", + "check_id": "C5", + "description": "The `make test-integration` target in the Makefile is currently a stub that calls `$(error ...)` on main. The CI job will fail until this target is properly implemented. This is a known dependency (CC-0002 scope item S002) and not a defect in the CI workflow itself β€” the workflow correctly delegates to the Makefile target.", + "location": "Makefile:73-74", + "fix": "No action required for CC-0003. The Makefile target will be implemented by the relevant future task." + } + ], + "suggested_improvements": [ + "Consider pinning actions to full SHA refs (e.g., actions/checkout@) instead of major version tags for supply-chain hardening β€” this is a future enhancement, not blocking for the minimal CI gate", + "When the `test-integration` Makefile target is implemented, verify the CI job passes end-to-end on a real PR" + ], + "next_steps": [ + "Merge this workflow and verify all three jobs execute successfully on the first real PR", + "Configure branch protection rules (repo setting) to require lint, test, and test-integration as required status checks", + "Implement the `test-integration` Makefile target (S002 dependency) so the test-integration CI job passes" + ] +} diff --git a/.planwerk/reviews/CC-0003-github-review-by-sourcery-ai-bot-external-1.json b/.planwerk/reviews/CC-0003-github-review-by-sourcery-ai-bot-external-1.json new file mode 100644 index 0000000..f269041 --- /dev/null +++ b/.planwerk/reviews/CC-0003-github-review-by-sourcery-ai-bot-external-1.json @@ -0,0 +1,35 @@ +{ + "feature_id": "CC-0003", + "title": "GitHub Review by sourcery-ai[bot]", + "summary": "Hey - I've found 1 issue, and left some high level feedback:\n\n- Consider adding `paths` / `paths-ignore` filters to the workflow triggers so that docs-only or non-Go changes don’t unnecessarily run the full CI pipeline.\n- It may be useful to set explicit `timeout-minutes` values on each job (lint, test, test-integration) to avoid hanging runs consuming runners indefinitely if something stalls.\n\n
\nPrompt for AI Agents\n\n~~~markdown\nPlease address the comments from this code review:\n\n## Overall Comments\n- Consider adding `paths` / `paths-ignore` filters to the workflow triggers so that docs-only or non-Go changes don’t unnecessarily run the full CI pipeline.\n- It may be useful to set explicit `timeout-minutes` values on each job (lint, test, test-integration) to avoid hanging runs consuming runners indefinitely if something stalls.\n\n## Individual Comments\n\n### Comment 1\n\n\n+ - name: Run unit tests\n+ run: make test\n+\n+ test-integration:\n+ runs-on: ubuntu-latest\n+ steps:\n+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n+ - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5\n+ with:\n+ go-version-file: go.work\n+ - name: Run integration tests\n+ run: make test-integration\n\n\n**suggestion (testing):** Adding explicit timeouts for long-running integration tests can prevent stuck workflows.\n\nSince `make test-integration` may depend on external services and could hang, please configure `timeout-minutes` on this job (or the test step) so a stuck run doesn’t block runners indefinitely.\n\n```suggestion\n test-integration:\n runs-on: ubuntu-latest\n timeout-minutes: 30\n```\n\n~~~\n\n
\n\n***\n\n
\nSourcery is free for open source - if you like our reviews please consider sharing them ✨\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https://sourcery.ai)\n- [Facebook](https://www.facebook.com/sharer/sharer.php?u=https://sourcery.ai)\n\n
\n\n\nHelp me be more useful! Please click πŸ‘ or πŸ‘Ž on each comment and I'll use the feedback to improve your reviews.\n", + "verdict": "NEEDS_CHANGES", + "tests_checklist": [], + "code_quality_checklist": [], + "security_checklist": [], + "architecture_checklist": [], + "dry_yagni_checklist": [], + "fail_fast_checklist": [], + "defensive_checklist": [], + "security_findings": [], + "architecture_findings": [], + "issues_found": [], + "suggested_improvements": [], + "next_steps": [], + "reviewer": "sourcery-ai[bot]", + "date": "2026-03-01T11:38:24Z", + "commit_reference": "", + "review_type": "external", + "sequence_number": 1, + "external_feedback": "Hey - I've found 1 issue, and left some high level feedback:\n\n- Consider adding `paths` / `paths-ignore` filters to the workflow triggers so that docs-only or non-Go changes don’t unnecessarily run the full CI pipeline.\n- It may be useful to set explicit `timeout-minutes` values on each job (lint, test, test-integration) to avoid hanging runs consuming runners indefinitely if something stalls.\n\n
\nPrompt for AI Agents\n\n~~~markdown\nPlease address the comments from this code review:\n\n## Overall Comments\n- Consider adding `paths` / `paths-ignore` filters to the workflow triggers so that docs-only or non-Go changes don’t unnecessarily run the full CI pipeline.\n- It may be useful to set explicit `timeout-minutes` values on each job (lint, test, test-integration) to avoid hanging runs consuming runners indefinitely if something stalls.\n\n## Individual Comments\n\n### Comment 1\n\n\n+ - name: Run unit tests\n+ run: make test\n+\n+ test-integration:\n+ runs-on: ubuntu-latest\n+ steps:\n+ - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4\n+ - uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5\n+ with:\n+ go-version-file: go.work\n+ - name: Run integration tests\n+ run: make test-integration\n\n\n**suggestion (testing):** Adding explicit timeouts for long-running integration tests can prevent stuck workflows.\n\nSince `make test-integration` may depend on external services and could hang, please configure `timeout-minutes` on this job (or the test step) so a stuck run doesn’t block runners indefinitely.\n\n```suggestion\n test-integration:\n runs-on: ubuntu-latest\n timeout-minutes: 30\n```\n\n~~~\n\n
\n\n***\n\n
\nSourcery is free for open source - if you like our reviews please consider sharing them ✨\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20got%20an%20instant%20code%20review%20from%20%40SourceryAI%2C%20and%20it%20was%20brilliant%21%20It%27s%20free%20for%20open%20source%20and%20has%20a%20free%20trial%20for%20private%20code.%20Check%20it%20out%20https%3A//sourcery.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https://sourcery.ai)\n- [Facebook](https://www.facebook.com/sharer/sharer.php?u=https://sourcery.ai)\n\n
\n\n\nHelp me be more useful! Please click πŸ‘ or πŸ‘Ž on each comment and I'll use the feedback to improve your reviews.\n", + "code_comments": [ + { + "body": "**suggestion (testing):** Adding explicit timeouts for long-running integration tests can prevent stuck workflows.\n\nSince `make test-integration` may depend on external services and could hang, please configure `timeout-minutes` on this job (or the test step) so a stuck run doesn’t block runners indefinitely.\n\n```suggestion\n test-integration:\n runs-on: ubuntu-latest\n timeout-minutes: 30\n```", + "path": ".github/workflows/ci.yaml", + "line": 39, + "author": "sourcery-ai[bot]", + "created_at": "2026-03-01T11:38:24Z", + "id": null + } + ], + "github_review_id": 3871953393 +} \ No newline at end of file diff --git a/docs/ci-workflow.md b/docs/ci-workflow.md new file mode 100644 index 0000000..1466219 --- /dev/null +++ b/docs/ci-workflow.md @@ -0,0 +1,111 @@ + + +--- +title: CI Workflow +quadrant: infrastructure +--- + +# CI Workflow + +Reference documentation for the GitHub Actions CI workflow (`.github/workflows/ci.yaml`). + +## File Location + +```text +.github/workflows/ci.yaml +``` + +## Trigger Events + +The workflow triggers on: + +- **`push`** to the `main` branch β€” runs CI on every direct push to main. +- **`pull_request`** (all activity types) β€” runs CI on PR open, synchronize, and reopen. + +Pushes to non-main branches without an open PR do **not** trigger the workflow. + +## Jobs + +All three jobs run in **parallel** with no inter-job dependencies (`needs:` is absent). +Each job uses `runs-on: ubuntu-latest`. + +### `lint` + +Runs golangci-lint against the Go workspace root. + +| Step | Action | +| --- | --- | +| 1 | `actions/checkout` (SHA-pinned, v4) | +| 2 | `golangci/golangci-lint-action` (SHA-pinned, v9) with `version: v2.10` | + +The golangci-lint-action handles Go installation internally β€” no separate `actions/setup-go` step is needed. The action reads the project's `.golangci.yml` for linter configuration. + +### `test` + +Runs unit tests via the Makefile. + +| Step | Action | +| --- | --- | +| 1 | `actions/checkout` (SHA-pinned, v4) | +| 2 | `actions/setup-go` (SHA-pinned, v5) with `go-version-file: go.work` | +| 3 | `make test` | + +### `test-integration` + +Runs envtest-based integration tests via the Makefile. + +| Step | Action | +| --- | --- | +| 1 | `actions/checkout` (SHA-pinned, v4) | +| 2 | `actions/setup-go` (SHA-pinned, v5) with `go-version-file: go.work` | +| 3 | `make test-integration` | + +## Go Setup Convention + +Both `test` and `test-integration` jobs use `actions/setup-go@v5` with: + +- **`go-version-file: go.work`** β€” the Go version is read from the workspace file rather than hardcoded, so upgrading Go only requires updating `go.work`. +- **Module caching** β€” enabled by default in `actions/setup-go@v5` (caches `~/go/pkg/mod`). Not explicitly disabled. + +The `lint` job does not use a separate `actions/setup-go` step because `golangci-lint-action` manages Go installation internally. + +## Concurrency + +```yaml +concurrency: + group: ${{ github.ref }}-${{ github.workflow }} + cancel-in-progress: true +``` + +- Scoped per-branch per-workflow: pushing to branch A does not cancel runs on branch B. +- New pushes to the same branch cancel any in-progress CI run for that branch. +- Matches the concurrency pattern used in `mega-linter.yml`. + +## Permissions + +```yaml +permissions: + contents: read +``` + +Top-level `contents: read` applies to all jobs (least-privilege). No job-level `permissions:` overrides exist. + +## Dependencies + +This workflow depends on artifacts from [CC-0001](https://github.com/C5C3/forge/pull/1): + +- **`go.work`** β€” used by `actions/setup-go` to determine the Go version. +- **`Makefile`** β€” provides `test` and `test-integration` targets that iterate over operator modules via the `OPERATORS` variable. +- **`.golangci.yml`** β€” linter configuration consumed by `golangci-lint-action`. + +## Conventions + +- **SPDX header**: `Copyright 2026 SAP SE or an SAP affiliate company`, `Apache-2.0` β€” matching `deploy-docs.yaml`. +- **File extension**: `.yaml` (not `.yml`) β€” matching `reuse.yaml` and `deploy-docs.yaml`. +- **`"on"` quoting**: the trigger key is quoted to prevent YAML boolean interpretation. +- **YAML document separator**: `---` follows the SPDX header block. +- **SHA-pinned actions**: all `uses:` references pin to full 40-character commit SHAs with a version comment (e.g., `actions/checkout@ # v4`). This prevents supply-chain attacks via mutable tags. When updating an action version, resolve the new tag to its commit SHA and update both the hash and the comment.