beachio-hammer 0.1.0.pre5 → 0.1.0.pre6

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 761f1f1873cb333406eeab947ee2ae1edde559b69fa38497810c96bdf802f58e
4
- data.tar.gz: 6721ab8889e4129b9c886fa875b92579d359a9012852d69aaa711fa1e29c08eb
3
+ metadata.gz: f3b4a0b499b230ddf29d32eec63d87dc4e6ceac09bbfdcbc11b076532dad79a6
4
+ data.tar.gz: 6eb175a810aae7ad23c4ffef79f770cb9201083f3ed4466b9c3ed5fefb975c4c
5
5
  SHA512:
6
- metadata.gz: 23c9ab030b80757ac305dc66d4f0a35c9df394e248fa22ce62e8164d96c9b1573c4771b49ea82770574c113a7c4fd56ccfd26e294bda7f4515ede443dca28bfa
7
- data.tar.gz: 5b670417365cbd83d7a706f3a1dc03edaadbcde2ca5cff920651446f66c790565d97a798e3a784fed847493cd62e1051cd27a0a4b23d11d67cd46014fb85314b
6
+ metadata.gz: 1b6f05d60825d07e45d3c1055b76b4e9e1155c664ae7de008602c1072fbddec96d19818aad8496f7955eb1f3b4c7c9363cc6ab87ab8990e77dded5a4bd9e00c7
7
+ data.tar.gz: 036de2226fd8f9708baf2ff5a46c9fe58f23b7d54e61331ca55aa87f55fb2b0cf05c351869d6fc7a48091104068aebf18a0fa8b3e984115cfb175a5900d67d5b
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- beachio-hammer (0.1.0.pre5)
4
+ beachio-hammer (0.1.0.pre6)
5
5
  json (~> 2.7)
6
6
 
7
7
  GEM
data/PUBLISH.md CHANGED
@@ -38,7 +38,14 @@ gem build beachio-hammer.gemspec
38
38
  gem push beachio-hammer-*.gem
39
39
  ```
40
40
 
41
- Prerelease pin for executor team: **`beachio-hammer` `0.1.0.pre5`**
41
+ Prerelease pin for executor team: **`beachio-hammer` `0.1.0.pre6`**
42
+
43
+ ### 0.1.0.pre6 changes (`hammer check`)
44
+
45
+ - Add `hammer check` for content validation (Swift CLI parity)
46
+ - Flags: `--project`, `--strict`, `--format json|human`
47
+ - Rule IDs: `CONFIG_MISSING`, `CONFIG_INVALID`, `COLLECTION_DIR_MISSING`, `TEMPLATE_MISSING`, `PARSE_ERROR`, `REQUIRED_FIELD_MISSING`, `SLUG_MISSING`, `PROJECT_NOT_FOUND`
48
+ - Agent QC: `hammer check --strict --format json`
42
49
 
43
50
  ### 0.1.0.pre5 changes (collection loops on static pages)
44
51
 
@@ -68,16 +75,17 @@ Prerelease pin for executor team: **`beachio-hammer` `0.1.0.pre5`**
68
75
  Pin the published gem version in the executor Dockerfile:
69
76
 
70
77
  ```dockerfile
71
- RUN gem install beachio-hammer -v 0.1.0.pre5
78
+ RUN gem install beachio-hammer -v 0.1.0.pre6
72
79
  ```
73
80
 
74
- Build step in the agent:
81
+ Validate and build in the agent:
75
82
 
76
83
  ```bash
84
+ hammer check --project "$WORKSPACE" --strict --format json
77
85
  hammer build --project "$WORKSPACE" --mode export --format json --clean
78
86
  ```
79
87
 
80
- ### CLI contract
88
+ ### CLI contract — `hammer build`
81
89
 
82
90
  | Flag | Default | Notes |
83
91
  |------|---------|-------|
@@ -100,6 +108,29 @@ hammer build --project "$WORKSPACE" --mode export --format json --clean
100
108
  }
101
109
  ```
102
110
 
111
+ ### CLI contract — `hammer check`
112
+
113
+ | Flag | Default | Notes |
114
+ |------|---------|-------|
115
+ | `--project` | cwd (walk-up for markers) | Project root |
116
+ | `--strict` | off | Treat warnings as errors |
117
+ | `--format` | `human` | `json` for agent parsing |
118
+
119
+ **Exit codes:** `0` pass (or warnings without `--strict`), `1` check failures, `2` project/config error, `3` internal.
120
+
121
+ **JSON stdout** (`--format json`):
122
+
123
+ ```json
124
+ {
125
+ "status": "pass",
126
+ "errors": [{ "ruleId", "message", "file", "suggestion" }],
127
+ "warnings": [{ "ruleId", "message", "file", "suggestion" }],
128
+ "stats": { "filesChecked", "durationMs" }
129
+ }
130
+ ```
131
+
132
+ **Rule IDs:** `CONFIG_MISSING` (warn), `CONFIG_INVALID`, `COLLECTION_DIR_MISSING`, `TEMPLATE_MISSING`, `PARSE_ERROR`, `REQUIRED_FIELD_MISSING`, `SLUG_MISSING` (warn), `PROJECT_NOT_FOUND` (JSON `status: "error"`, exit 2).
133
+
103
134
  ### Parity fixtures
104
135
 
105
136
  | Fixture | Path | Files |
@@ -23,6 +23,7 @@ require_relative "hammer/content/page_generator"
23
23
  require_relative "hammer/content/builder"
24
24
  require_relative "hammer/builder"
25
25
  require_relative "hammer/build_command"
26
+ require_relative "hammer/check_command"
26
27
  require_relative "hammer/cli"
27
28
 
28
29
  module Hammer
data/lib/hammer/cli.rb CHANGED
@@ -2,13 +2,17 @@
2
2
 
3
3
  module Hammer
4
4
  module CLI
5
+ KNOWN_COMMANDS = %w[build check].freeze
6
+
5
7
  module_function
6
8
 
7
9
  def run(argv)
8
- command = argv.first == "build" ? argv.shift : "build"
10
+ command = resolve_command(argv)
9
11
  case command
10
12
  when "build"
11
13
  BuildCommand.run(argv)
14
+ when "check"
15
+ CheckCommand.run(argv)
12
16
  else
13
17
  warn "Unknown command: #{command}"
14
18
  2
@@ -23,5 +27,13 @@ module Hammer
23
27
  warn "Build failed: #{e.message}"
24
28
  1
25
29
  end
30
+
31
+ def resolve_command(argv)
32
+ return "build" if argv.empty?
33
+ return argv.shift if KNOWN_COMMANDS.include?(argv.first)
34
+ return "build" if argv.first.start_with?("-")
35
+
36
+ argv.first
37
+ end
26
38
  end
27
39
  end
@@ -22,6 +22,24 @@ module Hammer
22
22
  output&.dig("filename") || output_path
23
23
  end
24
24
 
25
+ def validate_required_fields(metadata)
26
+ return [] unless fields
27
+
28
+ missing = []
29
+ fields.each do |field_name, field_config|
30
+ next unless field_config.required == true
31
+
32
+ unless metadata.key?(field_name)
33
+ missing << field_name
34
+ next
35
+ end
36
+
37
+ value = metadata[field_name]
38
+ missing << field_name if value.is_a?(String) && value.empty?
39
+ end
40
+ missing
41
+ end
42
+
25
43
  def self.from_hash(hash)
26
44
  fields = (hash["fields"] || {}).transform_values { |f| FieldConfig.from_hash(f) }
27
45
  new(
@@ -29,5 +29,56 @@ module Hammer
29
29
  puts "Build finished in #{duration.round(2)}s — #{file_count} files (#{build_size})"
30
30
  end
31
31
  end
32
+
33
+ def format_check_result(status:, errors:, warnings:, files_checked:, duration_ms:, format:)
34
+ if format == :json
35
+ payload = {
36
+ "status" => status,
37
+ "errors" => errors.map { |e| check_issue_hash(e) },
38
+ "warnings" => warnings.map { |w| check_issue_hash(w) },
39
+ "stats" => {
40
+ "filesChecked" => files_checked,
41
+ "durationMs" => duration_ms
42
+ }
43
+ }
44
+ puts JSON.pretty_generate(payload)
45
+ return
46
+ end
47
+
48
+ puts ""
49
+ if status == "pass"
50
+ puts "\u2714 #{files_checked} files validated"
51
+ else
52
+ puts "\u2716 #{errors.length} error#{errors.length == 1 ? '' : 's'}"
53
+ end
54
+
55
+ errors.each do |error|
56
+ puts ""
57
+ puts "[#{error[:rule_id]}]"
58
+ puts error[:message]
59
+ puts " #{error[:file]}"
60
+ puts " Suggestion: #{error[:suggestion]}" if error[:suggestion]
61
+ end
62
+
63
+ unless warnings.empty?
64
+ puts ""
65
+ puts "\u26A0 #{warnings.length} warning#{warnings.length == 1 ? '' : 's'}"
66
+ warnings.each do |warning|
67
+ puts " [#{warning[:rule_id]}] #{warning[:message]}"
68
+ puts " #{warning[:file]}"
69
+ end
70
+ end
71
+ puts ""
72
+ end
73
+
74
+ def check_issue_hash(issue)
75
+ hash = {
76
+ "ruleId" => issue[:rule_id],
77
+ "message" => issue[:message],
78
+ "file" => issue[:file]
79
+ }
80
+ hash["suggestion"] = issue[:suggestion] if issue[:suggestion]
81
+ hash
82
+ end
32
83
  end
33
84
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hammer
4
- VERSION = "0.1.0.pre5"
4
+ VERSION = "0.1.0.pre6"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: beachio-hammer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0.pre5
4
+ version: 0.1.0.pre6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Beach.io