cimas 0.1.4 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/rake.yml +18 -0
- data/.github/workflows/release.yml +31 -0
- data/.gitignore +3 -0
- data/.rubocop.yml +29 -0
- data/CLAUDE.md +56 -0
- data/README.adoc +467 -14
- data/bin/console +1 -1
- data/cimas.gemspec +4 -3
- data/exe/cimas +9 -201
- data/lib/cimas/cli/command.rb +827 -239
- data/lib/cimas/cli/error.rb +8 -0
- data/lib/cimas/cli/runner.rb +239 -0
- data/lib/cimas/cli.rb +7 -0
- data/lib/cimas/github.rb +47 -0
- data/lib/cimas/orphan_files.rb +37 -0
- data/lib/cimas/patch.rb +25 -0
- data/lib/cimas/release_preflight.rb +140 -0
- data/lib/cimas/repository.rb +25 -17
- data/lib/cimas/version.rb +1 -1
- data/lib/cimas/working_copy.rb +136 -0
- data/lib/cimas.rb +22 -3
- data/plans/cimas-revival-and-release-workflow-realignment.md +2158 -0
- metadata +38 -12
- data/Gemfile.lock +0 -86
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 11ddc7c90fe0593643ea085df50c9e05133d501aa2e158dc3a125b2dbcb8fdca
|
|
4
|
+
data.tar.gz: dad6f26540e9640d86737f89e3e00c9df3bf372f8521c86cf6e0e0f04d6a7e30
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a3bc8620cb6566187a87816f7ccc66ebec1eb8692099cba77d0ee78c70c4376b8652e0d8c837c2af322cf977931af0ba9a64fdb4138a935e3c90a56adfca34dc
|
|
7
|
+
data.tar.gz: 0f5e66b3d7440f699d2d58378be0467deb4b60d4dfb88986b270e506b2a8bde59f23ff24f1744865e0aec942829c19209a772ff8b5784d0c981c36b7a19f207e
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
|
2
|
+
# See https://github.com/metanorma/cimas
|
|
3
|
+
name: rake
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
branches: [ master, main ]
|
|
8
|
+
tags: [ v* ]
|
|
9
|
+
pull_request:
|
|
10
|
+
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write
|
|
13
|
+
|
|
14
|
+
jobs:
|
|
15
|
+
rake:
|
|
16
|
+
uses: metanorma/ci/.github/workflows/generic-rake.yml@main
|
|
17
|
+
secrets:
|
|
18
|
+
pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
|
2
|
+
# See https://github.com/metanorma/cimas
|
|
3
|
+
name: release
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
inputs:
|
|
8
|
+
next_version:
|
|
9
|
+
description: |
|
|
10
|
+
Next release version. Possible values: x.y.z, major, minor, patch (or pre|rc|etc).
|
|
11
|
+
Also, you can pass 'skip' to skip 'git tag' and do 'gem push' for the current version
|
|
12
|
+
required: true
|
|
13
|
+
default: 'skip'
|
|
14
|
+
repository_dispatch:
|
|
15
|
+
types: [ do-release ]
|
|
16
|
+
|
|
17
|
+
# Least-privilege ceiling for the called rubygems-release.yml: its release job
|
|
18
|
+
# needs contents:write (git tag push) and id-token:write (OIDC Trusted Publishing).
|
|
19
|
+
permissions:
|
|
20
|
+
contents: write
|
|
21
|
+
id-token: write
|
|
22
|
+
|
|
23
|
+
jobs:
|
|
24
|
+
release:
|
|
25
|
+
uses: metanorma/ci/.github/workflows/rubygems-release.yml@main
|
|
26
|
+
with:
|
|
27
|
+
next_version: ${{ github.event.inputs.next_version }}
|
|
28
|
+
secrets:
|
|
29
|
+
rubygems-api-key: ${{ secrets.METANORMA_CI_RUBYGEMS_API_KEY }}
|
|
30
|
+
pat_token: ${{ secrets.METANORMA_CI_PAT_TOKEN }}
|
|
31
|
+
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Auto-generated by Cimas: Do not edit it manually!
|
|
2
|
+
# See https://github.com/metanorma/cimas
|
|
3
|
+
inherit_from:
|
|
4
|
+
- https://raw.githubusercontent.com/riboseinc/oss-guides/main/ci/rubocop.yml
|
|
5
|
+
# A repo-local `.rubocop_todo.yml`, when one exists, MUST be the last
|
|
6
|
+
# entry: inherit_from is last-wins, so listing it before oss-guides lets
|
|
7
|
+
# the shared config's stricter Metrics/ rules override the todo's
|
|
8
|
+
# per-file grandfathering. Emit the reference only when the todo file
|
|
9
|
+
# actually exists in the repo — this repo has none, and a dangling
|
|
10
|
+
# reference makes every local rubocop run exit 2 with
|
|
11
|
+
# "Configuration file not found".
|
|
12
|
+
|
|
13
|
+
# Rubocop plugins enabled centrally so every metanorma-org gem picks them up
|
|
14
|
+
# on cimas sync — best practice belongs at the shared-template layer, not
|
|
15
|
+
# per-repo. Per ronaldtse feedback on metanorma/ci#332.
|
|
16
|
+
plugins:
|
|
17
|
+
- rubocop-rspec
|
|
18
|
+
- rubocop-performance
|
|
19
|
+
- rubocop-rake
|
|
20
|
+
|
|
21
|
+
# local repo-specific modifications
|
|
22
|
+
# ...
|
|
23
|
+
|
|
24
|
+
AllCops:
|
|
25
|
+
# 3.3 matches the org-wide minimum being pushed via #274 (Raise minimum
|
|
26
|
+
# Ruby version to 3.3 due to EOL of 3.2 on 2026-03-31). Was 3.4 before
|
|
27
|
+
# this commit — 3.4 was above the org's stated minimum and would have
|
|
28
|
+
# applied Rubocop rules that fail-close on gems still targeting 3.3.
|
|
29
|
+
TargetRubyVersion: 3.3
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## What cimas is
|
|
6
|
+
|
|
7
|
+
A CLI gem that fans out CI-configuration synchronization ("waves") across a fleet of GitHub repos: clone all repos listed in a `cimas.yml`, render template files into each repo's working copy, commit drift to a per-wave branch, push, open PRs, then clean up branches/files after waves land or die. Metanorma-org specific; the live fleet configs live in `metanorma/metanorma-build-scripts/cimas-config/`.
|
|
8
|
+
|
|
9
|
+
Development happens on `main`; all changes land via PRs, one clean (squashed) commit each, rebase-merged.
|
|
10
|
+
|
|
11
|
+
## Commands
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
bundle install # Gemfile is gemspec-driven; Gemfile.lock is untracked
|
|
15
|
+
bundle exec rspec # full suite (rake default == spec)
|
|
16
|
+
bundle exec rspec spec/cimas/repository_spec.rb # one file
|
|
17
|
+
bundle exec rspec spec/cimas/cli/command_spec.rb -e "refuses push" # one example
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
- Rubocop: **not in the bundle** (not a gemspec dev-dependency) — run the globally installed `rubocop` directly. `.rubocop.yml` inherits a remote riboseinc config and lists plugin gems that may not be installed; it parses fine, but the run reports hundreds of pre-existing style offenses (single quotes vs the org's double-quote policy, 80-col lines) — do not treat it as a merge gate. CI (`.github/workflows/rake.yml` → `metanorma/ci` reusable workflow) runs specs only.
|
|
21
|
+
- `bin/console` works (`bundle exec ruby bin/console`).
|
|
22
|
+
- GitHub-touching code paths need `GITHUB_TOKEN` in the environment; specs do not.
|
|
23
|
+
|
|
24
|
+
## Architecture
|
|
25
|
+
|
|
26
|
+
Everything routes through two files:
|
|
27
|
+
|
|
28
|
+
- **`exe/cimas`** — entry point only: `require_relative '../lib/cimas'`, `Cimas::Cli::Runner.start(ARGV)`, and a two-tier rescue (`Cimas::Cli::Error`/`Thor::Error` → one clean line, exit 1; anything else → backtrace). All parsing/help lives in `Cimas::Cli::Runner` (Thor).
|
|
29
|
+
- **`lib/cimas/cli/runner.rb`** — `Runner < Thor` is the CLI surface: one definition per flag (`SHARED_OPTIONS` + `STRING_OPTION_KEYS` data; per-command `method_option`), `cimas help [COMMAND]` is the help interface (no `--help` remap), no `default_task` (bare `cimas` prints help; a leading global option would otherwise dispatch the default with the subcommand as an argument), `exit_on_failure?` true (Thor 1.5 exits 0 otherwise). Every task is one line: `run_command("name")` → `Command.new(command_options).execute(name)`. Adding a subcommand = desc + options + one-line action; adding a flag = one entry in the tables.
|
|
30
|
+
- **`lib/cimas/cli/command.rb`** — `Command` is the orchestrator holding the domain: config loading, every subcommand's behavior, ERB rendering, the patch engine. GitHub access goes through the `Cimas::GitHub` seam. Config precedence: `DEFAULT_CONFIG` < cimas.yml `settings:` < Runner-translated options. User-facing errors raise `Cimas::Cli::Error` (lib/cimas/cli/error.rb).
|
|
31
|
+
|
|
32
|
+
Domain models and seams, each loaded via autoload with `__dir__`-absolute paths (see lib/cimas.rb / lib/cimas/cli.rb): `Cimas::Repository` (`repositories:`), `Cimas::Patch` (`patches:` — compiled regex, `matches?`/`apply`), `Cimas::OrphanFiles` (pure orphan-detection logic), `Cimas::WorkingCopy` (the git seam — every git-gem call, rescue, and porcelain parse lives behind ~10 domain verbs like `drift?`, `reset_clean`, `provision via reset_onto/switch_branch`, `push` returning `:pushed/:behind_remote/[:rejected, e]`; subcommands must not call the git gem directly), `Cimas::GitHub` (Octokit boundary: client, remote→slug, visibility fallback), `Cimas::ReleasePreflight` (extracted check-runner). `Cimas::GENERATED_HEADER` / `GENERATED_HEADER_MARKER` are the SSOT for the generated-file header. `repo_by_name` returns a real `nil` for unknown names.
|
|
33
|
+
|
|
34
|
+
### Dispatch-time scope guard (the key safety mechanism)
|
|
35
|
+
|
|
36
|
+
`Command.execute(command_name)` is the single dispatch entrypoint (the Thor Runner calls it). One `COMMANDS` registry entry per subcommand drives everything: remote-mutating classification (`remote_mutating` / `remote_mutating_if`) applies the scope guard **and** the `Scope for <command>: N repo(s): ...` announcement from the same data; `requires` / `requires_if` fail fast on missing flags (`push` without `-b`/`-m`, `for-each` without `-c`, `release-preflight` without `--repo` exit 1 before any repo iteration). Remote-mutating commands refuse a missing, empty, or zero-resolving `-g`; local-only commands (`sync`, `pull`, `diff`) still default to every repo. **Adding a subcommand = adding one registry entry — nothing else.** Calling a subcommand method directly bypasses guard/validation by design (it protects CLI operators, not library callers).
|
|
37
|
+
|
|
38
|
+
### The wave lifecycle (order matters)
|
|
39
|
+
|
|
40
|
+
`setup` → `pull` → `sync` → `diff` → `push` → `open-prs` → (`cleanup-merged-prs` | `cleanup-closed-prs` | `cleanup-orphan-files`), plus `for-each` (arbitrary shell per repo) and `release-preflight` (single repo).
|
|
41
|
+
|
|
42
|
+
- **`sync`** copies each `files:` mapping from the config-master directory (`-d`) into the repo working area under `repos_path` (`-r`). `.erb` sources render with an `OpenStruct` binding: legacy per-repo `template: binding:` keys become dot-notation methods; the top-level `with:` hash is exposed as `with_values[...]` (for keys that aren't valid Ruby identifiers). After copying, `apply_patches` runs regex find/replace on in-place files.
|
|
43
|
+
- **Ownership marker**: every synced file gets the two-line `# Auto-generated by Cimas` header from the single managed-file writer (`write_managed` under `copy_file`/`write_rendered`). `cleanup-orphan-files` uses this header (first 500 bytes) as proof cimas owns a file before deleting it; **patches deliberately do not add the header** because they edit existing files.
|
|
44
|
+
- **`push`** skips repos without local drift (`WorkingCopy#drift?`); `open-prs` already tolerates missing/empty remote branches, so no-op pushes are skipped rather than forced.
|
|
45
|
+
- **Scope**: `-g` takes a group name, a bare repo name, or `all`. See "Dispatch-time scope guard" above.
|
|
46
|
+
- **Per-repo iteration**: commands loop via `each_configured_repo` (skips unconfigured names) and `each_target_repo` (also skips repos whose working copy is missing, uniform `skipping <command> for it` message). Use these in new commands — do not hand-roll the skip preamble.
|
|
47
|
+
- **Mutation safety**: every mutating step is wrapped in `dry_run("description") { ... }`, which prints instead of executing under `--dry-run`.
|
|
48
|
+
- **`open-prs`** handles stale prior-wave PRs via `--supersede-stale` (label + comment, reviewer keeps close authority) and `--flatten-stale` (also auto-closes).
|
|
49
|
+
|
|
50
|
+
### Conventions
|
|
51
|
+
|
|
52
|
+
- Log lines carry severity prefixes (`[ERROR]`, `[WARNING]`, `[INFO]`); `sanity_check` is advisory — it warns and continues.
|
|
53
|
+
- Specs build real temp-dir working areas, real `Command` objects, real `Git.init`/local-bare-remotes (no doubles, no network); `exe_spec` boots the real executable with `RUBYOPT` cleared (installed-gem execution model). GitHub-backed commands inject `config['github'] = Cimas::GitHub.new(client: FakeGitHubClient.new)` (`spec/support/`, never `double()`); release-preflight injects `config['release_preflight_runner']`. `spec/cimas/wave_lifecycle_spec.rb` is the end-to-end money path (sync → diff → push against a local bare remote); when touching git-touching code, run it first.
|
|
54
|
+
- `plans/` holds dated sync-wave planning notes; consult the newest file for in-flight wave context.
|
|
55
|
+
- `TODO*` files are local working notes — git-ignored, never commit them.
|
|
56
|
+
- README.adoc is the authoritative user documentation and includes a "Gotchas summary" table; update it when adding subcommand flags or behavior changes.
|