Skip to content

Add way_of_working config for persisting CLI values - #95

Open
timgentry wants to merge 1 commit into
mainfrom
timgentry/config-yaml-email-contributing
Open

Add way_of_working config for persisting CLI values#95
timgentry wants to merge 1 commit into
mainfrom
timgentry/config-yaml-email-contributing

Conversation

@timgentry

Copy link
Copy Markdown
Contributor

What?

Adds way_of_working config get/set, a small CLI subcommand for persisting values in ~/.config/way_of_working/config.yaml so they don't have to be typed in on every invocation. The Code of Conduct generator's --contact-method is the first consumer: it's now optional, falls back to a stored value, and offers to remember a newly-provided one.

Why?

--contact-method is a per-person/organisation setting, not a per-project one, so requiring it on every way_of_working init call is unnecessary friction. Storing it once removes that repetition while leaving room for other features (e.g. a future security contact) to store their own values under the same file.

How?

Config keys are dotted paths namespaced by feature (code_of_conduct.contact_method) rather than by variant, so swapping the underlying standard (e.g. a future Contributor Covenant v3 variant) won't orphan a stored value — matching this gem's existing promise that variant swaps stay additive. The generator resolves the effective contact method fresh on each run (option, then config), rather than baking a default into the Thor option declaration, so config changes are always picked up.

Testing?

Added unit tests for WayOfWorking::Config (get/set, nested keys, missing file) and extended the Code of Conduct generator's tests to cover the fallback, the remember-prompt, and the friendly error when nothing is available. Also manually exercised the real CLI end-to-end in a scratch directory (fresh config, stored config, accept/decline the remember prompt). Full test suite and RuboCop pass.

Anything Else?

None of the other built-in features (changelog, decision records, etc.) take a comparable option today, so this only wires up Code of Conduct for now — the same pattern can be reused if/when a security contact or similar is added.

Adds `way_of_working config get/set` backed by ~/.config/way_of_working/config.yaml
(dotted, feature-namespaced keys) so options like the code of conduct
--contact-method don't need to be retyped on every run. --contact-method is now
optional, falling back to the stored value and offering to remember a
newly-provided one.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

MegaLinter analysis: Error

Descriptor Linter Files Fixed Errors Warnings Elapsed time
❌ COPYPASTE jscpd yes 10 no 0.72s
⚠️ MARKDOWN markdownlint 2 17 0 0.86s
⚠️ MARKDOWN markdown-table-formatter 2 1 0 0.24s
✅ REPOSITORY checkov yes no no 19.19s
❌ REPOSITORY devskim yes 1 no 2.49s
✅ REPOSITORY dustilock yes no no 0.04s
✅ REPOSITORY gitleaks yes no no 0.77s
✅ REPOSITORY git_diff yes no no 0.01s
✅ REPOSITORY grype yes no no 61.21s
✅ REPOSITORY secretlint yes no no 1.44s
✅ REPOSITORY syft yes no no 1.71s
✅ REPOSITORY trivy yes no no 11.69s
✅ REPOSITORY trivy-sbom yes no no 0.38s
✅ REPOSITORY trufflehog yes no no 4.83s
✅ SPELL lychee 2 0 0 1.45s

Detailed Issues

❌ REPOSITORY / devskim - 1 error
{"$schema":"https://schemastore.azurewebsites.net/schemas/json/sarif-2.1.0-rtm.6.json","version":"2.1.0","runs":[{"tool":{"driver":{"name":"devskim","fullName":"Microsoft DevSkim Command Line Interface","version":"1.0.70+d69541fde7","informationUri":"https://github.com/microsoft/DevSkim/","rules":[{"id":"DS176209","name":"SuspiciousComment","fullDescription":{"text":"Suspicious comment: A \"TODO\" or similar was left in source code, possibly indicating incomplete functionality"},"help":{"text":"A \"TODO\" or similar was left in source code, possibly indicating incomplete functionality","markdown":"Visit [https://github.com/Microsoft/DevSkim/blob/main/guidance/DS176209.md](https://github.com/Microsoft/DevSkim/blob/main/guidance/DS176209.md) for additional guidance on this issue."},"shortDescription":{"text":"A \"TODO\" or similar was left in source code, possibly indicating incomplete functionality"},"defaultConfiguration":{"level":"note"},"helpUri":"https://github.com/Microsoft/DevSkim/blob/main/guidance/DS176209.md","properties":{"precision":"high","problem.severity":"recommendation","DevSkimSeverity":"ManualReview","DevSkimConfidence":"High"}},{"id":"DS425030","name":"DoNotDeserializeUntrustedData","fullDescription":{"text":"Do not deserialize untrusted data.: Deserializing attacker-supplied data using YAML, Syck, or Marshall can result in code execution."},"help":{"text":"Either add integrity protection or use a data format like JSON.","markdown":"Either add integrity protection or use a data format like JSON. Visit [https://github.com/Microsoft/DevSkim/blob/main/guidance/DS425000.md](https://github.com/Microsoft/DevSkim/blob/main/guidance/DS425000.md) for additional guidance on this issue."},"shortDescription":{"text":"Deserializing attacker-supplied data using YAML, Syck, or Marshall can result in code execution."},"defaultConfiguration":{"level":"note"},"helpUri":"https://github.com/Microsoft/DevSkim/blob/main/guidance/DS425000.md","properties":{"precision":"high","problem.severity":"recommendation","DevSkimSeverity":"ManualReview","DevSkimConfidence":"High"}}]}},"versionControlProvenance":[{"repositoryUri":"https://github.com/HealthDataInsight/way_of_working","revisionId":"HIDDEN_BY_MEGALINTER","branch":"(no branch)"}],"results":[{"ruleId":"DS425030","level":"note","message":{"text":"Do not deserialize untrusted data."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"lib/way_of_working/config.rb"},"region":{"startLine":36,"startColumn":8,"endLine":36,"endColumn":17,"charOffset":1136,"charLength":9,"snippet":{"text":"YAML.load","rendered":{"text":"YAML.load","markdown":"`YAML.load`"}},"sourceLanguage":"ruby"}}}],"properties":{"tags":["Deserialization"],"DevSkimSeverity":"ManualReview","DevSkimConfidence":"High"}},{"ruleId":"DS176209","level":"note","message":{"text":"Suspicious comment"},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"lib/way_of_working/changelog/keepachangelog/generators/init.rb"},"region":{"startLine":95,"startColumn":37,"endLine":95,"endColumn":41,"charOffset":3413,"charLength":4,"snippet":{"text":"TODO","rendered":{"text":"TODO","markdown":"`TODO`"}},"sourceLanguage":"ruby"}}}],"properties":{"tags":["Hygiene.Comment.Suspicious"],"DevSkimSeverity":"ManualReview","DevSkimConfidence":"High"}},{"ruleId":"DS425030","level":"note","message":{"text":"Do not deserialize untrusted data."},"locations":[{"physicalLocation":{"artifactLocation":{"uri":"test/way_of_working/config_test.rb"},"region":{"startLine":24,"startColumn":83,"endLine":24,"endColumn":92,"charOffset":801,"charLength":9,"snippet":{"text":"YAML.load","rendered":{"text":"YAML.load","markdown":"`YAML.load`"}},"sourceLanguage":"ruby"}}}],"properties":{"tags":["Deserialization"],"DevSkimSeverity":"ManualReview","DevSkimConfidence":"High"}}],"columnKind":"utf16CodeUnits"}]}
❌ COPYPASTE / jscpd - 10 errors
Using config from /action/lib/.automation/.jscpd.json
Clone found (ruby)
 - lib/way_of_working/decision_record/madr/github_audit_rule.rb [29:9 - 42:12] (14 lines, 59 tokens)
   lib/way_of_working/versioning/semver/github_audit_rule.rb [17:9 - 30:12]
Clone found (ruby)
 - test/way_of_working/audit/github/auditor_test.rb [31:63 - 55:14] (25 lines, 87 tokens)
   test/way_of_working/audit/github/auditor_test.rb [66:64 - 90:14]
Clone found (ruby)
 - test/way_of_working/audit/github/generators/exec_test.rb [92:81 - 99:54] (8 lines, 59 tokens)
   test/way_of_working/audit/github/generators/exec_test.rb [116:88 - 123:54]
Clone found (ruby)
 - test/way_of_working/audit/github/generators/exec_test.rb [185:104 - 193:54] (9 lines, 74 tokens)
   test/way_of_working/audit/github/generators/exec_test.rb [232:125 - 240:54]
Clone found (ruby)
 - test/way_of_working/changelog/keepachangelog/github_audit_rule_test.rb [9:7 - 24:4] (16 lines, 86 tokens)
   test/way_of_working/code_of_conduct/contributor_covenant/github_audit_rule_test.rb [9:7 - 24:4]
Clone found (ruby)
 - test/way_of_working/changelog/keepachangelog/github_audit_rule_test.rb [9:7 - 24:4] (16 lines, 86 tokens)
   test/way_of_working/decision_record/madr/github_audit_rule_test.rb [9:7 - 24:4]
Clone found (ruby)
 - test/way_of_working/changelog/keepachangelog/github_audit_rule_test.rb [9:7 - 24:4] (16 lines, 86 tokens)
   test/way_of_working/inclusive_language/alex/github_audit_rule_test.rb [9:7 - 24:4]
Clone found (ruby)
 - test/way_of_working/changelog/keepachangelog/github_audit_rule_test.rb [9:7 - 24:4] (16 lines, 86 tokens)
   test/way_of_working/pull_request_template/hdi/github_audit_rule_test.rb [9:7 - 24:4]
Clone found (ruby)
 - test/way_of_working/changelog/keepachangelog/github_audit_rule_test.rb [9:7 - 24:4] (16 lines, 86 tokens)
   test/way_of_working/versioning/semver/github_audit_rule_test.rb [9:7 - 24:4]
Clone found (ruby)
 - test/way_of_working/readme_badge/generators/init_test.rb [21:11 - 38:13] (18 lines, 61 tokens)
   test/way_of_working/readme_badge/generators/init_test.rb [47:11 - 64:13]
┌────────┬────────────────┬─────────────┬──────────────┬──────────────┬──────────────────┬───────────────────┐
│ Format │ Files analyzed │ Total lines │ Total tokens │ Clones found │ Duplicated lines │ Duplicated tokens │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ ruby   │ 57             │ 2860        │ 10595        │ 10           │ 144 (5.03%)      │ 770 (7.27%)       │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ txt    │ 1              │ 22          │ 201          │ 0            │ 0 (0.00%)        │ 0 (0.00%)         │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ Total: │ 58             │ 2882        │ 10796        │ 10           │ 144 (5.00%)      │ 770 (7.13%)       │
└────────┴────────────────┴─────────────┴──────────────┴──────────────┴──────────────────┴───────────────────┘
Found 10 clones.
HTML report saved to megalinter-reports/copy-paste/jscpd-report.html
ERROR: jscpd found too many duplicates (5.0%) over threshold (0.0%)
time: 77.780ms
⚠️ MARKDOWN / markdown-table-formatter - 1 error
1 files contain markdown tables to format:
- README.md
⚠️ MARKDOWN / markdownlint - 17 errors
CHANGELOG.md:16 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Added"]
CHANGELOG.md:40 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Added"]
CHANGELOG.md:45 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Removed"]
CHANGELOG.md:57 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Fixed"]
CHANGELOG.md:64 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Added"]
CHANGELOG.md:77 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Fixed"]
README.md:26:232 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:27:178 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:29:75 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:29:193 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:30:166 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:31:163 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:32:178 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:33:185 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:77:401 error MD013/line-length Line length [Expected: 400; Actual: 454]
README.md:249:109 error MD009/no-trailing-spaces Trailing spaces [Expected: 0 or 2; Actual: 1]
README.md:275 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Code of Conduct"]

Notices

📣 MegaLinter 9.5.0 is out! Discover the new features and security recommendations in the release announcement. (Skip this info by defining SECURITY_SUGGESTIONS: false)

See detailed reports in MegaLinter artifacts
Set VALIDATE_ALL_CODEBASE: true in mega-linter.yml to validate all sources, not only the diff

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants