From 7b4abb17eb66003f2c1e7e721cc5a1178d09e358 Mon Sep 17 00:00:00 2001 From: Volker Schukai <volker.schukai@schukai.com> Date: Wed, 22 Jun 2022 17:14:07 +0200 Subject: [PATCH] chore: commit save point --- README.md | 137 ++++++++++-------- application/source/commandline.go | 3 +- application/source/gitlab.go | 52 ++++--- application/source/issues.go | 18 ++- development/examples/example1/req1/1/test1.md | 37 +++-- 5 files changed, 149 insertions(+), 98 deletions(-) diff --git a/README.md b/README.md index c1d01d9..d099423 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,6 @@ chmod u+x reqman The date format for the output can be specified with the parameter `--date-format`. The format can be looked up in the first column of the table below. - | Layout | Java notation | C notation | Notes | | ------------------ | --------------- | ------------ | ---------- | | 2006-01-02 | yyyy-MM-dd | %F | ISO 8601 | @@ -93,7 +92,6 @@ reqman tasks print --path=examples/ The output is then of the type: - | AUFGABE | BIS | ERLEDIGT | DATEI | | -------------------------- | ----- | ---------- | -------------------- | | das ist das erste todo 1 | — | — | ./req1/001-1425.md | @@ -106,7 +104,6 @@ reqman requirements print --path examples/ --column ID --column Title The output is then of the type: - | ID | TITEL | | ---- | ---------------- | | A1 | My requirement | @@ -127,7 +124,6 @@ reqman requirements print --path=example/ --column=ID --column= The output is then of the type: - | ID | GRUPPE | NAME | TYP | BESCHREIBUNG | BIS | ERLEDIGT | AM | VON | DATEI | | -------------------- | -------- | -------------------------- | ------ | -------------- | ------------ | ---------- | ------------ | ----- | ---------------------- | | 23423-Beistellung1 | A1 | Beistellung eines Bildes | Bild | Großes Logo | 2022-12-12 | ✓ | 2022-12-01 | Me | ./req1/002/002-01.md | @@ -159,37 +155,36 @@ requirements report --grouped-by ID This command produces two tables: - | Anforderung | Gesch | TIME SPENT | -| ------------- | ------- | ------------ | -| ID1 | 40 | 1 | -| ID2 | 40 | 1 | -| ID3 | 40 | 1 | -| ID4 | 40 | 1 | -| ID5 | 40 | 2 | -| ID6 | 40 | 2 | -| ID7 | 40 | 2 | -| ID8 | 40 | 2 | -| ID9 | 40 | 2 | -| ID10 | 40 | 2 | -| ID11 | 40 | 3 | -| ID12 | 40 | 3 | -| ID13 | 40 | 3 | -| ID14 | 40 | 3 | -| ID15 | 40 | 3 | -| ID16 | 40 | 3 | -| ID17 | 40 | 3 | -| ID18 | 40 | 4 | -| ID19 | 40 | 4 | -| ID20 | 40 | 4 | -| ID21 | 40 | 4 | -| ID22 | 40 | 5 | -| ID23 | 40 | 5 | -| ID24 | 40 | 6 | -| ID25 | 40 | 6 | - -1) Groups all estimates and adds up the estimate and the booked times. This allows you to see how much time you have spent. - +| ------------- | ------- | --------- | +| ID1 | 40 | 1 | +| ID2 | 40 | 1 | +| ID3 | 40 | 1 | +| ID4 | 40 | 1 | +| ID5 | 40 | 2 | +| ID6 | 40 | 2 | +| ID7 | 40 | 2 | +| ID8 | 40 | 2 | +| ID9 | 40 | 2 | +| ID10 | 40 | 2 | +| ID11 | 40 | 3 | +| ID12 | 40 | 3 | +| ID13 | 40 | 3 | +| ID14 | 40 | 3 | +| ID15 | 40 | 3 | +| ID16 | 40 | 3 | +| ID17 | 40 | 3 | +| ID18 | 40 | 4 | +| ID19 | 40 | 4 | +| ID20 | 40 | 4 | +| ID21 | 40 | 4 | +| ID22 | 40 | 5 | +| ID23 | 40 | 5 | +| ID24 | 40 | 6 | +| ID25 | 40 | 6 | + +1) Groups all estimates and adds up the estimate and the booked times. This allows you to see how much time you have + spent. | KEY | PLANNED VALUE | TIME SPENT | RATIO | | :---- | --------------- | ------------ | ------- | @@ -197,7 +192,6 @@ This command produces two tables: 2) This table shows for each plan value the hours needed, the mean, the variance and the standard deviation. - | PLAN VALUE | TIME SPENT | MEAN | VARIANCE | STANDARD DEVIATION | | ------------ | ------------ | ------ | ---------- | -------------------- | | 40 | 75h0m0s | 3.00 | 2.08 | 1.44 | @@ -211,6 +205,30 @@ The smaller the standard deviation, the better. So what decision can we derive? If a new requirement is estimated at 40, the hours offered should be between 3 and 5. +### Sync with Gitlab + +You can synchronize the issues of a document with a Gitlab server. + +```bash +reqman gitlab sync --path=example/ +``` + +If no ID is defined in the document, an issue is created, + +```yaml +issues: + - gitlab: + title: "Issue 1" +``` + +otherwise the data is updated. + +```yaml +issues: + - gitlab: + id: 1 +``` + ## Structure ### The Text @@ -223,42 +241,43 @@ The data from the YAML block can be integrated in the text via [placeholders](ht For example, the following statement can be used to include the items within the document. ```golang -{{ if .Items }} +{{ if.Items }} **Items** | ID | Name | Delivery until | Provided on | |--------------------|--------------|----------------------:|-----------------------------------------:| -{{ range .Items - }}| {{ .ID }} | {{ .Name }} | {{ .DeliveryUntil.Format "02.Jan" }} | {{ .ProvidedOn.Format "02.Jan" }} | +{{ range.Items +}}| {{ .ID }} | {{ .Name }} | {{ .DeliveryUntil.Format "02.Jan" }} | {{ .ProvidedOn.Format "02.Jan" }} | {{ end }} {{ end }} ``` -If the PDF function is used, LaTeX commands can also be included in the text. For example, the LaTex instruction `/newline' leads to a line break. +If the PDF function is used, LaTeX commands can also be included in the text. For example, the LaTex instruction ` +/newline' leads to a line break. ## YAML - -| | `>` | `|` | | `"` | `'` | `>-` | `>+` | `|-` | `|+` | -| --------------------------------- | ----- | ------ | --- | ---- | --- | ----- | ------ | ------ | ------ | -| **Spaces/newlines converted as:** | | | | | | | | | | -| Trailing space → | \_ | \_ | | | | \_ | \_ | \_ | \_ | -| Leading space → | \\n\_ | \\n\_ | | | | \\n\_ | \\n\_ | \\n\_ | \\n\_ | -| Single newline → | \_ | \\n | \_ | \_ | \_ | \_ | \_ | \\n | \\n | -| Double newline → | \\n | \\n\\n | \\n | \\n | \\n | \\n | \\n | \\n\\n | \\n\\n | -| Final newline → | \\n | \\n | | | | | \\n | | \\n | -| Final double newline → | | | | | | | \\n\\n | | \\n\\n | -| **How to create a literal:** | | | | | | | | | | -| Single quote | ' | ' | ' | ' | '' | ' | ' | ' | ' | -| Double quote | " | " | " | \\" | " | " | " | " | " | -| Backslash | \\ | \\ | \\ | \\\\ | \\ | \\ | \\ | \\ | \\ | -| **Other features** | | | | | | | | | | -| In-line newlines with `\n` | 🚫 | 🚫 | 🚫 | ✅ | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | -| Spaceless newlines with `\` | 🚫 | 🚫 | 🚫 | ✅ | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | -| `#` or `:` in value | ✅ | ✅ | 🚫 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| Can start on same line as key | 🚫 | 🚫 | ✅ | ✅ | ✅ | 🚫 | 🚫 | 🚫 | 🚫 | - +| | `>` | `│` | | `"` | `'` | `>-` | `>+` | `│-` | `│+` | +|-----------------------------------|---------|--------|-----|------|-----|-------|--------|--------|--------| +| **Spaces/newlines converted as:** | | | | | | | | | | +| Trailing space → | \_ | \_ | | | | \_ | \_ | \_ | \_ | +| Leading space → | \\n\_ | \\n\_ | | | | \\n\_ | \\n\_ | \\n\_ | \\n\_ | +| Single newline → | \_ | \\n | \_ | \_ | \_ | \_ | \_ | \\n | \\n | +| Double newline → | \\n | \\n\\n | \\n | \\n | \\n | \\n | \\n | \\n\\n | \\n\\n | +| Final newline → | \\n | \\n | | | | | \\n | | \\n | +| Final double newline → | | | | | | | \\n\\n | | \\n\\n | +| **How to create a literal:** | | | | | | | | | | +| Single quote | ' | ' | ' | ' | '' | ' | ' | ' | ' | +| Double quote | " | " | " | \\" | " | " | " | " | " | +| Backslash | \\ | \\ | \\ | \\\\ | \\ | \\ | \\ | \\ | \\ | +| **Other features** | | | | | | | | | | +| In-line newlines with `\n` | 🚫 | 🚫 | 🚫 | ✅ | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | +| Spaceless newlines with `\` | 🚫 | 🚫 | 🚫 | ✅ | 🚫 | 🚫 | 🚫 | 🚫 | 🚫 | +| `#` or `:` in value | ✅ | ✅ | 🚫 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| Can start on same line as key | 🚫 | 🚫 | ✅ | ✅ | ✅ | 🚫 | 🚫 | 🚫 | 🚫 | + +`│ -> |` ## Latex diff --git a/application/source/commandline.go b/application/source/commandline.go index 3b1bc54..35b5366 100644 --- a/application/source/commandline.go +++ b/application/source/commandline.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "os" "path" "path/filepath" @@ -42,7 +41,7 @@ func executeCommand() { switch activeCommand.Name { case "version": - fmt.Println("Version " + version + " (" + build + ")") + printInfo("Version " + version + " (" + build + ")") case "changelog": subcommand := activeCommand.Active switch subcommand.Name { diff --git a/application/source/gitlab.go b/application/source/gitlab.go index 1f6ff04..7ca2a44 100644 --- a/application/source/gitlab.go +++ b/application/source/gitlab.go @@ -2,7 +2,6 @@ package main import ( "errors" - "fmt" "net/url" "path" @@ -250,33 +249,52 @@ func recursiveMerge(from, into *yaml.Node) error { func syncIssuesWithGitlab(pageData map[string]*requirement) { + err := enrichIssuesWithGitlab(pageData) + if err != nil { + printError(err.Error()) + printErrorAndExit(2, "Failed to enrich issues with gitlab") + } + for _, pageData := range pageData { for k, info := range pageData.Issues { - if info.GitlabRemote != nil { - continue - } - if info.GitlabIntern == nil { - continue - } + if info.GitlabIntern.ID == 0 { issue, err := createIssue(info) if err != nil { printErrorAndExit(2, "Failed to create issue %s", err.Error()) } + pageData.Issues[k].GitlabRemote = issue pageData.Issues[k].GitlabIntern = new(GitlabInternalIssueStruct) pageData.Issues[k].GitlabIntern.ID = issue.IID + pageData.Issues[k].GitlabIntern.URL = issue.WebURL + pageData.Issues[k].GitlabIntern.Title = issue.Title + pageData.Issues[k].GitlabIntern.Description = issue.Description + pageData.Issues[k].GitlabIntern.Labels = issue.Labels + pageData.Issues[k].GitlabIntern.Status = issue.State - var change yaml.Node - bytes, err := yaml.Marshal(&pageData) - if err != nil { - fmt.Println(err) - } - yaml.Unmarshal(bytes, &change) - recursiveRemove(pageData.OriginNode) - recursiveMerge(&change, pageData.OriginNode) + } else { + + pageData.Issues[k].GitlabIntern = new(GitlabInternalIssueStruct) + pageData.Issues[k].GitlabIntern.ID = info.GitlabRemote.IID + pageData.Issues[k].GitlabIntern.URL = info.GitlabRemote.WebURL + pageData.Issues[k].GitlabIntern.Title = info.GitlabRemote.Title + pageData.Issues[k].GitlabIntern.Description = info.GitlabRemote.Description + pageData.Issues[k].GitlabIntern.Labels = info.GitlabRemote.Labels + pageData.Issues[k].GitlabIntern.Status = info.GitlabRemote.State } + var change yaml.Node + bytes, err := yaml.Marshal(&pageData) + if err != nil { + printError("Failed to marshal page data %s", err.Error()) + continue + } + + yaml.Unmarshal(bytes, &change) + recursiveRemove(pageData.OriginNode) + recursiveMerge(&change, pageData.OriginNode) + } } } @@ -309,8 +327,8 @@ func createIssue(issue Issue) (*gitlab.Issue, error) { return gitlabIssue, err } - printInfo("Created issue %s (%s)", gitlabIssue.Title, gitlabIssue.ID) - printInfo(" %s", gitlabIssue.WebURL) + printInfo("Created issue %v (ID %v)", gitlabIssue.Title, gitlabIssue.IID) + printInfo("\t%s", gitlabIssue.WebURL) return gitlabIssue, nil } diff --git a/application/source/issues.go b/application/source/issues.go index 0cb9f5b..372baa6 100644 --- a/application/source/issues.go +++ b/application/source/issues.go @@ -11,16 +11,18 @@ import ( ) type GitlabInternalIssueStruct struct { - ID int `yaml:"ID"` - Title string `yaml:"Title,omitempty"` - Description string `yaml:"Description,omitempty"` - //Priority string `yaml:"Priority,omitempty"` - Status string `yaml:"Status,omitempty"` - //Assignee string `yaml:"Assignee,omitempty"` - //Milestone string `yaml:"Milestone,omitempty"` - Labels []string `yaml:"Labels,omitempty"` + ID int `yaml:"ID"` + Title string `yaml:"Title,omitempty"` + Description string `yaml:"Description,omitempty"` + Status string `yaml:"Status,omitempty"` + Labels []string `yaml:"Labels,omitempty"` + URL string `yaml:"URL,omitempty"` } +//Priority string `yaml:"Priority,omitempty"` +//Assignee string `yaml:"Assignee,omitempty"` +//Milestone string `yaml:"Milestone,omitempty"` + type Issue struct { GitlabIntern *GitlabInternalIssueStruct `yaml:"Gitlab"` GitlabRemote *gitlab.Issue `yaml:"-"` diff --git a/development/examples/example1/req1/1/test1.md b/development/examples/example1/req1/1/test1.md index a0f6a3b..a28b2fd 100644 --- a/development/examples/example1/req1/1/test1.md +++ b/development/examples/example1/req1/1/test1.md @@ -39,18 +39,6 @@ Time Spent: 2h Source: null Created: 2022-05-03 Last Update: null -Issues: - - Gitlab: - ID: 1 - - Gitlab: - Title: Test 1 - Status: offen - Description: | - Lorem Ipsum Lila Rot - Blau1 Lila Rot Blau2 - Labels: - - a - - b # the individual items as a list Items: - ID: null @@ -103,7 +91,32 @@ Privacy: # Where possible, a general description of the technical and organisational # security measures referred to in Article 32(1). TOM: null +Issues: + - Gitlab: + ID: 1 + Title: demo + Status: closed + Labels: + - bug + - enhancement + - feature + URL: https://gitlab.schukai.com/oss/utilities/requirements-manager/-/issues/1 + - Gitlab: + ID: 47 + Title: Test 15 + Description: |- + Lorem Ipsum Lila Rot + Blau1 Lila Rot Blau2 + + ``` + a=4 + ``` + Status: closed + Labels: + - bug + - bugfix + URL: https://gitlab.schukai.com/oss/utilities/requirements-manager/-/issues/47 ... ### {{ .Title }} - {{ .ID }} -- GitLab