From 91222bbb4f062e17ea11d2ffeb0490c955bb399d Mon Sep 17 00:00:00 2001 From: Sugat <233906380+SugatD@users.noreply.github.com> Date: Thu, 28 May 2026 12:53:26 +0530 Subject: [PATCH 1/4] (MODULES-11816) Add CLAUDE.md for Claude Code guidance MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document the module's three-layer architecture (globals → params → server), custom types/providers, Hiera data layout, validate/spec/Litmus commands, spec conventions, lint customizations, and how the CI matrix is built. --- CLAUDE.md | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..468b54bb0c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,99 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Module overview + +`puppetlabs-postgresql` manages PostgreSQL packages, services, databases, roles, grants, and `pg_hba.conf` / `pg_ident.conf` rules across RHEL-family, Debian-family, SLES, Arch, Gentoo, FreeBSD, and OpenBSD. The Puppet Forge entry point is `class { 'postgresql::server': }`, but every consumer is expected to declare `postgresql::globals` first (see Architecture). + +## Architecture + +The module has a three-layer composition that you must understand before changing anything in `manifests/`: + +1. **`manifests/globals.pp`** — sole source of truth for version + OS detection. Resolves `$default_version` from `$facts['os']['family']`, `$facts['os']['name']`, and `$facts['os']['release']['major']` (a nested selector hash, ~70 lines). Also resolves `$default_postgis_version`. Optionally configures the PGDG yum/apt repo via `postgresql::repo`, or enables `postgresql::dnfmodule` on EL8+/Fedora. **Must be included before `postgresql::server`** — `postgresql::server` reads `$postgresql::globals::default_version` to decide package names. Adding a new OS or version means editing the selector here. + +2. **`manifests/params.pp`** — translates the resolved version into package/service/path names per OS. Has a critical branch: if `$version == $default_version` (and not Amazon Linux), it uses unversioned package names (`postgresql`, `postgresql-server`) from the OS base repo; otherwise it constructs versioned names (`postgresql16-server`) for the PGDG repo. Changing default version mappings without understanding this branch will break either base-repo or PGDG installs. + +3. **`manifests/server.pp` + `manifests/server/`** — the user-facing API. `server.pp` orchestrates `install` → `initdb` → `config` → `service` → `reload`. The defined types under `manifests/server/` (`db.pp`, `role.pp`, `grant.pp`, `database_grant.pp`, `default_privileges.pp`, `extension.pp`, `pg_hba_rule.pp`, `schema.pp`, `tablespace.pp`, `table_grant.pp`, etc.) are the public interface — each one ultimately fires a `postgresql_psql` custom resource. + +**Multi-instance support** (`manifests/server_instance.pp` + `manifests/server/instance/`) is opt-in and currently tested only on RHEL 8 / CentOS Stream 8 — see the warning at `manifests/server_instance.pp:39`. Treat changes there as RHEL-8-specific unless explicitly broadening scope. + +**Hiera-driven OS defaults**: `hiera.yaml` is keyed by `os.name`/`os.family` + `os.release.major`. Per-OS YAML lives in `data/os//.yaml` and `data/os/.yaml`. Add new-OS defaults here rather than hard-coding them in `params.pp` when possible. + +**Custom types and providers** (`lib/puppet/`) — these are the actual workhorses; the manifests just wire them: +- `postgresql_psql` (type + provider in `lib/puppet/type/postgresql_psql.rb` and `lib/puppet/provider/postgresql_psql/ruby.rb`): runs idempotent SQL via the `unless`/`onlyif` query pattern. Every `server::*` defined type funnels through this. +- `postgresql_conf`: manages `postgresql.conf` entries as resources. +- `postgresql_conn_validator`: connectivity check; backed by `lib/puppet/util/postgresql_validator.rb`. +- `postgresql_replication_slot`: replication slot management. +- Functions in `lib/puppet/functions/`: `postgresql_password` (md5/scram-sha-256 hashing), `postgresql_escape` (dollar-quoting), plus the `postgresql::` namespace. +- Puppet type aliases in `types/`: `pg_hba_rule`, `pg_hba_rules`, `pg_password_encryption`, etc. — used as parameter types in the manifests. + +## Common commands + +All commands assume `bundle install --path=vendor` has been run. + +**Validation (run before pushing):** +```sh +bundle exec rake validate # puppet syntax + lint + metadata-json-lint +bundle exec rake lint # puppet-lint only +bundle exec rake rubocop # Ruby style for lib/ and spec/ +``` + +**Unit tests:** +```sh +bundle exec rake spec # full unit suite (rspec-puppet + lib specs) +bundle exec rake parallel_spec # same, parallelized — preferred for full runs +bundle exec rspec spec/classes/globals_spec.rb # one file +bundle exec rspec spec/classes/globals_spec.rb -e "RedHat 8" # one example +``` + +`rake spec` automatically runs `spec_prep` first, which clones the fixture modules listed in `.fixtures.yml` into `spec/fixtures/modules/`. If fixtures get stale after dependency changes, run `bundle exec rake spec_clean && bundle exec rake spec_prep`. + +**Acceptance tests (Litmus, run against a real container/VM):** +```sh +bundle exec rake 'litmus:provision[docker,litmusimage/almalinux:9]' +bundle exec rake 'litmus:install_agent' +bundle exec rake 'litmus:install_module' +bundle exec rake 'litmus:acceptance:parallel' +bundle exec rake 'litmus:tear_down' +``` + +A single acceptance spec, against an already-provisioned target listed in `spec/fixtures/litmus_inventory.yaml`: +```sh +bundle exec rspec spec/acceptance/server_spec.rb +``` + +**Reference docs:** `REFERENCE.md` is generated from puppet-strings annotations on classes/defines/types. Regenerate with `bundle exec rake strings:generate:reference` after editing parameter documentation. + +## Spec layout conventions + +- `spec/classes/` — `rspec-puppet` catalog tests for classes in `manifests/`. +- `spec/defines/` — `rspec-puppet` for defined types. +- `spec/functions/` — function tests. +- `spec/type_aliases/` — tests for Puppet type aliases in `types/`. +- `spec/unit/{type,provider,puppet}/` — pure Ruby tests for `lib/puppet/`. +- `spec/acceptance/` — Litmus tests; run on provisioned hosts, NOT in unit runs. + +`spec/spec_helper_local.rb` defines `shared_context` blocks for OSes (`'RedHat 8'`, `'Debian 11'`, etc.) backed by `rspec-puppet-facts`. When adding tests for a new OS, prefer adding a `shared_context` here over inlining fact hashes. Use `include_examples 'RedHat 8'` (note: `include_examples`, not `include_context` — that's the project convention). + +## Lint and style customizations + +`.puppet-lint.rc` and the `Rakefile` disable: `80chars`, `140chars`, `class_inherits_from_params_class`, `autoloader_layout`, `documentation`, `single_quote_string_with_variables`, `anchor_resource`, `params_empty_string_assignment`, `relative`. `fail_on_warnings` is **on** — any new puppet-lint warning will fail CI. The lint ignores `types/**/*.pp` (Puppet type aliases use a different syntax that puppet-lint doesn't grok well). + +RuboCop config lives in `.rubocop.yml` with overrides for puppet-module style. Existing exceptions are tracked in `.rubocop_todo.yml` — prefer fixing offenses over adding to the todo list. + +## CI + +`.github/workflows/ci.yml` and `nightly.yml` are thin shims that call reusable workflows from `puppetlabs/cat-github-actions`: +- `module_ci.yml` runs `rake validate` and `rake parallel_spec`. +- `module_acceptance.yml` runs Litmus against a matrix built by `matrix_from_metadata_v3`, which reads `metadata.json`'s `operatingsystem_support` and cross-references the platform catalog in `puppetlabs/puppet_litmus/exe/matrix.json`. **Adding an OS/version to `metadata.json` does NOT automatically produce a CI job** — `puppet_litmus`'s matrix.json must also have a Docker image or provision-service entry for that platform. + +## Conventions when committing + +- Branch names follow `MODULES-` (the Jira project key). For test-PR runs of community PRs, the convention used here is `MODULES--pr`. +- Commit messages and PR titles start with `(MODULES-XXXX)` — the Jira automation uses this to link commits back to tickets. +- When cherry-picking community PRs, squash to one commit and add a `Co-authored-by:` trailer for the original contributor. + +## Dependency boundaries + +`metadata.json` declares the supported Puppet (`>= 8.0.0 < 9.0.0`) and module-dependency ranges. The hard runtime dependencies are `puppetlabs/stdlib`, `puppetlabs/apt`, `puppet/systemd`, `puppetlabs/concat`. Don't introduce new module dependencies without an explicit Jira ticket — they propagate to every consumer. From 03230a8dd5087fcb43d808549a1e42611699d3e6 Mon Sep 17 00:00:00 2001 From: Sugat <233906380+SugatD@users.noreply.github.com> Date: Thu, 28 May 2026 13:16:19 +0530 Subject: [PATCH 2/4] (MODULES-11816) Update branch-name convention in CLAUDE.md Branch names now follow - (e.g. MODULES-11816-add-claude-md) instead of just the bare ticket id. Test-PR runs of community PRs still use the -pr pattern. --- CLAUDE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CLAUDE.md b/CLAUDE.md index 468b54bb0c..e9ca491969 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -90,7 +90,7 @@ RuboCop config lives in `.rubocop.yml` with overrides for puppet-module style. E ## Conventions when committing -- Branch names follow `MODULES-` (the Jira project key). For test-PR runs of community PRs, the convention used here is `MODULES--pr`. +- Branch names follow `-`, where `` is the Jira ticket key (e.g. `MODULES-11816-add-claude-md`, `MODULES-12345-fix-el10-default-version`). Keep the trailing slug short, kebab-cased, and descriptive of the change. For test-PR runs of community PRs, the convention used here is `-pr` (e.g. `MODULES-11807-pr1650`). - Commit messages and PR titles start with `(MODULES-XXXX)` — the Jira automation uses this to link commits back to tickets. - When cherry-picking community PRs, squash to one commit and add a `Co-authored-by:` trailer for the original contributor. From baa872ac68464f632e4455f1b535f8c92fd0529b Mon Sep 17 00:00:00 2001 From: Sugat <233906380+SugatD@users.noreply.github.com> Date: Thu, 28 May 2026 14:07:54 +0530 Subject: [PATCH 3/4] (MODULES-11816) Refactor CLAUDE.md to avoid duplicating authoritative sources Address review feedback from @bastelfreak: drop content that duplicates existing single-sources-of-truth (OS list, dependency versions, lint disabled-checks, custom type/provider enumeration, spec subdirectory listing). Replace with an explicit "Authoritative sources" table that points readers at the real file for each piece of information. Keeps the non-discoverable content: three-layer architecture, the default-vs-versioned package-name branch in params.pp, the include_examples convention, and how the CI matrix is actually built. --- CLAUDE.md | 86 +++++++++++++++++++++---------------------------------- 1 file changed, 32 insertions(+), 54 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e9ca491969..410fc4f5aa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,96 +4,74 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Module overview -`puppetlabs-postgresql` manages PostgreSQL packages, services, databases, roles, grants, and `pg_hba.conf` / `pg_ident.conf` rules across RHEL-family, Debian-family, SLES, Arch, Gentoo, FreeBSD, and OpenBSD. The Puppet Forge entry point is `class { 'postgresql::server': }`, but every consumer is expected to declare `postgresql::globals` first (see Architecture). +`puppetlabs-postgresql` manages PostgreSQL packages, services, databases, roles, grants, and `pg_hba.conf` / `pg_ident.conf` rules. Entry point is `class { 'postgresql::server': }`, but every consumer is expected to declare `postgresql::globals` first (see Architecture). Supported OSes, Puppet version range, and module dependencies are declared in `metadata.json` — treat that as the single source of truth. ## Architecture -The module has a three-layer composition that you must understand before changing anything in `manifests/`: +The module has a three-layer composition that must be understood before changing anything in `manifests/`: 1. **`manifests/globals.pp`** — sole source of truth for version + OS detection. Resolves `$default_version` from `$facts['os']['family']`, `$facts['os']['name']`, and `$facts['os']['release']['major']` (a nested selector hash, ~70 lines). Also resolves `$default_postgis_version`. Optionally configures the PGDG yum/apt repo via `postgresql::repo`, or enables `postgresql::dnfmodule` on EL8+/Fedora. **Must be included before `postgresql::server`** — `postgresql::server` reads `$postgresql::globals::default_version` to decide package names. Adding a new OS or version means editing the selector here. 2. **`manifests/params.pp`** — translates the resolved version into package/service/path names per OS. Has a critical branch: if `$version == $default_version` (and not Amazon Linux), it uses unversioned package names (`postgresql`, `postgresql-server`) from the OS base repo; otherwise it constructs versioned names (`postgresql16-server`) for the PGDG repo. Changing default version mappings without understanding this branch will break either base-repo or PGDG installs. -3. **`manifests/server.pp` + `manifests/server/`** — the user-facing API. `server.pp` orchestrates `install` → `initdb` → `config` → `service` → `reload`. The defined types under `manifests/server/` (`db.pp`, `role.pp`, `grant.pp`, `database_grant.pp`, `default_privileges.pp`, `extension.pp`, `pg_hba_rule.pp`, `schema.pp`, `tablespace.pp`, `table_grant.pp`, etc.) are the public interface — each one ultimately fires a `postgresql_psql` custom resource. +3. **`manifests/server.pp` + `manifests/server/`** — the user-facing API. `server.pp` orchestrates `install` → `initdb` → `config` → `service` → `reload`. The defined types under `manifests/server/` are the public interface — each one ultimately fires a `postgresql_psql` custom resource (see `lib/puppet/type/postgresql_psql.rb`). **Multi-instance support** (`manifests/server_instance.pp` + `manifests/server/instance/`) is opt-in and currently tested only on RHEL 8 / CentOS Stream 8 — see the warning at `manifests/server_instance.pp:39`. Treat changes there as RHEL-8-specific unless explicitly broadening scope. -**Hiera-driven OS defaults**: `hiera.yaml` is keyed by `os.name`/`os.family` + `os.release.major`. Per-OS YAML lives in `data/os//.yaml` and `data/os/.yaml`. Add new-OS defaults here rather than hard-coding them in `params.pp` when possible. +**Custom types and providers** live in `lib/puppet/{type,provider}/`. The workhorse is `postgresql_psql`, which runs idempotent SQL via the `unless`/`onlyif` query pattern — every `server::*` defined type funnels through it. The manifests are mostly orchestration; the actual work happens in these Ruby files. -**Custom types and providers** (`lib/puppet/`) — these are the actual workhorses; the manifests just wire them: -- `postgresql_psql` (type + provider in `lib/puppet/type/postgresql_psql.rb` and `lib/puppet/provider/postgresql_psql/ruby.rb`): runs idempotent SQL via the `unless`/`onlyif` query pattern. Every `server::*` defined type funnels through this. -- `postgresql_conf`: manages `postgresql.conf` entries as resources. -- `postgresql_conn_validator`: connectivity check; backed by `lib/puppet/util/postgresql_validator.rb`. -- `postgresql_replication_slot`: replication slot management. -- Functions in `lib/puppet/functions/`: `postgresql_password` (md5/scram-sha-256 hashing), `postgresql_escape` (dollar-quoting), plus the `postgresql::` namespace. -- Puppet type aliases in `types/`: `pg_hba_rule`, `pg_hba_rules`, `pg_password_encryption`, etc. — used as parameter types in the manifests. +**Hiera-driven OS defaults**: `hiera.yaml` is keyed by `os.name`/`os.family` + `os.release.major`. Per-OS YAML lives in `data/os//.yaml` and `data/os/.yaml`. Add new-OS defaults here rather than hard-coding them in `params.pp` when possible. ## Common commands -All commands assume `bundle install --path=vendor` has been run. +Assume `bundle install --path=vendor` has been run. -**Validation (run before pushing):** ```sh -bundle exec rake validate # puppet syntax + lint + metadata-json-lint -bundle exec rake lint # puppet-lint only -bundle exec rake rubocop # Ruby style for lib/ and spec/ -``` - -**Unit tests:** -```sh -bundle exec rake spec # full unit suite (rspec-puppet + lib specs) -bundle exec rake parallel_spec # same, parallelized — preferred for full runs +bundle exec rake validate # puppet syntax + lint + metadata-json-lint (run before pushing) +bundle exec rake parallel_spec # full unit suite, parallelized — preferred over `rake spec` for full runs bundle exec rspec spec/classes/globals_spec.rb # one file bundle exec rspec spec/classes/globals_spec.rb -e "RedHat 8" # one example -``` - -`rake spec` automatically runs `spec_prep` first, which clones the fixture modules listed in `.fixtures.yml` into `spec/fixtures/modules/`. If fixtures get stale after dependency changes, run `bundle exec rake spec_clean && bundle exec rake spec_prep`. -**Acceptance tests (Litmus, run against a real container/VM):** -```sh bundle exec rake 'litmus:provision[docker,litmusimage/almalinux:9]' bundle exec rake 'litmus:install_agent' bundle exec rake 'litmus:install_module' bundle exec rake 'litmus:acceptance:parallel' bundle exec rake 'litmus:tear_down' -``` -A single acceptance spec, against an already-provisioned target listed in `spec/fixtures/litmus_inventory.yaml`: -```sh -bundle exec rspec spec/acceptance/server_spec.rb +bundle exec rake strings:generate:reference # regenerate REFERENCE.md after editing puppet-strings annotations ``` -**Reference docs:** `REFERENCE.md` is generated from puppet-strings annotations on classes/defines/types. Regenerate with `bundle exec rake strings:generate:reference` after editing parameter documentation. - -## Spec layout conventions +`rake spec` automatically runs `spec_prep` first, cloning the fixture modules listed in `.fixtures.yml` into `spec/fixtures/modules/`. If fixtures get stale after dependency changes, run `bundle exec rake spec_clean && bundle exec rake spec_prep`. -- `spec/classes/` — `rspec-puppet` catalog tests for classes in `manifests/`. -- `spec/defines/` — `rspec-puppet` for defined types. -- `spec/functions/` — function tests. -- `spec/type_aliases/` — tests for Puppet type aliases in `types/`. -- `spec/unit/{type,provider,puppet}/` — pure Ruby tests for `lib/puppet/`. -- `spec/acceptance/` — Litmus tests; run on provisioned hosts, NOT in unit runs. +## Spec conventions -`spec/spec_helper_local.rb` defines `shared_context` blocks for OSes (`'RedHat 8'`, `'Debian 11'`, etc.) backed by `rspec-puppet-facts`. When adding tests for a new OS, prefer adding a `shared_context` here over inlining fact hashes. Use `include_examples 'RedHat 8'` (note: `include_examples`, not `include_context` — that's the project convention). +`spec/spec_helper_local.rb` defines `shared_context` blocks for OSes (`'RedHat 8'`, `'Debian 11'`, etc.) backed by `rspec-puppet-facts`. When adding tests for a new OS, prefer adding a `shared_context` here over inlining fact hashes. Use `include_examples 'RedHat 8'` — note: `include_examples`, **not** `include_context`. That's the project convention and tests written with the wrong helper will silently behave differently. -## Lint and style customizations +## Lint and CI -`.puppet-lint.rc` and the `Rakefile` disable: `80chars`, `140chars`, `class_inherits_from_params_class`, `autoloader_layout`, `documentation`, `single_quote_string_with_variables`, `anchor_resource`, `params_empty_string_assignment`, `relative`. `fail_on_warnings` is **on** — any new puppet-lint warning will fail CI. The lint ignores `types/**/*.pp` (Puppet type aliases use a different syntax that puppet-lint doesn't grok well). +Lint configuration lives in `.puppet-lint.rc` and the `Rakefile`. `fail_on_warnings` is **on** — any new puppet-lint warning will fail CI. The `types/**/*.pp` directory is excluded from lint (Puppet type aliases use syntax that puppet-lint doesn't grok well). RuboCop exceptions are tracked in `.rubocop_todo.yml` — prefer fixing offenses over adding to the todo list. -RuboCop config lives in `.rubocop.yml` with overrides for puppet-module style. Existing exceptions are tracked in `.rubocop_todo.yml` — prefer fixing offenses over adding to the todo list. +`.github/workflows/{ci,nightly}.yml` are thin shims that call reusable workflows from `puppetlabs/cat-github-actions`. The acceptance matrix is built by `matrix_from_metadata_v3`, which reads `metadata.json`'s `operatingsystem_support` **and** cross-references the platform catalog in `puppetlabs/puppet_litmus/exe/matrix.json`. **Adding an OS/version to `metadata.json` does NOT automatically produce a CI job** — `puppet_litmus`'s matrix.json must also have a Docker image or provision-service entry for that platform. This is the most common cause of "I added the OS but no job appeared". -## CI - -`.github/workflows/ci.yml` and `nightly.yml` are thin shims that call reusable workflows from `puppetlabs/cat-github-actions`: -- `module_ci.yml` runs `rake validate` and `rake parallel_spec`. -- `module_acceptance.yml` runs Litmus against a matrix built by `matrix_from_metadata_v3`, which reads `metadata.json`'s `operatingsystem_support` and cross-references the platform catalog in `puppetlabs/puppet_litmus/exe/matrix.json`. **Adding an OS/version to `metadata.json` does NOT automatically produce a CI job** — `puppet_litmus`'s matrix.json must also have a Docker image or provision-service entry for that platform. - -## Conventions when committing +## Commit and branch conventions - Branch names follow `-`, where `` is the Jira ticket key (e.g. `MODULES-11816-add-claude-md`, `MODULES-12345-fix-el10-default-version`). Keep the trailing slug short, kebab-cased, and descriptive of the change. For test-PR runs of community PRs, the convention used here is `-pr` (e.g. `MODULES-11807-pr1650`). - Commit messages and PR titles start with `(MODULES-XXXX)` — the Jira automation uses this to link commits back to tickets. - When cherry-picking community PRs, squash to one commit and add a `Co-authored-by:` trailer for the original contributor. -## Dependency boundaries - -`metadata.json` declares the supported Puppet (`>= 8.0.0 < 9.0.0`) and module-dependency ranges. The hard runtime dependencies are `puppetlabs/stdlib`, `puppetlabs/apt`, `puppet/systemd`, `puppetlabs/concat`. Don't introduce new module dependencies without an explicit Jira ticket — they propagate to every consumer. +## Authoritative sources (do not duplicate here) + +When you need any of these, read the file directly — the lists drift fast and a copy here would lie: + +| What | Authoritative file | +|---|---| +| Supported operating systems and versions | `metadata.json` → `operatingsystem_support` | +| Puppet version range, module dependencies | `metadata.json` → `requirements`, `dependencies` | +| Class, defined-type, and parameter docs | `REFERENCE.md` (regenerate with `rake strings:generate:reference`) | +| Lint configuration | `.puppet-lint.rc`, `Rakefile` | +| Custom types and providers | `lib/puppet/type/`, `lib/puppet/provider/` | +| Puppet type aliases | `types/` | +| OS-specific Hiera defaults | `data/os/` | +| Fixture-module pins for unit tests | `.fixtures.yml` | +| CI workflow definitions | `.github/workflows/`, `puppetlabs/cat-github-actions` | +| CI platform catalog | `puppetlabs/puppet_litmus/exe/matrix.json` | From bdd9a01eeea1958c9e3cd84553e83a0b38602930 Mon Sep 17 00:00:00 2001 From: Sugat <233906380+SugatD@users.noreply.github.com> Date: Fri, 29 May 2026 14:05:12 +0530 Subject: [PATCH 4/4] (MODULES-11816) Narrow CLAUDE.md to postgresql-specific content Address review feedback from @bastelfreak: drop generic Puppet-module content (commands, lint config, CI mechanics, spec helpers, branch conventions) that belongs in PDK docs or org-level documentation, not duplicated into every module. Keeps only what is specific to puppetlabs-postgresql and not derivable from reading individual files: the three-layer architecture (globals -> params -> server), the default-vs-versioned package-name branch in params.pp, the multi-instance RHEL-8-only caveat, and the Hiera data/os layout. --- CLAUDE.md | 66 ++++--------------------------------------------------- 1 file changed, 4 insertions(+), 62 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 410fc4f5aa..b387c032e1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,76 +2,18 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. -## Module overview - -`puppetlabs-postgresql` manages PostgreSQL packages, services, databases, roles, grants, and `pg_hba.conf` / `pg_ident.conf` rules. Entry point is `class { 'postgresql::server': }`, but every consumer is expected to declare `postgresql::globals` first (see Architecture). Supported OSes, Puppet version range, and module dependencies are declared in `metadata.json` — treat that as the single source of truth. +For generic Puppet module workflow (validate, lint, unit/acceptance tests, Litmus, branch/commit conventions, CI matrix mechanics), see the PDK docs and the README's Tests section. The notes below cover only what is specific to `puppetlabs-postgresql` and not derivable from reading individual files. ## Architecture The module has a three-layer composition that must be understood before changing anything in `manifests/`: -1. **`manifests/globals.pp`** — sole source of truth for version + OS detection. Resolves `$default_version` from `$facts['os']['family']`, `$facts['os']['name']`, and `$facts['os']['release']['major']` (a nested selector hash, ~70 lines). Also resolves `$default_postgis_version`. Optionally configures the PGDG yum/apt repo via `postgresql::repo`, or enables `postgresql::dnfmodule` on EL8+/Fedora. **Must be included before `postgresql::server`** — `postgresql::server` reads `$postgresql::globals::default_version` to decide package names. Adding a new OS or version means editing the selector here. +1. **`manifests/globals.pp`** — sole source of truth for version + OS detection. Resolves `$default_version` from `$facts['os']['family']`, `$facts['os']['name']`, and `$facts['os']['release']['major']` (a nested selector hash). Also resolves `$default_postgis_version`. Optionally configures the PGDG yum/apt repo via `postgresql::repo`, or enables `postgresql::dnfmodule` on EL8+/Fedora. **Must be included before `postgresql::server`** — `postgresql::server` reads `$postgresql::globals::default_version` to decide package names. Adding a new OS or version means editing the selector here. 2. **`manifests/params.pp`** — translates the resolved version into package/service/path names per OS. Has a critical branch: if `$version == $default_version` (and not Amazon Linux), it uses unversioned package names (`postgresql`, `postgresql-server`) from the OS base repo; otherwise it constructs versioned names (`postgresql16-server`) for the PGDG repo. Changing default version mappings without understanding this branch will break either base-repo or PGDG installs. -3. **`manifests/server.pp` + `manifests/server/`** — the user-facing API. `server.pp` orchestrates `install` → `initdb` → `config` → `service` → `reload`. The defined types under `manifests/server/` are the public interface — each one ultimately fires a `postgresql_psql` custom resource (see `lib/puppet/type/postgresql_psql.rb`). +3. **`manifests/server.pp` + `manifests/server/`** — the user-facing API. `server.pp` orchestrates `install` → `initdb` → `config` → `service` → `reload`. The defined types under `manifests/server/` are the public interface — each one ultimately fires a `postgresql_psql` custom resource. The manifests are mostly orchestration; the actual work happens in `lib/puppet/`. **Multi-instance support** (`manifests/server_instance.pp` + `manifests/server/instance/`) is opt-in and currently tested only on RHEL 8 / CentOS Stream 8 — see the warning at `manifests/server_instance.pp:39`. Treat changes there as RHEL-8-specific unless explicitly broadening scope. -**Custom types and providers** live in `lib/puppet/{type,provider}/`. The workhorse is `postgresql_psql`, which runs idempotent SQL via the `unless`/`onlyif` query pattern — every `server::*` defined type funnels through it. The manifests are mostly orchestration; the actual work happens in these Ruby files. - -**Hiera-driven OS defaults**: `hiera.yaml` is keyed by `os.name`/`os.family` + `os.release.major`. Per-OS YAML lives in `data/os//.yaml` and `data/os/.yaml`. Add new-OS defaults here rather than hard-coding them in `params.pp` when possible. - -## Common commands - -Assume `bundle install --path=vendor` has been run. - -```sh -bundle exec rake validate # puppet syntax + lint + metadata-json-lint (run before pushing) -bundle exec rake parallel_spec # full unit suite, parallelized — preferred over `rake spec` for full runs -bundle exec rspec spec/classes/globals_spec.rb # one file -bundle exec rspec spec/classes/globals_spec.rb -e "RedHat 8" # one example - -bundle exec rake 'litmus:provision[docker,litmusimage/almalinux:9]' -bundle exec rake 'litmus:install_agent' -bundle exec rake 'litmus:install_module' -bundle exec rake 'litmus:acceptance:parallel' -bundle exec rake 'litmus:tear_down' - -bundle exec rake strings:generate:reference # regenerate REFERENCE.md after editing puppet-strings annotations -``` - -`rake spec` automatically runs `spec_prep` first, cloning the fixture modules listed in `.fixtures.yml` into `spec/fixtures/modules/`. If fixtures get stale after dependency changes, run `bundle exec rake spec_clean && bundle exec rake spec_prep`. - -## Spec conventions - -`spec/spec_helper_local.rb` defines `shared_context` blocks for OSes (`'RedHat 8'`, `'Debian 11'`, etc.) backed by `rspec-puppet-facts`. When adding tests for a new OS, prefer adding a `shared_context` here over inlining fact hashes. Use `include_examples 'RedHat 8'` — note: `include_examples`, **not** `include_context`. That's the project convention and tests written with the wrong helper will silently behave differently. - -## Lint and CI - -Lint configuration lives in `.puppet-lint.rc` and the `Rakefile`. `fail_on_warnings` is **on** — any new puppet-lint warning will fail CI. The `types/**/*.pp` directory is excluded from lint (Puppet type aliases use syntax that puppet-lint doesn't grok well). RuboCop exceptions are tracked in `.rubocop_todo.yml` — prefer fixing offenses over adding to the todo list. - -`.github/workflows/{ci,nightly}.yml` are thin shims that call reusable workflows from `puppetlabs/cat-github-actions`. The acceptance matrix is built by `matrix_from_metadata_v3`, which reads `metadata.json`'s `operatingsystem_support` **and** cross-references the platform catalog in `puppetlabs/puppet_litmus/exe/matrix.json`. **Adding an OS/version to `metadata.json` does NOT automatically produce a CI job** — `puppet_litmus`'s matrix.json must also have a Docker image or provision-service entry for that platform. This is the most common cause of "I added the OS but no job appeared". - -## Commit and branch conventions - -- Branch names follow `-`, where `` is the Jira ticket key (e.g. `MODULES-11816-add-claude-md`, `MODULES-12345-fix-el10-default-version`). Keep the trailing slug short, kebab-cased, and descriptive of the change. For test-PR runs of community PRs, the convention used here is `-pr` (e.g. `MODULES-11807-pr1650`). -- Commit messages and PR titles start with `(MODULES-XXXX)` — the Jira automation uses this to link commits back to tickets. -- When cherry-picking community PRs, squash to one commit and add a `Co-authored-by:` trailer for the original contributor. - -## Authoritative sources (do not duplicate here) - -When you need any of these, read the file directly — the lists drift fast and a copy here would lie: - -| What | Authoritative file | -|---|---| -| Supported operating systems and versions | `metadata.json` → `operatingsystem_support` | -| Puppet version range, module dependencies | `metadata.json` → `requirements`, `dependencies` | -| Class, defined-type, and parameter docs | `REFERENCE.md` (regenerate with `rake strings:generate:reference`) | -| Lint configuration | `.puppet-lint.rc`, `Rakefile` | -| Custom types and providers | `lib/puppet/type/`, `lib/puppet/provider/` | -| Puppet type aliases | `types/` | -| OS-specific Hiera defaults | `data/os/` | -| Fixture-module pins for unit tests | `.fixtures.yml` | -| CI workflow definitions | `.github/workflows/`, `puppetlabs/cat-github-actions` | -| CI platform catalog | `puppetlabs/puppet_litmus/exe/matrix.json` | +**Hiera-driven OS defaults**: `hiera.yaml` is keyed by `os.name`/`os.family` + `os.release.major`. Per-OS YAML lives in `data/os//.yaml` and `data/os/.yaml`. Prefer adding new-OS defaults here over hard-coding them in `params.pp`.