docopslab-dev 0.1.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.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.adoc +904 -0
  4. data/assets/config-packs/actionlint/base.yml +13 -0
  5. data/assets/config-packs/actionlint/project.yml +13 -0
  6. data/assets/config-packs/htmlproofer/base.yml +27 -0
  7. data/assets/config-packs/htmlproofer/project.yml +25 -0
  8. data/assets/config-packs/rubocop/base.yml +130 -0
  9. data/assets/config-packs/rubocop/project.yml +8 -0
  10. data/assets/config-packs/shellcheck/base.shellcheckrc +14 -0
  11. data/assets/config-packs/subtxt/ai-asciidoc-antipatterns.sub.txt +11 -0
  12. data/assets/config-packs/vale/asciidoc/ExplicitSectionIDs.yml +8 -0
  13. data/assets/config-packs/vale/asciidoc/ExtraLineBeforeLevel1.yml +7 -0
  14. data/assets/config-packs/vale/asciidoc/OneSentencePerLine.yml +8 -0
  15. data/assets/config-packs/vale/asciidoc/PreferSourceBlocks.yml +8 -0
  16. data/assets/config-packs/vale/asciidoc/ProperAdmonitions.yml +8 -0
  17. data/assets/config-packs/vale/asciidoc/ProperDLs.yml +7 -0
  18. data/assets/config-packs/vale/asciidoc/UncleanListStart.yml +8 -0
  19. data/assets/config-packs/vale/authoring/ButParagraph.yml +8 -0
  20. data/assets/config-packs/vale/authoring/ExNotEg.yml +8 -0
  21. data/assets/config-packs/vale/authoring/LiteralTerms.yml +20 -0
  22. data/assets/config-packs/vale/authoring/Spelling.yml +679 -0
  23. data/assets/config-packs/vale/base.ini +38 -0
  24. data/assets/config-packs/vale/config/scripts/ExplicitSectionIDs.tengo +56 -0
  25. data/assets/config-packs/vale/config/scripts/ExtraLineBeforeLevel1.tengo +121 -0
  26. data/assets/config-packs/vale/config/scripts/OneSentencePerLine.tengo +53 -0
  27. data/assets/config-packs/vale/project.ini +5 -0
  28. data/assets/hooks/pre-commit +63 -0
  29. data/assets/hooks/pre-push +72 -0
  30. data/assets/scripts/adoc_section_ids.rb +50 -0
  31. data/assets/scripts/build-common.sh +193 -0
  32. data/assets/scripts/build-docker.sh +64 -0
  33. data/assets/scripts/build.sh +56 -0
  34. data/assets/scripts/parse_jekyll_asciidoc_logs.rb +467 -0
  35. data/assets/templates/Gemfile +7 -0
  36. data/assets/templates/Rakefile +3 -0
  37. data/assets/templates/gitignore +69 -0
  38. data/assets/templates/jekyll-asciidoc-fix.prompt.yml +17 -0
  39. data/assets/templates/spellcheck.prompt.yml +16 -0
  40. data/docopslab-dev.gemspec +56 -0
  41. data/docs/agent/AGENTS.md +229 -0
  42. data/docs/agent/index.md +80 -0
  43. data/docs/agent/missions/conduct-release.md +224 -0
  44. data/docs/agent/missions/setup-new-project.md +250 -0
  45. data/docs/agent/roles/devops-release-engineer.md +152 -0
  46. data/docs/agent/roles/docops-engineer.md +193 -0
  47. data/docs/agent/roles/planner-architect.md +74 -0
  48. data/docs/agent/roles/product-engineer.md +153 -0
  49. data/docs/agent/roles/product-manager.md +130 -0
  50. data/docs/agent/roles/project-manager.md +139 -0
  51. data/docs/agent/roles/qa-testing-engineer.md +115 -0
  52. data/docs/agent/roles/tech-docs-manager.md +143 -0
  53. data/docs/agent/roles/tech-writer.md +163 -0
  54. data/docs/agent/skills/asciidoc.md +609 -0
  55. data/docs/agent/skills/code-commenting.md +347 -0
  56. data/docs/agent/skills/fix-broken-links.md +309 -0
  57. data/docs/agent/skills/fix-jekyll-asciidoc-build-errors.md +23 -0
  58. data/docs/agent/skills/fix-spelling-issues.md +13 -0
  59. data/docs/agent/skills/git.md +170 -0
  60. data/docs/agent/skills/github-issues.md +135 -0
  61. data/docs/agent/skills/product-release-rollback-and-patching.md +71 -0
  62. data/docs/agent/skills/rake-cli-dev.md +57 -0
  63. data/docs/agent/skills/readme-driven-dev.md +13 -0
  64. data/docs/agent/skills/release-history.md +29 -0
  65. data/docs/agent/skills/ruby.md +192 -0
  66. data/docs/agent/skills/schemagraphy-sgyml.md +18 -0
  67. data/docs/agent/skills/tests-running.md +25 -0
  68. data/docs/agent/skills/tests-writing.md +45 -0
  69. data/docs/agent/skills/write-the-docs.md +54 -0
  70. data/docs/agent/topics/common-project-paths.md +117 -0
  71. data/docs/agent/topics/dev-tooling-usage.md +202 -0
  72. data/docs/agent/topics/devops-ci-cd.md +55 -0
  73. data/docs/agent/topics/product-docs-deployment.md +25 -0
  74. data/lib/docopslab/dev/auto_fix_asciidoc.rb +46 -0
  75. data/lib/docopslab/dev/checkers.rb +108 -0
  76. data/lib/docopslab/dev/config_manager.rb +241 -0
  77. data/lib/docopslab/dev/file_utils.rb +140 -0
  78. data/lib/docopslab/dev/git_hooks.rb +140 -0
  79. data/lib/docopslab/dev/help.rb +121 -0
  80. data/lib/docopslab/dev/initializer.rb +95 -0
  81. data/lib/docopslab/dev/linters.rb +451 -0
  82. data/lib/docopslab/dev/log_parser.rb +31 -0
  83. data/lib/docopslab/dev/paths.rb +46 -0
  84. data/lib/docopslab/dev/script_manager.rb +136 -0
  85. data/lib/docopslab/dev/spell_check.rb +194 -0
  86. data/lib/docopslab/dev/sync_ops.rb +468 -0
  87. data/lib/docopslab/dev/tasks.rb +440 -0
  88. data/lib/docopslab/dev/tool_execution.rb +68 -0
  89. data/lib/docopslab/dev/version.rb +8 -0
  90. data/lib/docopslab/dev.rb +392 -0
  91. data/specs/data/default-manifest.yml +64 -0
  92. data/specs/data/manifest-schema.yaml +63 -0
  93. data/specs/data/tasks-def.yml +321 -0
  94. data/specs/data/tools.yml +60 -0
  95. metadata +362 -0
@@ -0,0 +1,392 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'English'
4
+ require 'rake/tasklib'
5
+ require 'yaml'
6
+ require 'fileutils'
7
+ require 'pathname'
8
+ require 'shellwords'
9
+ require_relative 'dev/version' # includes RUBY_TARGET
10
+ require_relative 'dev/paths'
11
+ require_relative 'dev/spell_check'
12
+ require_relative 'dev/log_parser'
13
+ require_relative 'dev/tasks'
14
+ require_relative 'dev/git_hooks'
15
+ require_relative 'dev/tool_execution'
16
+ require_relative 'dev/linters'
17
+ require_relative 'dev/config_manager'
18
+ require_relative 'dev/file_utils'
19
+ require_relative 'dev/script_manager'
20
+ require_relative 'dev/sync_ops'
21
+ require_relative 'dev/checkers'
22
+ require_relative 'dev/initializer'
23
+ require_relative 'dev/auto_fix_asciidoc'
24
+ require_relative 'dev/help'
25
+
26
+ # Suppress experimental IO::Buffer warning from io-event gem (via html-proofer)
27
+ Warning[:experimental] = false if Warning.respond_to?(:[]=)
28
+
29
+ module DocOpsLab
30
+ module Dev
31
+ GEM_ROOT = begin
32
+ spec = Gem::Specification.find_by_name('docopslab-dev')
33
+ if spec
34
+ spec.gem_dir
35
+ else # Fallback for development
36
+ File.expand_path('../../../', __dir__)
37
+ end
38
+ end
39
+
40
+ # Path constants
41
+ # Project paths (local/runtime)
42
+ MANIFEST_PATH = '.config/docopslab-dev.yml'
43
+ CONFIG_VENDOR_DIR = Paths.config_vendor_dir
44
+ HOOKS_DIR = '.git/hooks'
45
+
46
+ # Runtime/generated config files (merged from base + local)
47
+ CONFIG_PATHS = Paths::CONFIG_FILES
48
+
49
+ # Shorthand for rubocop (most commonly referenced)
50
+ RUBOCOP_CONFIG_PATH = CONFIG_PATHS[:rubocop]
51
+
52
+ # Gem source paths (assets bundled with gem)
53
+ MANIFEST_DEF_PATH = File.join(GEM_ROOT, 'specs', 'data', 'default-manifest.yml')
54
+ TOOLS_DEF_PATH = File.join(GEM_ROOT, 'specs', 'data', 'tools.yml')
55
+ CONFIG_PACKS_SOURCE_DIR = Paths.gem_config_packs
56
+ SCRIPTS_SOURCE_DIR = Paths.gem_scripts
57
+ HOOKS_SOURCE_DIR = Paths.gem_hooks
58
+ TEMPLATES_DIR = File.join(GEM_ROOT, 'assets', 'templates')
59
+ GITIGNORE_STUB_SOURCE_PATH = File.join(TEMPLATES_DIR, 'gitignore')
60
+ GEMFILE_STUB_SOURCE_PATH = File.join(TEMPLATES_DIR, 'Gemfile')
61
+ RAKEFILE_STUB_SOURCE_PATH = File.join(TEMPLATES_DIR, 'Rakefile')
62
+
63
+ # Cached data
64
+ @manifest = nil
65
+ @tools_data = nil
66
+
67
+ class << self
68
+ attr_accessor :manifest, :tools_data
69
+
70
+ # Common Utility
71
+
72
+ def load_manifest force_reload: false
73
+ return @manifest if @manifest && !force_reload
74
+
75
+ @manifest = YAML.load_file(MANIFEST_PATH) if File.exist?(MANIFEST_PATH)
76
+ @manifest
77
+ rescue StandardError => e
78
+ warn "Failed to load manifest: #{e.message}"
79
+ nil
80
+ end
81
+
82
+ def load_tools_data
83
+ return @tools_data if @tools_data
84
+
85
+ @tools_data = begin
86
+ if File.exist?(TOOLS_DEF_PATH)
87
+ YAML.load_file(TOOLS_DEF_PATH)
88
+ else
89
+ []
90
+ end
91
+ rescue StandardError => e
92
+ warn "Failed to load tools data: #{e.message}"
93
+ []
94
+ end
95
+ end
96
+
97
+ def get_tool_metadata tool_slug
98
+ # Get a tool's info from tools definition
99
+ tools_data = load_tools_data
100
+ tools_data.find { |t| t['slug'] == tool_slug }
101
+ end
102
+
103
+ def get_tool_entry tool_slug
104
+ # Get a tool's configuration from project manifest
105
+ manifest = load_manifest
106
+ return nil unless manifest
107
+
108
+ manifest['tools']&.find { |t| t['tool'] == tool_slug }
109
+ end
110
+
111
+ def get_tool_files tool_slug
112
+ # Get file mappings for a tool from manifest
113
+ # Returns hash: { base: {upstream:, local:, synced:}, project: {upstream:, local:, synced:} }
114
+ tool_entry = get_tool_entry(tool_slug)
115
+ return {} unless tool_entry
116
+
117
+ files = {}
118
+ tool_entry['files']&.each do |file_config|
119
+ target_path = file_config['target']
120
+ source_path = file_config['source']
121
+
122
+ next unless target_path # Skip if no target path defined
123
+
124
+ if target_path.include?('.vendor/')
125
+ files[:base] = {
126
+ source: source_path,
127
+ local: target_path,
128
+ synced: file_config.fetch('synced', true)
129
+ }
130
+ else
131
+ files[:project] = {
132
+ source: source_path,
133
+ local: target_path,
134
+ synced: file_config.fetch('synced', false)
135
+ }
136
+ end
137
+ end
138
+
139
+ files
140
+ end
141
+
142
+ # Tool Execution
143
+
144
+ def run_with_fallback tool_name, command, use_docker: false
145
+ ToolExecution.run_with_fallback(tool_name, command, use_docker: use_docker)
146
+ end
147
+
148
+ def run_in_docker command
149
+ ToolExecution.run_in_docker(command)
150
+ end
151
+
152
+ def run_script script_name, args=[]
153
+ ScriptManager.run_script(script_name, args)
154
+ end
155
+
156
+ # Initialization
157
+
158
+ def create_project_manifest
159
+ Initializer.create_project_manifest
160
+ end
161
+
162
+ def bootstrap_project
163
+ Initializer.bootstrap_project
164
+ end
165
+
166
+ def install_vale_styles
167
+ SyncOps.install_vale_styles(self)
168
+ end
169
+
170
+ def install_missing_hooks
171
+ GitHooks.install_missing_hooks
172
+ end
173
+
174
+ def check_hook_updates
175
+ GitHooks.check_hook_updates
176
+ end
177
+
178
+ def update_hooks_interactive
179
+ GitHooks.update_hooks_interactive
180
+ end
181
+
182
+ def create_gitignore_stub
183
+ Initializer.create_gitignore_stub
184
+ end
185
+
186
+ # Sync Operations
187
+
188
+ def sync_config_files tool_filter=:all, offline: false
189
+ SyncOps.sync_config_files(self, tool_filter: tool_filter, offline: offline)
190
+ end
191
+
192
+ def sync_directory source_dir, target_dir, synced: false, expected_targets: nil
193
+ SyncOps.sync_directory(source_dir, target_dir, synced: synced, expected_targets: expected_targets)
194
+ end
195
+
196
+ def sync_scripts
197
+ SyncOps.sync_scripts(self)
198
+ end
199
+
200
+ def sync_vale_styles local: false
201
+ SyncOps.sync_vale_styles(self, local: local)
202
+ end
203
+
204
+ def sync_docs force: false
205
+ SyncOps.sync_docs(self, force: force)
206
+ end
207
+
208
+ # Checkers & Finders
209
+
210
+ def tool_available? tool_name
211
+ ToolExecution.tool_available?(tool_name)
212
+ end
213
+
214
+ def docker_available?
215
+ ToolExecution.docker_available?
216
+ end
217
+
218
+ def image_available?
219
+ ToolExecution.image_available?
220
+ end
221
+
222
+ def lab_dev_mode?
223
+ Checkers.lab_dev_mode?
224
+ end
225
+
226
+ def gem_sourced_locally?
227
+ Checkers.gem_sourced_locally?
228
+ end
229
+
230
+ def check_ruby_version
231
+ Checkers.check_ruby_version
232
+ end
233
+
234
+ def check_config_structure
235
+ Checkers.check_config_structure(self)
236
+ end
237
+
238
+ def check_standard_rake_tasks
239
+ Checkers.check_standard_rake_tasks
240
+ end
241
+
242
+ def find_shell_scripts
243
+ FileUtilities.find_shell_scripts(self)
244
+ end
245
+
246
+ def shell_shebang? file
247
+ FileUtilities.shell_shebang?(file)
248
+ end
249
+
250
+ def find_asciidoc_files
251
+ FileUtilities.find_asciidoc_files(self)
252
+ end
253
+
254
+ def get_path_config tool_slug
255
+ ConfigManager.get_path_config(tool_slug, self)
256
+ end
257
+
258
+ def file_matches_ignore_pattern? file, pattern
259
+ FileUtilities.file_matches_ignore_pattern?(file, pattern)
260
+ end
261
+
262
+ def git_tracked_or_staged? file
263
+ FileUtilities.git_tracked_or_staged?(file)
264
+ end
265
+
266
+ # Special Runtime Config Handling
267
+
268
+ def generate_vale_config style_override: nil
269
+ ConfigManager.generate_vale_config(self, style_override: style_override)
270
+ end
271
+
272
+ def generate_htmlproofer_config
273
+ ConfigManager.generate_htmlproofer_config(self)
274
+ end
275
+
276
+ def load_htmlproofer_config
277
+ ConfigManager.load_htmlproofer_config
278
+ end
279
+
280
+ # Run Linters
281
+
282
+ def run_rubocop file_path=nil, opts_string=''
283
+ Linters.run_rubocop(self, file_path, opts_string)
284
+ end
285
+
286
+ def run_rubocop_with_filter filter_name
287
+ Linters.run_rubocop_with_filter(self, filter_name)
288
+ end
289
+
290
+ def run_shellcheck file_path=nil, opts_string=''
291
+ Linters.run_shellcheck(self, file_path, opts_string)
292
+ end
293
+
294
+ def run_actionlint opts_string=''
295
+ Linters.run_actionlint(self, opts_string)
296
+ end
297
+
298
+ def run_all_linters
299
+ Linters.run_all_linters(self)
300
+ end
301
+
302
+ def run_auto_fix
303
+ Linters.run_auto_fix
304
+ AsciiidocAutoFix.fix_asciidoc_files(self)
305
+ end
306
+
307
+ def run_rubocop_auto_fix path: nil
308
+ Linters.run_rubocop_auto_fix(self, path: path)
309
+ end
310
+
311
+ def run_adoc_auto_fix path=nil
312
+ AutoFixAsciidoc.fix_asciidoc_files(self, path: path)
313
+ end
314
+
315
+ def run_linter_group group_name, linters
316
+ Linters.run_linter_group(self, group_name, linters)
317
+ end
318
+
319
+ def run_vale file_path=nil, opts_string='', output_format: :cli, filter: nil, style_override: nil
320
+ Linters.run_vale self, file_path, opts_string, output_format: output_format, filter: filter,
321
+ style_override: style_override
322
+ end
323
+
324
+ def lint_file file_path
325
+ Linters.lint_file(self, file_path)
326
+ end
327
+
328
+ # Show Stuff
329
+
330
+ def show_lint_rule tool, rule
331
+ case tool
332
+ when 'vale'
333
+ print_vale_style(rule)
334
+ when 'rubocop'
335
+ print_cop(rule)
336
+ else
337
+ puts "❌ Unknown or unsupported tool: #{tool}. Supported tools: vale, rubocop"
338
+ end
339
+ end
340
+
341
+ def list_hook_templates
342
+ GitHooks.list_hook_templates
343
+ end
344
+
345
+ def list_script_templates
346
+ ScriptManager.list_script_templates
347
+ end
348
+
349
+ private
350
+
351
+ def print_vale_style rule
352
+ puts "📄 Vale rule documentation for: #{rule}"
353
+ package = rule.split('.').first
354
+ rule_name = rule.split('.').last
355
+ style_path = File.join('.config', '.vendor', 'vale', 'styles', package, "#{rule_name}.yml")
356
+ unless File.exist?(style_path)
357
+ puts "❌ Vale rule file not found: #{style_path}"
358
+ return
359
+ end
360
+ config = File.read(CONFIG_PATHS[:vale])
361
+ config.lines.each do |line|
362
+ next unless line.strip.start_with?("#{package}.#{rule_name} =")
363
+
364
+ rule_setting = line.strip.split('=', 2).last.strip
365
+ puts "⚙️ Rule setting from #{CONFIG_PATHS[:vale]}: '#{rule_setting}'"
366
+ break
367
+ end
368
+ unless File.exist?(style_path)
369
+ puts "❌ Failed to retrieve style definition from #{style_path}"
370
+ return
371
+ end
372
+ puts '---'
373
+ puts File.read(style_path)
374
+ puts ''
375
+ end
376
+
377
+ def print_cop rule
378
+ puts "📄 RuboCop cop documentation for: #{rule}"
379
+ cmd = "bundle exec rubocop --show-cops #{rule} --config #{RUBOCOP_CONFIG_PATH}"
380
+ success = system(cmd)
381
+ puts '❌ Failed to retrieve RuboCop cop documentation' unless success
382
+ end
383
+
384
+ def find_files_to_lint tool_slug
385
+ FileUtilities.find_files_to_lint(tool_slug, self)
386
+ end
387
+ end
388
+ end
389
+ end
390
+
391
+ # Auto-load tasks when required
392
+ DocOpsLab::Dev::Tasks.new if defined?(Rake)
@@ -0,0 +1,64 @@
1
+ source:
2
+ repo: DocOps/lab
3
+ ref: v1
4
+ root: gems/docopslab-dev/assets/config-packs
5
+
6
+ docs:
7
+ - source: docs/agent/AGENTS.md
8
+ target: AGENTS.md
9
+ synced: false
10
+ - source: docs/agent/skills/*.md
11
+ target: .agent/docs/skills/
12
+ synced: true
13
+ - source: docs/agent/topics/*.md
14
+ target: .agent/docs/topics/
15
+ synced: true
16
+ - source: docs/agent/roles/*.md
17
+ target: .agent/docs/roles/
18
+ synced: true
19
+
20
+ tools:
21
+ - tool: rubocop
22
+ files:
23
+ - source: rubocop/base.yml
24
+ target: .config/.vendor/docopslab/rubocop.yml
25
+ synced: true
26
+ - source: rubocop/project.yml
27
+ target: .config/rubocop.yml
28
+ synced: false
29
+
30
+ - tool: vale
31
+ files:
32
+ - source: vale/base.ini
33
+ target: .config/.vendor/docopslab/vale.ini
34
+ synced: true
35
+ - source: vale/project.ini
36
+ target: .config/vale.local.ini
37
+ synced: false
38
+
39
+ - tool: htmlproofer
40
+ enabled: false # Disabled by default, enable per project
41
+ files:
42
+ - source: htmlproofer/base.yml
43
+ target: .config/.vendor/docopslab/htmlproofer.yml
44
+ synced: true
45
+ - source: htmlproofer/project.yml
46
+ target: .config/htmlproofer.yml
47
+ synced: false
48
+ paths:
49
+ lint: docs/_site
50
+
51
+ - tool: shellcheck
52
+ files:
53
+ - source: shellcheck/base.shellcheckrc
54
+ target: .config/shellcheckrc
55
+ synced: true
56
+
57
+ - tool: actionlint
58
+ files:
59
+ - source: actionlint/base.yml
60
+ target: .config/.vendor/docopslab/actionlint.yml
61
+ synced: true
62
+ - source: actionlint/project.yml
63
+ target: .config/actionlint.yml
64
+ synced: false
@@ -0,0 +1,63 @@
1
+ $schema:
2
+ type: Map
3
+ desc: Manifest for docopslab-dev config sync
4
+ meta:
5
+ version: v1
6
+ properties:
7
+ _meta:
8
+ req: [source,tools]
9
+ source:
10
+ type: Map
11
+ properties:
12
+ _meta:
13
+ req: [repo,ref]
14
+ repo:
15
+ type: String
16
+ desc: Source repo.
17
+ default: DocOps/lab
18
+ ref:
19
+ type: String
20
+ desc: Git ref (tag or branch) to fetch from
21
+ default:
22
+ spec: The latest tag.
23
+ root:
24
+ type: String
25
+ desc: Root path within the source repo
26
+ default: config-packs
27
+ tools:
28
+ type: ArrayTable
29
+ desc: List of config targets to sync & tools to permit.
30
+ properties:
31
+ _meta:
32
+ req: [tool,files]
33
+ tool:
34
+ type: Slug
35
+ desc: Tool ID; must match registry.
36
+ enable:
37
+ type: Boolean
38
+ desc: Whether to sync this target (default: true)
39
+ default: true
40
+ synced:
41
+ type: Boolean
42
+ desc: Whether to keep this file in sync with upstream source
43
+ default: false
44
+ files:
45
+ type: ArrayTable
46
+ desc: List of upstream/local file pairs
47
+ properties:
48
+ _meta:
49
+ req: [upstream,local]
50
+ upstream:
51
+ type: Path
52
+ desc: Upstream path within config-packs root
53
+ local:
54
+ type: Path
55
+ desc: Local destination path within the project repo
56
+ synced:
57
+ type: Boolean
58
+ desc: Whether to auto-sync this file from upstream (overwrites local changes)
59
+ default: true
60
+ enabled:
61
+ type: Boolean
62
+ desc: Whether this file mapping is active
63
+ default: true