commenter 0.2.2 → 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/.rubocop.yml +4 -0
- data/.rubocop_todo.yml +7 -102
- data/CLAUDE.md +58 -0
- data/README.adoc +154 -14
- data/commenter.gemspec +3 -2
- data/data/github_config_sample.yaml +8 -0
- data/data/github_issue_body_template.liquid +1 -1
- data/data/github_issue_title_template.liquid +1 -1
- data/lib/commenter/cli.rb +20 -11
- data/lib/commenter/comment.rb +34 -2
- data/lib/commenter/comment_sheet.rb +10 -2
- data/lib/commenter/github_integration.rb +67 -21
- data/lib/commenter/parser/osd_xlsx_parser.rb +252 -0
- data/lib/commenter/parser.rb +95 -37
- data/lib/commenter/version.rb +1 -1
- data/schema/iso_comment_2012-03.yaml +2 -2
- data/schema/iso_comment_osd.yaml +112 -0
- data/spec/commenter/cli_spec.rb +35 -0
- data/spec/commenter/comment_spec.rb +2 -2
- data/spec/commenter/github_integration_spec.rb +3 -3
- data/spec/commenter/osd_xlsx_parser_spec.rb +180 -0
- data/spec/support/osd_fixtures.rb +94 -0
- data/spec/support/xlsx_builder.rb +147 -0
- metadata +26 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 99f441f58237864e8ea0bc5c8682f04d2b15757ef1f28c45317f0181d6621fb4
|
|
4
|
+
data.tar.gz: 0a48406aa86377612a2722455dad5013457a10805da311c74c1fbfb82cccafd7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7c26ede9e2a9e4f5f060c0b8679cc9afcb36214a4c5b1a2f02c15a44cd6671d7b104954f4cf4b6df3df9f3806ab7c4d0418982a75371805c773c90064b82c8b9
|
|
7
|
+
data.tar.gz: 32dd2e31a603391bef5a112d0b10da62b7c29e249bcc76c3e5456aab939015ff51d21036108c3366743db11e01411a2bd285b7992f1a534009d5d4cc184e9d31
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
|
@@ -1,80 +1,21 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
2
|
# `rubocop --auto-gen-config`
|
|
3
|
-
# on
|
|
3
|
+
# on 2026-03-16 10:59:51 UTC using RuboCop version 1.85.1.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
9
|
# Offense count: 1
|
|
10
|
-
# Configuration parameters: Severity, Include.
|
|
11
|
-
# Include: **/*.gemspec
|
|
12
10
|
Gemspec/RequiredRubyVersion:
|
|
13
11
|
Exclude:
|
|
14
12
|
- 'commenter.gemspec'
|
|
15
13
|
|
|
16
|
-
# Offense count: 1
|
|
17
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
18
|
-
# Configuration parameters: EnforcedStyleAlignWith, Severity.
|
|
19
|
-
# SupportedStylesAlignWith: start_of_line, begin
|
|
20
|
-
Layout/BeginEndAlignment:
|
|
21
|
-
Exclude:
|
|
22
|
-
- 'lib/commenter/parser.rb'
|
|
23
|
-
|
|
24
|
-
# Offense count: 1
|
|
25
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
26
|
-
# Configuration parameters: EnforcedStyle.
|
|
27
|
-
# SupportedStyles: empty_lines, no_empty_lines
|
|
28
|
-
Layout/EmptyLinesAroundBlockBody:
|
|
29
|
-
Exclude:
|
|
30
|
-
- 'spec/commenter_spec.rb'
|
|
31
|
-
|
|
32
|
-
# Offense count: 2
|
|
33
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
34
|
-
# Configuration parameters: Width, AllowedPatterns.
|
|
35
|
-
Layout/IndentationWidth:
|
|
36
|
-
Exclude:
|
|
37
|
-
- 'lib/commenter/parser.rb'
|
|
38
|
-
|
|
39
|
-
# Offense count: 1
|
|
40
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
41
|
-
Layout/RescueEnsureAlignment:
|
|
42
|
-
Exclude:
|
|
43
|
-
- 'lib/commenter/parser.rb'
|
|
44
|
-
|
|
45
14
|
# Offense count: 1
|
|
46
15
|
Lint/NonLocalExitFromIterator:
|
|
47
16
|
Exclude:
|
|
48
17
|
- 'lib/commenter/filler.rb'
|
|
49
18
|
|
|
50
|
-
# Offense count: 4
|
|
51
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
52
|
-
Lint/SafeNavigationWithEmpty:
|
|
53
|
-
Exclude:
|
|
54
|
-
- 'lib/commenter/parser.rb'
|
|
55
|
-
|
|
56
|
-
# Offense count: 1
|
|
57
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
58
|
-
# Configuration parameters: AutoCorrect, IgnoreEmptyBlocks, AllowUnusedKeywordArguments.
|
|
59
|
-
Lint/UnusedBlockArgument:
|
|
60
|
-
Exclude:
|
|
61
|
-
- 'lib/commenter/filler.rb'
|
|
62
|
-
|
|
63
|
-
# Offense count: 4
|
|
64
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
65
|
-
# Configuration parameters: AutoCorrect, AllowUnusedKeywordArguments, IgnoreEmptyMethods, IgnoreNotImplementedMethods, NotImplementedExceptions.
|
|
66
|
-
# NotImplementedExceptions: NotImplementedError
|
|
67
|
-
Lint/UnusedMethodArgument:
|
|
68
|
-
Exclude:
|
|
69
|
-
- 'lib/commenter/github_integration.rb'
|
|
70
|
-
|
|
71
|
-
# Offense count: 1
|
|
72
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
73
|
-
# Configuration parameters: AutoCorrect.
|
|
74
|
-
Lint/UselessAssignment:
|
|
75
|
-
Exclude:
|
|
76
|
-
- 'lib/commenter/parser.rb'
|
|
77
|
-
|
|
78
19
|
# Offense count: 15
|
|
79
20
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
|
|
80
21
|
Metrics/AbcSize:
|
|
@@ -89,9 +30,9 @@ Metrics/BlockLength:
|
|
|
89
30
|
# Offense count: 5
|
|
90
31
|
# Configuration parameters: CountComments, CountAsOne.
|
|
91
32
|
Metrics/ClassLength:
|
|
92
|
-
Max:
|
|
33
|
+
Max: 231
|
|
93
34
|
|
|
94
|
-
# Offense count:
|
|
35
|
+
# Offense count: 8
|
|
95
36
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
|
96
37
|
Metrics/CyclomaticComplexity:
|
|
97
38
|
Max: 22
|
|
@@ -101,7 +42,7 @@ Metrics/CyclomaticComplexity:
|
|
|
101
42
|
Metrics/MethodLength:
|
|
102
43
|
Max: 53
|
|
103
44
|
|
|
104
|
-
# Offense count:
|
|
45
|
+
# Offense count: 8
|
|
105
46
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
|
106
47
|
Metrics/PerceivedComplexity:
|
|
107
48
|
Max: 22
|
|
@@ -112,7 +53,7 @@ Metrics/PerceivedComplexity:
|
|
|
112
53
|
# ForbiddenPrefixes: is_, has_, have_, does_
|
|
113
54
|
# AllowedMethods: is_a?
|
|
114
55
|
# MethodDefinitionMacros: define_method, define_singleton_method
|
|
115
|
-
Naming/
|
|
56
|
+
Naming/PredicatePrefix:
|
|
116
57
|
Exclude:
|
|
117
58
|
- 'spec/**/*'
|
|
118
59
|
- 'lib/commenter/comment.rb'
|
|
@@ -130,45 +71,9 @@ Style/Documentation:
|
|
|
130
71
|
- 'lib/commenter/github_integration.rb'
|
|
131
72
|
- 'lib/commenter/parser.rb'
|
|
132
73
|
|
|
133
|
-
# Offense count: 1
|
|
134
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
135
|
-
# Configuration parameters: AutoCorrect, EnforcedStyle, AllowComments.
|
|
136
|
-
# SupportedStyles: empty, nil, both
|
|
137
|
-
Style/EmptyElse:
|
|
138
|
-
Exclude:
|
|
139
|
-
- 'lib/commenter/filler.rb'
|
|
140
|
-
|
|
141
74
|
# Offense count: 3
|
|
142
75
|
# This cop supports safe autocorrection (--autocorrect).
|
|
143
|
-
|
|
144
|
-
Exclude:
|
|
145
|
-
- 'lib/commenter/cli.rb'
|
|
146
|
-
- 'lib/commenter/github_integration.rb'
|
|
147
|
-
- 'lib/commenter/parser.rb'
|
|
148
|
-
|
|
149
|
-
# Offense count: 1
|
|
150
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
151
|
-
Style/MultilineIfModifier:
|
|
152
|
-
Exclude:
|
|
153
|
-
- 'lib/commenter/parser.rb'
|
|
154
|
-
|
|
155
|
-
# Offense count: 2
|
|
156
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
157
|
-
Style/RescueModifier:
|
|
158
|
-
Exclude:
|
|
159
|
-
- 'lib/commenter/parser.rb'
|
|
160
|
-
|
|
161
|
-
# Offense count: 2
|
|
162
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
163
|
-
# Configuration parameters: EnforcedStyle.
|
|
164
|
-
# SupportedStyles: implicit, explicit
|
|
165
|
-
Style/RescueStandardError:
|
|
166
|
-
Exclude:
|
|
167
|
-
- 'lib/commenter/parser.rb'
|
|
168
|
-
|
|
169
|
-
# Offense count: 2
|
|
170
|
-
# This cop supports safe autocorrection (--autocorrect).
|
|
171
|
-
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
|
|
76
|
+
# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, AllowRBSInlineAnnotation, AllowCopDirectives, AllowedPatterns, SplitStrings.
|
|
172
77
|
# URISchemes: http, https
|
|
173
78
|
Layout/LineLength:
|
|
174
|
-
Max:
|
|
79
|
+
Max: 138
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
bin/setup # install dependencies
|
|
9
|
+
bundle exec rake # default task: specs + RuboCop (this is what CI runs)
|
|
10
|
+
bundle exec rspec # all specs
|
|
11
|
+
bundle exec rspec spec/commenter/comment_spec.rb # single spec file
|
|
12
|
+
bundle exec rspec spec/commenter/comment_spec.rb:42 # single example
|
|
13
|
+
bundle exec rubocop # lint (part of default rake task — must be clean)
|
|
14
|
+
bundle exec rubocop -a # autocorrect
|
|
15
|
+
bundle exec exe/commenter # run the CLI locally
|
|
16
|
+
bin/console # interactive prompt
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
CI (metanorma/ci `generic-rake.yml`) runs `bundle exec rake` on Ruby 3.2/3.4/4.0 across macOS/Ubuntu/Windows. RuboCop offenses fail CI — run `bundle exec rake`, not just rspec, before pushing. `Gemfile.lock` is gitignored; dependencies resolve fresh in CI.
|
|
20
|
+
|
|
21
|
+
Specs generate XLSX fixtures at runtime via `spec/support/xlsx_builder.rb` (plain rubyzip, no spreadsheet-writing dependency) plus row data in `spec/support/osd_fixtures.rb` — there are no binary fixture files in the repo.
|
|
22
|
+
|
|
23
|
+
## What this gem does
|
|
24
|
+
|
|
25
|
+
Converts ISO comment sheets to structured YAML and back, and syncs comments to GitHub issues:
|
|
26
|
+
|
|
27
|
+
- **Import**: DOCX (ISO 2012-03 balloting template) or XLSX (ISO Online Standards Development exports) → YAML + schema file. Format auto-detected from extension.
|
|
28
|
+
- **Fill**: YAML → filled DOCX comment sheet (`data/iso_comment_template_2012-03.docx`), optional status-based cell shading.
|
|
29
|
+
- **GitHub round-trip**: `github-create` makes issues from YAML via Liquid templates; `github-retrieve` pulls `> **OBSERVATION:**` blockquotes from closed issues back into the YAML's observations field.
|
|
30
|
+
|
|
31
|
+
Plain text only — formulas/images/complex formatting are unsupported (docx gem limitation).
|
|
32
|
+
|
|
33
|
+
## Architecture
|
|
34
|
+
|
|
35
|
+
Core flow: `Parser` → `CommentSheet` (metadata + `Comment` objects) → YAML / DOCX / GitHub issues.
|
|
36
|
+
|
|
37
|
+
- `Commenter::Comment` / `Commenter::CommentSheet` — data model. `Comment` carries the common fields plus optional OSD-specific fields (`user_name`, `resolution_status`, `motivation`, etc.) and a `github` sub-hash tracking issue state. The sheet's `version` field (`"2012-03"` vs `"osd"`) selects the output schema.
|
|
38
|
+
- `Commenter::Parser` — dispatches by format: `.docx` parsed inline with the `docx` gem; `.xlsx` delegated to `Parser::OsdXlsxParser` (uses `roo`).
|
|
39
|
+
- `Parser::OsdXlsxParser` — auto-detects two OSD export variants by header row ("resolved" 17-col starting `Comment ID`; "unresolved" 15-col starting `User name`), extracts metadata (date/reference/stage/titles) from header rows 1–2, maps columns by header name into `Comment` attributes, and synthesizes `observations` from `resolution_status` + `motivation`.
|
|
40
|
+
- `Commenter::Filler` — writes comments into the DOCX template table.
|
|
41
|
+
- `Commenter::GitHubIssueCreator` (`lib/commenter/github_integration.rb`) — Octokit-based; duplicate detection searches for a unique ID rendered from a configurable Liquid `unique_id` template (stage-aware by default: `[DIS] GB-001`), so the same comment ID at different ballot stages creates separate issues.
|
|
42
|
+
- `Commenter::Cli` (`lib/commenter/cli.rb`) — Thor CLI with subcommands `import`, `fill`, `github-create`, `github-retrieve`.
|
|
43
|
+
|
|
44
|
+
### Schemas
|
|
45
|
+
|
|
46
|
+
`schema/iso_comment_2012-03.yaml` and `schema/iso_comment_osd.yaml` are JSON-Schema-style files for IDE validation. `import` copies the matching schema (based on sheet version) into the schema dir and stamps the YAML header with a `yaml-language-server` reference. When the data model changes, update the corresponding schema file.
|
|
47
|
+
|
|
48
|
+
### Templates
|
|
49
|
+
|
|
50
|
+
`data/github_issue_title_template.liquid` and `data/github_issue_body_template.liquid` render issue titles/bodies; both are user-overridable via config. See README.adoc for the full variable list.
|
|
51
|
+
|
|
52
|
+
## Conventions
|
|
53
|
+
|
|
54
|
+
- Ruby style: double-quoted strings (enforced by RuboCop).
|
|
55
|
+
- `data/` files (DOCX template, Liquid templates, sample config) are shipped with the gem and loaded relative to `__dir__` — do not treat them as disposable.
|
|
56
|
+
- Testing GitHub integration: use `--dry-run` with `GITHUB_TOKEN=dummy_token` — exercises template rendering without API calls.
|
|
57
|
+
- `sig/commenter.rbs` is a minimal stub; RBS coverage is not currently maintained.
|
|
58
|
+
- Release: pushing a `v*` tag triggers `.github/workflows/release.yml`. Version lives in `lib/commenter/version.rb`.
|
data/README.adoc
CHANGED
|
@@ -7,14 +7,18 @@ image:https://img.shields.io/github/commits-since/metanorma/commenter/latest.svg
|
|
|
7
7
|
|
|
8
8
|
== Purpose
|
|
9
9
|
|
|
10
|
-
Commenter is a Ruby gem for working with ISO comment sheets in DOCX
|
|
10
|
+
Commenter is a Ruby gem for working with ISO comment sheets in DOCX and XLSX
|
|
11
|
+
format.
|
|
11
12
|
|
|
12
13
|
It provides utilities for parsing, manipulating, and serializing ISO comment
|
|
13
|
-
data, converting between DOCX and structured YAML with schema validation.
|
|
14
|
+
data, converting between DOCX/XLSX and structured YAML with schema validation.
|
|
14
15
|
|
|
15
|
-
The
|
|
16
|
+
The supported input formats are:
|
|
16
17
|
|
|
17
18
|
* "ISO/IEC/CEN/CENELEC electronic balloting commenting template/version 2012-03"
|
|
19
|
+
(DOCX)
|
|
20
|
+
* ISO Online Standards Development (OSD) XLSX exports (resolved and unresolved
|
|
21
|
+
comment sheets)
|
|
18
22
|
|
|
19
23
|
This gem only supports plain text comment extraction and filling. Only use this
|
|
20
24
|
to handle plain text comments and resolutions.
|
|
@@ -49,19 +53,27 @@ $ gem install commenter
|
|
|
49
53
|
|
|
50
54
|
== Usage
|
|
51
55
|
|
|
52
|
-
=== Importing comments
|
|
56
|
+
=== Importing comments
|
|
53
57
|
|
|
54
|
-
Convert an ISO comment sheet DOCX
|
|
58
|
+
Convert an ISO comment sheet (DOCX or XLSX) to structured YAML.
|
|
59
|
+
The format is auto-detected from the file extension.
|
|
55
60
|
|
|
56
61
|
[source,shell]
|
|
57
62
|
----
|
|
63
|
+
# From DOCX (ISO 2012-03 template or OSD DOCX export)
|
|
58
64
|
$ commenter import "ISO 80000-2 review comments.docx" -o comments.yaml
|
|
65
|
+
|
|
66
|
+
# From XLSX (ISO OSD resolved comment export)
|
|
67
|
+
$ commenter import "91855-Comments-resolved.xlsx" -o comments.yaml
|
|
68
|
+
|
|
69
|
+
# From XLSX (ISO OSD comments-only export)
|
|
70
|
+
$ commenter import "ISO 5843-6-Comments.xlsx" -o comments.yaml
|
|
59
71
|
----
|
|
60
72
|
|
|
61
73
|
This will create two files:
|
|
62
74
|
|
|
63
75
|
`comments.yaml`:: The structured comment data
|
|
64
|
-
`schema/iso_comment_2012-03.yaml`:: The YAML schema for validation
|
|
76
|
+
`schema/iso_comment_2012-03.yaml` or `schema/iso_comment_osd.yaml`:: The YAML schema for validation (selected automatically based on input format)
|
|
65
77
|
|
|
66
78
|
==== Import options
|
|
67
79
|
|
|
@@ -75,6 +87,10 @@ Options:
|
|
|
75
87
|
`-o, --output FILE`:: Output YAML file (default: comments.yaml)
|
|
76
88
|
`-e, --exclude-observations`:: Skip the observations column
|
|
77
89
|
`--schema-dir DIR`:: Directory for schema file (default: schema)
|
|
90
|
+
`--format FORMAT`:: Force input format (`docx` or `xlsx`; auto-detected by default)
|
|
91
|
+
`--sheet NAME`:: XLSX sheet name to parse (default: first sheet)
|
|
92
|
+
`--resolved-only`:: XLSX: use resolved comments sheet only
|
|
93
|
+
`--unresolved-only`:: XLSX: use unresolved comments sheet only
|
|
78
94
|
|
|
79
95
|
==== Metadata (extraction limitation)
|
|
80
96
|
|
|
@@ -227,6 +243,7 @@ The title template (`data/github_issue_title_template.liquid`) supports these va
|
|
|
227
243
|
* `body` - Member body abbreviation
|
|
228
244
|
* `type` - Comment type code
|
|
229
245
|
* `clause`, `element`, `line_number` - Location information
|
|
246
|
+
* `unique_id` - Rendered unique identifier (see <<_duplicate_detection>>)
|
|
230
247
|
|
|
231
248
|
===== Body template variables
|
|
232
249
|
|
|
@@ -256,6 +273,7 @@ github:
|
|
|
256
273
|
templates:
|
|
257
274
|
title: "custom_title.liquid"
|
|
258
275
|
body: "custom_body.liquid"
|
|
276
|
+
unique_id: "[{{ stage | upcase }}] {{ comment_id }}" # Optional: customize unique ID
|
|
259
277
|
----
|
|
260
278
|
====
|
|
261
279
|
|
|
@@ -301,9 +319,75 @@ $ commenter github comments.yaml --config github_config.yaml
|
|
|
301
319
|
|
|
302
320
|
==== Duplicate detection
|
|
303
321
|
|
|
304
|
-
The gem automatically checks for existing issues to avoid duplicates
|
|
305
|
-
|
|
306
|
-
|
|
322
|
+
The gem automatically checks for existing issues to avoid duplicates. The duplicate
|
|
323
|
+
detection uses a **configurable unique identifier** that is:
|
|
324
|
+
|
|
325
|
+
. Rendered from a Liquid template
|
|
326
|
+
. Embedded in the issue title for human identification
|
|
327
|
+
. Used as the search pattern to find existing issues
|
|
328
|
+
|
|
329
|
+
This ensures that the search pattern always matches what appears in the title,
|
|
330
|
+
preventing synchronization issues.
|
|
331
|
+
|
|
332
|
+
===== Unique ID template
|
|
333
|
+
|
|
334
|
+
The unique identifier is defined by the `unique_id` template in your configuration:
|
|
335
|
+
|
|
336
|
+
[source,yaml]
|
|
337
|
+
----
|
|
338
|
+
github:
|
|
339
|
+
templates:
|
|
340
|
+
# Default: "[STAGE] COMMENT_ID"
|
|
341
|
+
unique_id: "[{{ stage | upcase }}] {{ comment_id }}"
|
|
342
|
+
----
|
|
343
|
+
|
|
344
|
+
The default renders to: `[DIS] GB-001`
|
|
345
|
+
|
|
346
|
+
===== Why stage-aware unique IDs?
|
|
347
|
+
|
|
348
|
+
ISO standards go through multiple ballot stages (WD, CD, DIS, FDIS). The same
|
|
349
|
+
comment ID (e.g., `GB-001`) appears at each stage, but represents **different
|
|
350
|
+
comments**:
|
|
351
|
+
|
|
352
|
+
| Stage | Comment ID | Unique ID | Same Issue? |
|
|
353
|
+
|-------|------------|-----------|-------------|
|
|
354
|
+
| CD | GB-001 | `[CD] GB-001` | No |
|
|
355
|
+
| DIS | GB-001 | `[DIS] GB-001` | No |
|
|
356
|
+
|
|
357
|
+
Without stage-aware unique IDs, CD `GB-001` and DIS `GB-001` would be treated as
|
|
358
|
+
duplicates, causing the DIS comment to be skipped.
|
|
359
|
+
|
|
360
|
+
===== Custom unique ID patterns
|
|
361
|
+
|
|
362
|
+
You can customize the unique ID pattern to match your title template format:
|
|
363
|
+
|
|
364
|
+
[source,yaml]
|
|
365
|
+
----
|
|
366
|
+
github:
|
|
367
|
+
templates:
|
|
368
|
+
# Different order
|
|
369
|
+
unique_id: "{{ comment_id }} [{{ stage | upcase }}]"
|
|
370
|
+
|
|
371
|
+
# With document prefix
|
|
372
|
+
unique_id: "{{ document }} - {{ comment_id }}"
|
|
373
|
+
|
|
374
|
+
# With body prefix (for multi-body projects)
|
|
375
|
+
unique_id: "{{ body }}/{{ comment_id }}"
|
|
376
|
+
|
|
377
|
+
# Single stage project (no stage needed)
|
|
378
|
+
unique_id: "{{ comment_id }}"
|
|
379
|
+
----
|
|
380
|
+
|
|
381
|
+
===== Using unique_id in templates
|
|
382
|
+
|
|
383
|
+
The `unique_id` is available as a variable in title and body templates:
|
|
384
|
+
|
|
385
|
+
[source,liquid]
|
|
386
|
+
----
|
|
387
|
+
{{ unique_id }}: {{ brief_summary }} {% if document %}({{ document }}){% endif %}
|
|
388
|
+
----
|
|
389
|
+
|
|
390
|
+
This renders to: `[DIS] GB-001: Clause 5.1 summary (ISO/DIS 2533)`
|
|
307
391
|
|
|
308
392
|
==== Retrieving observations from GitHub issues
|
|
309
393
|
|
|
@@ -462,12 +546,17 @@ The comment types are defined as follows:
|
|
|
462
546
|
`te`:: Technical comment
|
|
463
547
|
`ed`:: Editorial comment
|
|
464
548
|
|
|
549
|
+
NOTE: In generated YAML, types are stored in expanded form (`general`,
|
|
550
|
+
`technical`, `editorial`). Short codes are accepted as input anywhere and are
|
|
551
|
+
expanded when the comment is loaded.
|
|
552
|
+
|
|
465
553
|
=== Workflow integration
|
|
466
554
|
|
|
467
555
|
[source,mermaid]
|
|
468
556
|
----
|
|
469
557
|
flowchart LR
|
|
470
|
-
|
|
558
|
+
A1[ISO Comment Sheet DOCX] --> B[commenter import]
|
|
559
|
+
A2[ISO OSD XLSX export] --> B
|
|
471
560
|
B --> C[YAML + Schema]
|
|
472
561
|
C --> D[commenter github-create]
|
|
473
562
|
D --> E[YAML + GitHub Info]
|
|
@@ -498,6 +587,8 @@ recognized and applied to the observations column:
|
|
|
498
587
|
|
|
499
588
|
== Data model
|
|
500
589
|
|
|
590
|
+
=== ISO 2012-03 template (DOCX)
|
|
591
|
+
|
|
501
592
|
The comment structure follows this schema:
|
|
502
593
|
|
|
503
594
|
[source,yaml]
|
|
@@ -525,14 +616,61 @@ comments: # Array of comment objects
|
|
|
525
616
|
updated_at: string # ISO 8601 timestamp (optional)
|
|
526
617
|
----
|
|
527
618
|
|
|
619
|
+
=== ISO OSD format (XLSX)
|
|
620
|
+
|
|
621
|
+
The OSD format includes additional metadata and resolution fields extracted from
|
|
622
|
+
the ISO Online Standards Development platform:
|
|
623
|
+
|
|
624
|
+
[source,yaml]
|
|
625
|
+
----
|
|
626
|
+
version: "osd" # OSD format identifier
|
|
627
|
+
date: string # Date from XLSX header (auto-extracted)
|
|
628
|
+
document: string # Document reference, e.g. "ISO/DIS 5843-6(en)"
|
|
629
|
+
project: string # Project name (auto-extracted)
|
|
630
|
+
stage: string # Stage: WD, CD, DIS, FDIS, PRF, PUB (auto-extracted)
|
|
631
|
+
title_en: string # Document title in English (auto-extracted)
|
|
632
|
+
title_fr: string # Document title in French (auto-extracted)
|
|
633
|
+
comments:
|
|
634
|
+
- id: string # Comment ID (numeric from OSD)
|
|
635
|
+
body: string # User name / member body
|
|
636
|
+
locality:
|
|
637
|
+
clause: string # Clause number
|
|
638
|
+
element: string # Clause title
|
|
639
|
+
type: "ge" | "te" | "ed"
|
|
640
|
+
comments: string # Comment text
|
|
641
|
+
proposed_change: string
|
|
642
|
+
observations: string # Built from resolution_status + motivation
|
|
643
|
+
user_name: string # OSD user name
|
|
644
|
+
comment_type: string # Subtype: Editorial, General, Technical
|
|
645
|
+
resolution_status: string # Accepted, Partially accepted, Rejected, etc.
|
|
646
|
+
resolution_date: string # Date resolved
|
|
647
|
+
feedbacks: string # Discussion replies
|
|
648
|
+
motivation: string # Resolution justification
|
|
649
|
+
created_date: string # Date comment was created
|
|
650
|
+
stage_code: string # ISO stage code (e.g. "40.20")
|
|
651
|
+
----
|
|
652
|
+
|
|
653
|
+
The OSD XLSX format comes in two variants, both auto-detected:
|
|
654
|
+
|
|
655
|
+
*Resolved*: 17 columns starting with `Comment ID`, includes resolution data
|
|
656
|
+
(`Resolution status`, `Motivation`, `Resolution Date`, `Stage code`)
|
|
657
|
+
|
|
658
|
+
*Unresolved/comments-only*: 15 columns starting with `User name`, includes
|
|
659
|
+
`Comment type`, `Comment/Motivation`, `Replies`, `Comment number`
|
|
660
|
+
|
|
528
661
|
|
|
529
662
|
== Schema validation
|
|
530
663
|
|
|
531
|
-
Each exported YAML file includes a schema reference for IDE support
|
|
664
|
+
Each exported YAML file includes a schema reference for IDE support.
|
|
665
|
+
The schema is selected automatically based on the input format:
|
|
532
666
|
|
|
533
667
|
[source,yaml]
|
|
534
668
|
----
|
|
669
|
+
# For ISO 2012-03 DOCX imports:
|
|
535
670
|
# yaml-language-server: $schema=schema/iso_comment_2012-03.yaml
|
|
671
|
+
|
|
672
|
+
# For ISO OSD XLSX imports:
|
|
673
|
+
# yaml-language-server: $schema=schema/iso_comment_osd.yaml
|
|
536
674
|
----
|
|
537
675
|
|
|
538
676
|
This enables:
|
|
@@ -627,7 +765,8 @@ The gem is organized into several key components:
|
|
|
627
765
|
|
|
628
766
|
`Commenter::Comment`:: Represents individual comments with locality, type, and content
|
|
629
767
|
`Commenter::CommentSheet`:: Container for multiple comments with metadata
|
|
630
|
-
`Commenter::Parser`:: Handles DOCX parsing
|
|
768
|
+
`Commenter::Parser`:: Handles DOCX and XLSX parsing with auto-detection
|
|
769
|
+
`Commenter::Parser::OsdXlsxParser`:: Parses ISO OSD XLSX exports (resolved and unresolved variants)
|
|
631
770
|
`Commenter::Filler`:: Fills DOCX templates with comment data
|
|
632
771
|
`Commenter::GitHubIssueCreator`:: Creates GitHub issues from comments
|
|
633
772
|
|
|
@@ -635,7 +774,7 @@ The gem is organized into several key components:
|
|
|
635
774
|
|
|
636
775
|
`Commenter::Cli`:: Thor-based command-line interface with subcommands:
|
|
637
776
|
|
|
638
|
-
** `import` - Convert DOCX to YAML
|
|
777
|
+
** `import` - Convert DOCX or XLSX to YAML
|
|
639
778
|
** `fill` - Fill DOCX template from YAML
|
|
640
779
|
** `github-create` - Create GitHub issues from comments
|
|
641
780
|
** `github-retrieve` - Retrieve observations from GitHub issues
|
|
@@ -646,7 +785,8 @@ The gem is organized into several key components:
|
|
|
646
785
|
* `data/github_issue_title_template.liquid` - GitHub issue title template
|
|
647
786
|
* `data/github_issue_body_template.liquid` - GitHub issue body template
|
|
648
787
|
* `data/github_config_sample.yaml` - Sample GitHub configuration
|
|
649
|
-
* `schema/iso_comment_2012-03.yaml` - YAML schema for validation
|
|
788
|
+
* `schema/iso_comment_2012-03.yaml` - YAML schema for ISO 2012-03 validation
|
|
789
|
+
* `schema/iso_comment_osd.yaml` - YAML schema for ISO OSD format validation
|
|
650
790
|
|
|
651
791
|
=== Debugging
|
|
652
792
|
|
data/commenter.gemspec
CHANGED
|
@@ -12,8 +12,8 @@ Gem::Specification.new do |spec|
|
|
|
12
12
|
spec.authors = ["Ribose"]
|
|
13
13
|
spec.email = ["open.source@ribose.com"]
|
|
14
14
|
|
|
15
|
-
spec.summary = "Library to work with ISO comment sheets in DOCX
|
|
16
|
-
spec.description = "Convert between ISO comment
|
|
15
|
+
spec.summary = "Library to work with ISO comment sheets in DOCX and XLSX formats."
|
|
16
|
+
spec.description = "Convert between ISO comment sheets (DOCX and XLSX) and structured YAML with schema validation."
|
|
17
17
|
spec.homepage = "https://github.com/metanorma/commenter"
|
|
18
18
|
spec.license = "BSD-2-Clause"
|
|
19
19
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.6.0")
|
|
@@ -35,5 +35,6 @@ Gem::Specification.new do |spec|
|
|
|
35
35
|
spec.add_dependency "dotenv", "~> 2.8"
|
|
36
36
|
spec.add_dependency "liquid", "~> 5.0"
|
|
37
37
|
spec.add_dependency "octokit", "~> 6.0"
|
|
38
|
+
spec.add_dependency "roo", ">= 2.10"
|
|
38
39
|
spec.add_dependency "thor", "~> 1.0"
|
|
39
40
|
end
|
|
@@ -61,9 +61,17 @@ github:
|
|
|
61
61
|
|
|
62
62
|
# Custom template paths (optional)
|
|
63
63
|
templates:
|
|
64
|
+
# Title template for GitHub issues
|
|
65
|
+
# The {{ unique_id }} variable is required for duplicate detection
|
|
64
66
|
title: "custom_title_template.liquid"
|
|
65
67
|
body: "custom_body_template.liquid"
|
|
66
68
|
|
|
69
|
+
# Unique identifier template for duplicate detection
|
|
70
|
+
# This is rendered and used to search for existing issues
|
|
71
|
+
# Default: "[{{ stage | upcase }}] {{ comment_id }}"
|
|
72
|
+
# The unique_id is also available as {{ unique_id }} in title/body templates
|
|
73
|
+
unique_id: "[{{ stage | upcase }}] {{ comment_id }}"
|
|
74
|
+
|
|
67
75
|
# Retrieval configuration for github-retrieve command
|
|
68
76
|
retrieval:
|
|
69
77
|
# Magic comment markers to look for in GitHub issue comments
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# {% if stage %}[{{ stage | upcase }}] {% endif %}{% if document %}{{ document }}
|
|
1
|
+
# {% if stage %}[{{ stage | upcase }}] {% endif %}{{ comment_id }} {% if document %}({{ document }}){% endif %}
|
|
2
2
|
|
|
3
3
|
**Stage:** {{ stage | default: "Not specified" }}
|
|
4
4
|
**Document:** {{ document | default: "Not specified" }}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{
|
|
1
|
+
{{ unique_id }}: {{ brief_summary }} {% if document %}({{ document }}){% endif %}
|
data/lib/commenter/cli.rb
CHANGED
|
@@ -9,34 +9,43 @@ require "commenter/github_integration"
|
|
|
9
9
|
|
|
10
10
|
module Commenter
|
|
11
11
|
class Cli < Thor
|
|
12
|
-
desc "import INPUT
|
|
12
|
+
desc "import INPUT", "Convert comment sheet (DOCX or XLSX) to YAML"
|
|
13
13
|
option :output, type: :string, aliases: :o, default: "comments.yaml", desc: "Output YAML file"
|
|
14
14
|
option :exclude_observations, type: :boolean, aliases: :e, desc: "Exclude observations column"
|
|
15
15
|
option :schema_dir, type: :string, default: "schema", desc: "Directory for schema file"
|
|
16
|
-
|
|
16
|
+
option :format, type: :string, desc: "Force input format (docx or xlsx)"
|
|
17
|
+
option :sheet, type: :string, desc: "XLSX sheet name to parse (default: first sheet)"
|
|
18
|
+
option :resolved_only, type: :boolean, desc: "XLSX: use resolved comments sheet only"
|
|
19
|
+
option :unresolved_only, type: :boolean, desc: "XLSX: use unresolved comments sheet only"
|
|
20
|
+
def import(input_file)
|
|
17
21
|
output_yaml = options[:output]
|
|
18
22
|
schema_dir = options[:schema_dir]
|
|
19
23
|
|
|
20
24
|
# Ensure schema directory exists
|
|
21
25
|
FileUtils.mkdir_p(schema_dir) unless Dir.exist?(schema_dir)
|
|
22
26
|
|
|
23
|
-
# Parse the
|
|
27
|
+
# Parse the input file
|
|
24
28
|
parser = Parser.new
|
|
25
|
-
comment_sheet = parser.parse(
|
|
29
|
+
comment_sheet = parser.parse(input_file, options)
|
|
30
|
+
|
|
31
|
+
# Determine which schema to use based on version
|
|
32
|
+
schema_name = comment_sheet.version == "osd" ? "iso_comment_osd.yaml" : "iso_comment_2012-03.yaml"
|
|
26
33
|
|
|
27
34
|
# Write the YAML data file with schema reference
|
|
28
|
-
yaml_content = generate_yaml_with_header(comment_sheet.to_yaml_h, schema_dir)
|
|
35
|
+
yaml_content = generate_yaml_with_header(comment_sheet.to_yaml_h, schema_dir, schema_name)
|
|
29
36
|
File.write(output_yaml, yaml_content)
|
|
30
37
|
|
|
31
38
|
# Copy schema file to output directory
|
|
32
|
-
schema_source = File.join(__dir__, "../../schema
|
|
33
|
-
schema_target = File.join(schema_dir,
|
|
39
|
+
schema_source = File.join(__dir__, "../../schema/#{schema_name}")
|
|
40
|
+
schema_target = File.join(schema_dir, schema_name)
|
|
34
41
|
|
|
35
42
|
# Only copy if source and target are different
|
|
36
43
|
FileUtils.cp(schema_source, schema_target) unless File.expand_path(schema_source) == File.expand_path(schema_target)
|
|
37
44
|
|
|
38
|
-
puts "Converted #{
|
|
39
|
-
puts "
|
|
45
|
+
puts "Converted #{input_file} to #{output_yaml}"
|
|
46
|
+
puts " Version: #{comment_sheet.version}"
|
|
47
|
+
puts " Comments: #{comment_sheet.comments.length}"
|
|
48
|
+
puts " Schema: #{schema_target}"
|
|
40
49
|
end
|
|
41
50
|
|
|
42
51
|
desc "fill INPUT.yaml", "Fill DOCX template from YAML comments"
|
|
@@ -206,8 +215,8 @@ module Commenter
|
|
|
206
215
|
|
|
207
216
|
private
|
|
208
217
|
|
|
209
|
-
def generate_yaml_with_header(data, schema_dir)
|
|
210
|
-
schema_path = File.join(schema_dir,
|
|
218
|
+
def generate_yaml_with_header(data, schema_dir, schema_name = "iso_comment_2012-03.yaml")
|
|
219
|
+
schema_path = File.join(schema_dir, schema_name)
|
|
211
220
|
header = "# yaml-language-server: $schema=#{schema_path}\n\n"
|
|
212
221
|
header + data.to_yaml
|
|
213
222
|
end
|