diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 2fd552b..524452e 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -3,8 +3,20 @@ on: push: branches: [main, master, develop] + paths: + - "**" + - "!docs/**" + - "!*.md" + - "!**/*.md" + - "docs/product/kaefa-core-api-contract.md" pull_request: branches: [main, master, develop] + paths: + - "**" + - "!docs/**" + - "!*.md" + - "!**/*.md" + - "docs/product/kaefa-core-api-contract.md" name: R-CMD-check diff --git a/.github/workflows/test-fast.yaml b/.github/workflows/test-fast.yaml index ea1cf69..d1afde6 100644 --- a/.github/workflows/test-fast.yaml +++ b/.github/workflows/test-fast.yaml @@ -3,8 +3,20 @@ name: test-fast on: push: branches: [main, master, develop] + paths: + - "**" + - "!docs/**" + - "!*.md" + - "!**/*.md" + - "docs/product/kaefa-core-api-contract.md" pull_request: branches: [main, master, develop] + paths: + - "**" + - "!docs/**" + - "!*.md" + - "!**/*.md" + - "docs/product/kaefa-core-api-contract.md" permissions: contents: read @@ -38,4 +50,6 @@ jobs: reporter = reporter) testthat::test_file("tests/testthat/test-core-api-contract.R", reporter = reporter) + testthat::test_file("tests/testthat/test-workflow-path-contract.R", + reporter = reporter) RSCRIPT diff --git a/.github/workflows/test-suite.yaml b/.github/workflows/test-suite.yaml index 439b9b7..eda8b99 100644 --- a/.github/workflows/test-suite.yaml +++ b/.github/workflows/test-suite.yaml @@ -10,8 +10,20 @@ name: test-suite on: push: branches: [main, master, develop] + paths: + - "**" + - "!docs/**" + - "!*.md" + - "!**/*.md" + - "docs/product/kaefa-core-api-contract.md" pull_request: branches: [main, master, develop] + paths: + - "**" + - "!docs/**" + - "!*.md" + - "!**/*.md" + - "docs/product/kaefa-core-api-contract.md" schedule: - cron: '17 3 * * 1' workflow_dispatch: diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 6ddd063..e85d685 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -57,9 +57,16 @@ explicitly requires vendored source integration. ## Quality and Security Gates - PR merge requires review approval and resolved conversations. -- Required checks include R-CMD-check matrix and dependency review. -- If code scanning is enabled later, alerts can be tracked via GitHub code - scanning APIs. +- Organization-owned required review and security gates run on every PR through + reusable workflows in `ContextualWisdomLab/.github`. +- Local `R-CMD-check`, `test-fast`, and `test-suite` workflows run for runtime, + package, workflow, `README.Rmd`, and public API contract changes. Plain + Markdown changes are excluded, except + `docs/product/kaefa-core-api-contract.md`, because + `tests/testthat/test-core-api-contract.R` consumes that file as executable + contract input. +- `tests/testthat/test-workflow-path-contract.R` prevents the API-contract + exception from silently disappearing when the trigger paths change. ## Change Rule diff --git a/NEWS.md b/NEWS.md index 38399b7..ad99fce 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,10 @@ +# kaefa (development version) + +* Reduced local R workflow load for prose-only Markdown changes while keeping + `docs/product/kaefa-core-api-contract.md` inside the package contract checks. +* Added a regression contract for the local workflow path filters and aligned + the architecture documentation with the live central/local gate boundary. + # kaefa 0.1.428.1 ## New Features @@ -24,4 +31,3 @@ This update addresses the need to set theta priors based on empirical raw score * Added a `NEWS.md` file to track changes to the package. - diff --git a/tests/testthat/test-workflow-path-contract.R b/tests/testthat/test-workflow-path-contract.R new file mode 100644 index 0000000..dd43aca --- /dev/null +++ b/tests/testthat/test-workflow-path-contract.R @@ -0,0 +1,48 @@ +workflow_lines <- function(name) { + readLines( + .kaefa_repo_file(".github", "workflows", name), + warn = FALSE + ) +} + +workflow_event_paths <- function(content, event_name) { + event_line <- match(paste0(" ", event_name, ":"), content) + if (is.na(event_line)) { + stop("Missing workflow event: ", event_name) + } + + remaining <- content[seq.int(event_line + 1L, length(content))] + paths_offset <- match(" paths:", remaining) + if (is.na(paths_offset)) { + stop("Missing paths list for workflow event: ", event_name) + } + + entries <- content[seq.int(event_line + paths_offset + 1L, length(content))] + entry_count <- rle(grepl('^ - "', entries))$lengths[1L] + if (!grepl('^ - "', entries[1L])) { + stop("Empty paths list for workflow event: ", event_name) + } + + sub('^ - "(.*)"$', "\\1", entries[seq_len(entry_count)]) +} + +test_that("runtime workflows keep the public API contract in scope", { + workflows <- c("R-CMD-check.yaml", "test-fast.yaml", "test-suite.yaml") + expected_paths <- c( + "**", + "!docs/**", + "!*.md", + "!**/*.md", + "docs/product/kaefa-core-api-contract.md" + ) + + for (workflow in workflows) { + content <- workflow_lines(workflow) + + expect_identical(workflow_event_paths(content, "push"), expected_paths) + expect_identical( + workflow_event_paths(content, "pull_request"), + expected_paths + ) + } +})