From 70378050381220e8451ba9fdd5249a03591a2e8d Mon Sep 17 00:00:00 2001 From: Michael Harp Date: Sat, 29 Aug 2026 08:01:02 -0400 Subject: [PATCH 1/2] Add GitHub Actions CI page and link DevKit from Hello OpenVox Add devkit/ci.md covering the voxpupuli/gha-puppet reusable workflow: the prerequisite (voxpupuli-test wired in, via the setup page or jig new module / jig convert), what the module needs first (Gemfile, Rakefile, metadata.json with an openvox or puppet requirement), the workflow file and its inputs, how the jobs map onto rake tasks, a lighter parser-validate-only alternative, and the failure modes seen when the prerequisites are missing. Add a Next Steps bullet on the Getting Started page pointing at the Developer Tooling section, which previously had no path there. Closes #464 Signed-off-by: Michael Harp Co-authored-by: Claude Fable 5 --- _data/nav/ecosystem_8x.yaml | 2 + docs/_ecosystem_8x/devkit/ci.md | 214 ++++++++++++++++++++ docs/_ecosystem_8x/getting_started/index.md | 1 + 3 files changed, 217 insertions(+) create mode 100644 docs/_ecosystem_8x/devkit/ci.md diff --git a/_data/nav/ecosystem_8x.yaml b/_data/nav/ecosystem_8x.yaml index 14ad1bbdd..6260a3cc1 100644 --- a/_data/nav/ecosystem_8x.yaml +++ b/_data/nav/ecosystem_8x.yaml @@ -35,6 +35,8 @@ link: "devkit/jig.html" - text: Consistent Style link: "devkit/linting.html" + - text: GitHub Actions CI + link: "devkit/ci.html" - text: Using VoxBox in CI link: "devkit/voxbox.html" - text: Unit Testing diff --git a/docs/_ecosystem_8x/devkit/ci.md b/docs/_ecosystem_8x/devkit/ci.md new file mode 100644 index 000000000..d2dcf5e5d --- /dev/null +++ b/docs/_ecosystem_8x/devkit/ci.md @@ -0,0 +1,214 @@ +--- +layout: default +title: "Module CI with GitHub Actions" +--- + +This page assumes your module already has the Vox Pupuli test suite wired in, so that `bundle exec rake validate lint` works locally. +If it doesn't yet, either [set up `voxpupuli-test`](setup.html#setting-up-the-vox-pupuli-test-suite) by hand, or let Jig do it: `jig new module` for a new module, or [`jig convert`](https://github.com/voxpupuli/jig/blob/main/docs/commands/convert.md) from the root of an existing one, which overwrites `Gemfile`, `Rakefile`, and `spec/spec_helper.rb` with the same templates `jig new module` uses. + +With that in place, the next step is to run the same tasks on every push and pull request. +Vox Pupuli publishes a set of [reusable GitHub Actions workflows](https://github.com/voxpupuli/gha-puppet) (`gha-puppet`) that do exactly that. +Nearly every module in the Vox Pupuli namespace uses them, and you can call them from your own repository with a workflow file of about ten lines. + +This page covers what the workflow expects to find in your module, how to call it, and what to do instead if you only want a quick syntax check. + +If you use GitLab CI or another runner, see [Using VoxBox in CI](voxbox.html) instead. +{: .tip } + +## What the workflow expects + +`gha-puppet` doesn't install tools or make assumptions about your module. +It checks out your repository, runs `bundle install`, and then calls the same rake tasks you run locally. +That means your module needs the same three files that the rest of the DevKit relies on: + +1. A `Gemfile` with a `test` group containing `voxpupuli-test` and `puppet_metadata`, and an `openvox` gem line that reads its version from the environment. + The workflow sets `OPENVOX_GEM_VERSION` to pick the release under test, so this is what lets it build a version matrix. + + ```ruby + source ENV['GEM_SOURCE'] || 'https://rubygems.org' + + group :test do + gem 'voxpupuli-test', '~> 14.0', :require => false + gem 'puppet_metadata', '~> 6.1', :require => false + end + + group :system_tests do + gem 'voxpupuli-acceptance', '~> 4.4', :require => false + end + + group :release do + gem 'voxpupuli-release', '~> 5.3', :require => false + end + + gem 'rake', :require => false + + gem 'openvox', ENV.fetch('OPENVOX_GEM_VERSION', [">= 7", "< 9"]), :require => false, :groups => [:test] + ``` + +2. A `Rakefile` that loads the `voxpupuli-test` tasks. + The `LoadError` rescues let the same file work when only some gem groups are installed, which is how CI keeps the static-check job small. + + ```ruby + begin + require 'voxpupuli/test/rake' + rescue LoadError + # only available if gem group test is installed + end + + begin + require 'voxpupuli/acceptance/rake' + rescue LoadError + # only available if gem group acceptance is installed + end + ``` + +3. A `metadata.json` with a `requirements` entry for `openvox` (or `puppet`; the tooling accepts either name) and, if you plan to add acceptance tests later, an `operatingsystem_support` list. + The workflow reads these to decide which OpenVox and Ruby versions to test against. + See the [module metadata reference](/openvox/latest/modules_metadata.html) for the full format. + +If you scaffolded your module with [`jig new module`](jig.html#creating-a-new-module), you already have all three. +If you ran `jig convert` on an existing module, you have the first two. +It works on PDK-generated and hand-maintained modules alike, but it insists on `metadata.json` already existing; if your module predates `metadata.json` and still carries a `Modulefile` (support for which was removed in Puppet 4), write `metadata.json` first, then run `jig convert`. + +## Adding the workflow + +Create `.github/workflows/ci.yml` in your module: + +```yaml +name: CI + +on: + pull_request: {} + push: + branches: + - main + +concurrency: + group: ${{ github.ref_name }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + puppet: + name: Puppet + uses: voxpupuli/gha-puppet/.github/workflows/basic.yml@v4 + with: + # Set to false if your module doesn't use Rubocop. + rubocop: true +``` + +Commit it, push, and open a pull request. You'll see three jobs under the **Puppet** heading: + +| Job | What it runs | +|-----|--------------| +| **Static validations** | `bundle exec rake validate lint check`, then `rake rubocop` (unless disabled), then `metadata2gha` to build the test matrix from `metadata.json` | +| **`` (Ruby ``)** | One job per supported OpenVox and Ruby combination, each running `bundle exec rake parallel_spec` | +| **Test suite** | A summary job that passes only if every job above passed. Use this one as your required status check in branch protection. | + +The reusable workflow accepts a few inputs under `with:`: + +| Input | Default | Purpose | +|-------|---------|---------| +| `rubocop` | `true` | Run the `rubocop` task. Set to `false` if your module has no Ruby code or doesn't inherit the Vox Pupuli Rubocop config. | +| `working-directory` | `.` | Path to the module when it lives in a subdirectory, such as a control repository's `site-modules/`. | +| `additional_packages` | `''` | Space-separated apt packages to install before the tests run, for gems with native extensions. | +| `timeout_minutes` | `45` | Cancel any job that runs longer than this. | +| `unit_runs_on` | `ubuntu-24.04` | Runner label for the unit-test jobs, for self-hosted runners. | + +The `gha-puppet` [README](https://github.com/voxpupuli/gha-puppet#readme) documents the full list, including the release workflow that Vox Pupuli uses to publish to the Forge. + +## Running the same checks locally + +Everything the workflow does maps onto a rake task, so you can reproduce a CI failure without pushing: + +```console +bundle exec rake validate lint check rubocop +bundle exec rake parallel_spec +``` + +Or run them all at once with `bundle exec rake test`. +The pages on [linting](linting.html) and [unit testing](unit_testing.html) explain what each task checks and how to configure it. + +To test against a specific OpenVox release the way the matrix does, set the same environment variable the workflow uses: + +```console +OPENVOX_GEM_VERSION='~> 8.0' bundle install +bundle exec rake parallel_spec +``` + +## Adding acceptance tests + +When you're ready to run your module against real operating systems, switch `basic.yml` to `beaker.yml` in the `uses:` line. +The beaker workflow runs everything above and then adds a job per platform listed in your `metadata.json`, using Docker on the GitHub-hosted runner. +The [acceptance testing guide](acceptance_testing.html#running-in-ci) covers what the tests themselves look like. + +## If you only want a syntax check + +The reusable workflow is the right tool for a module you maintain and publish. +For a one-off repository, or a module you're only validating before applying it with `puppet apply`, you might want something lighter that doesn't require adding a `Gemfile` and `Rakefile`. + +This workflow installs OpenVox as a gem and runs the parser and linter directly: + +```yaml +name: Validate + +on: + pull_request: {} + push: + branches: + - main + +permissions: + contents: read + +jobs: + validate: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - uses: ruby/setup-ruby@v1 + with: + ruby-version: '3.2' + - run: gem install openvox puppet-lint + - name: Check syntax + run: find manifests -name '*.pp' -print0 | xargs -0 puppet parser validate + - name: Lint + run: puppet-lint manifests +``` + +Be aware of what this doesn't catch. +`puppet parser validate` only checks that each file parses. +It won't notice a class that doesn't exist, a function from a module you forgot to declare as a dependency, or a template that renders garbage, because none of that is resolved until a catalog is compiled. +The `voxpupuli-test` unit tests catch all of those, which is why the reusable workflow is worth the extra setup as soon as the module matters. + +Neither workflow applies your manifest to a machine. +If that's what you want to verify, [acceptance tests](acceptance_testing.html) are the supported way to do it. +{: .tip } + +## Troubleshooting + +### `Could not locate Gemfile or .bundle/ directory` + +The **Static validations** job fails on its first step, and every unit job shows as skipped: + +```text +Run bundle exec rake validate lint check +Could not locate Gemfile or .bundle/ directory +Error: Process completed with exit code 10. +``` + +Your repository has no `Gemfile` at the path the workflow is looking at. +Add one as described in [What the workflow expects](#what-the-workflow-expects), or set `working-directory` if the module lives in a subdirectory. + +### `unit → skipped [required to succeed]` + +The **Test suite** job reports the unit matrix as skipped. +This is never the root cause; it means the **Static validations** job failed before `metadata2gha` could produce a matrix. +Open that job's log and fix the first error you see. + +### `metadata2gha` fails or produces an empty matrix + +`metadata.json` is missing, isn't valid JSON, or has no `requirements` entry for `openvox` or `puppet`. +Run `bundle exec rake metadata_lint` locally to see the specific complaint. diff --git a/docs/_ecosystem_8x/getting_started/index.md b/docs/_ecosystem_8x/getting_started/index.md index 97b6194ce..737bff066 100644 --- a/docs/_ecosystem_8x/getting_started/index.md +++ b/docs/_ecosystem_8x/getting_started/index.md @@ -266,3 +266,4 @@ Think of it as a blueprint: Puppet reads the blueprint, looks at the building, a * Using `puppet apply` is great for standalone work, but the real power of OpenVox comes from managing an entire infrastructure just as easily. [Learn about setting up an OpenVox Server](agent-server.html). * Maybe you'd rather learn more about the language first. Check out the [Puppet Language Intro](language.html). +* Ready to turn `hello.pp` into a module you can lint, test, and share? The [Developer Tooling guide](../devkit/index.html) walks through scaffolding, style checks, unit tests, and [running it all in CI](../devkit/ci.html). From 222d6544db88047def05eb0f58b9f58d8a7dfcb4 Mon Sep 17 00:00:00 2001 From: Michael Harp Date: Thu, 10 Sep 2026 09:07:36 -0400 Subject: [PATCH 2/2] Update the CI page for jig 2.4.0's convert behavior jig convert now creates a missing metadata.json (from a Modulefile or an interview) and repairs an invalid one, so the page no longer tells readers to write the file by hand first. Point the convert link at the Jig page on this site instead of jig's GitHub docs. Co-Authored-By: Claude Fable 5.1 Signed-off-by: Michael Harp --- docs/_ecosystem_8x/devkit/ci.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/_ecosystem_8x/devkit/ci.md b/docs/_ecosystem_8x/devkit/ci.md index d2dcf5e5d..64d25104e 100644 --- a/docs/_ecosystem_8x/devkit/ci.md +++ b/docs/_ecosystem_8x/devkit/ci.md @@ -4,7 +4,7 @@ title: "Module CI with GitHub Actions" --- This page assumes your module already has the Vox Pupuli test suite wired in, so that `bundle exec rake validate lint` works locally. -If it doesn't yet, either [set up `voxpupuli-test`](setup.html#setting-up-the-vox-pupuli-test-suite) by hand, or let Jig do it: `jig new module` for a new module, or [`jig convert`](https://github.com/voxpupuli/jig/blob/main/docs/commands/convert.md) from the root of an existing one, which overwrites `Gemfile`, `Rakefile`, and `spec/spec_helper.rb` with the same templates `jig new module` uses. +If it doesn't yet, either [set up `voxpupuli-test`](setup.html#setting-up-the-vox-pupuli-test-suite) by hand, or let Jig do it: `jig new module` for a new module, or [`jig convert`](jig.html#migrate-an-existing-module-to-jig) from the root of an existing one, which overwrites `Gemfile`, `Rakefile`, and `spec/spec_helper.rb` with the same templates `jig new module` uses. With that in place, the next step is to run the same tasks on every push and pull request. Vox Pupuli publishes a set of [reusable GitHub Actions workflows](https://github.com/voxpupuli/gha-puppet) (`gha-puppet`) that do exactly that. @@ -67,8 +67,9 @@ That means your module needs the same three files that the rest of the DevKit re See the [module metadata reference](/openvox/latest/modules_metadata.html) for the full format. If you scaffolded your module with [`jig new module`](jig.html#creating-a-new-module), you already have all three. -If you ran `jig convert` on an existing module, you have the first two. -It works on PDK-generated and hand-maintained modules alike, but it insists on `metadata.json` already existing; if your module predates `metadata.json` and still carries a `Modulefile` (support for which was removed in Puppet 4), write `metadata.json` first, then run `jig convert`. +If you ran `jig convert` (jig 2.4.0 or later) on an existing module, you have all three as well. +It works on PDK-generated and hand-maintained modules alike: when `metadata.json` is missing, `convert` creates it with an `openvox` requirements entry, pre-filled from a `Modulefile` if your module still carries one and completed from a short interview otherwise, and when the file exists but fails validation, `convert` repairs it. +Pass `--dry-run` to see what it would change first. ## Adding the workflow @@ -211,4 +212,4 @@ Open that job's log and fix the first error you see. ### `metadata2gha` fails or produces an empty matrix `metadata.json` is missing, isn't valid JSON, or has no `requirements` entry for `openvox` or `puppet`. -Run `bundle exec rake metadata_lint` locally to see the specific complaint. +Run `bundle exec rake metadata_lint` locally to see the specific complaint, or run `jig convert`, which creates a missing `metadata.json` and repairs one that fails validation.