diff --git a/.idea/modules.xml b/.idea/modules.xml index 2b7718b265b7186a2250aa2c91b4b2dc3b9949ad..d608247d5bcfb09c273c80aaa237ab5abfb77528 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,11 @@ <project version="4"> <component name="ProjectModuleManager"> <modules> + <module fileurl="file://$PROJECT_DIR$/../../../customer-projects/mey/alvine/Mey Alvine.iml" filepath="$PROJECT_DIR$/../../../customer-projects/mey/alvine/Mey Alvine.iml" /> + <module fileurl="file://$PROJECT_DIR$/../../../docker/alvine-mkdocs/alvine-mkdocs.iml" filepath="$PROJECT_DIR$/../../../docker/alvine-mkdocs/alvine-mkdocs.iml" /> + <module fileurl="file://$PROJECT_DIR$/../../../schukai/manual/manual.iml" filepath="$PROJECT_DIR$/../../../schukai/manual/manual.iml" /> <module fileurl="file://$PROJECT_DIR$/requirements-manager.iml" filepath="$PROJECT_DIR$/requirements-manager.iml" /> + <module fileurl="file://$PROJECT_DIR$/../../../customer-projects/administration/templates-for-requirements/templates-for-requirements.iml" filepath="$PROJECT_DIR$/../../../customer-projects/administration/templates-for-requirements/templates-for-requirements.iml" /> </modules> </component> </project> \ No newline at end of file diff --git a/.idea/runConfigurations/go_build_requirements_manager_and_run_print_overview.xml b/.idea/runConfigurations/go_build_requirements_manager_and_run_print_overview.xml index 3510644b0fc735b58df4340e0e4d04abf049bb39..6457f3d23ca25dc6ed655a0d4544deef54ee1548 100644 --- a/.idea/runConfigurations/go_build_requirements_manager_and_run_print_overview.xml +++ b/.idea/runConfigurations/go_build_requirements_manager_and_run_print_overview.xml @@ -2,7 +2,7 @@ <configuration default="false" name="go build requirements-manager and run print overview" type="GoApplicationRunConfiguration" factoryName="Go Application"> <module name="requirements-manager" /> <working_directory value="$PROJECT_DIR$/application/source" /> - <parameters value="overview print -c ID -c Title -c Version -p $PROJECT_DIR$/development/examples/example1 -o /tmp/overview.pdf -f pdf -t $PROJECT_DIR$/development/examples/overview.template" /> + <parameters value="overview print -c ID -c Title -c Version -p $PROJECT_DIR$/development/examples/example1 -o /tmp/overview.pdf -f pdf" /> <kind value="DIRECTORY" /> <package value="gitlab.schukai.com/oss/utilities/requirements-manager" /> <directory value="$PROJECT_DIR$/application/source" /> diff --git a/.idea/runConfigurations/go_build_requirements_manager_and_run_print_overview_mey.xml b/.idea/runConfigurations/go_build_requirements_manager_and_run_print_overview_mey.xml new file mode 100644 index 0000000000000000000000000000000000000000..d352f663f66e34c4623d36692730779743a0d328 --- /dev/null +++ b/.idea/runConfigurations/go_build_requirements_manager_and_run_print_overview_mey.xml @@ -0,0 +1,13 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="go build requirements-manager and run print overview (mey)" type="GoApplicationRunConfiguration" factoryName="Go Application"> + <module name="requirements-manager" /> + <working_directory value="$PROJECT_DIR$/application/source" /> + <parameters value="overview print -c ID -c ID -c Title -p $PROJECT_DIR$/../../../customer-projects/mey/alvine/requirement/documents -t $PROJECT_DIR$/../../../customer-projects/mey/alvine/requirement/template/schukai.md -l $PROJECT_DIR$/../../../customer-projects/mey/alvine/requirement/template/schukai.latex -o /tmp/overview.pdf -f pdf" /> + <kind value="DIRECTORY" /> + <package value="gitlab.schukai.com/oss/utilities/requirements-manager" /> + <directory value="$PROJECT_DIR$/application/source" /> + <filePath value="$PROJECT_DIR$/application/source/main.go" /> + <output_directory value="$PROJECT_DIR$/deployment/build" /> + <method v="2" /> + </configuration> +</component> \ No newline at end of file diff --git a/.idea/runConfigurations/go_build_requirements_manager_and_run_print_requirements.xml b/.idea/runConfigurations/go_build_requirements_manager_and_run_print_requirements.xml new file mode 100644 index 0000000000000000000000000000000000000000..ab66d06d6695ca37cb871846e008379aa59ccf0f --- /dev/null +++ b/.idea/runConfigurations/go_build_requirements_manager_and_run_print_requirements.xml @@ -0,0 +1,12 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="go build requirements-manager and run print requirements" type="GoApplicationRunConfiguration" factoryName="Go Application"> + <module name="requirements-manager" /> + <working_directory value="$PROJECT_DIR$/application/source" /> + <parameters value="requirements print -p $PROJECT_DIR$/development/examples/example1 -c ID -c Title" /> + <kind value="DIRECTORY" /> + <directory value="$PROJECT_DIR$/application/source" /> + <filePath value="$PROJECT_DIR$/application/source" /> + <output_directory value="$PROJECT_DIR$/deployment/build" /> + <method v="2" /> + </configuration> +</component> \ No newline at end of file diff --git a/.idea/runConfigurations/go_build_requirements_manager_and_run_print_todo.xml b/.idea/runConfigurations/go_build_requirements_manager_and_run_print_todo.xml index 8bdeda3473145a293d5453886544dcaca03a55d0..a5896b9ce69b25239cc5163fa49a41c017758494 100644 --- a/.idea/runConfigurations/go_build_requirements_manager_and_run_print_todo.xml +++ b/.idea/runConfigurations/go_build_requirements_manager_and_run_print_todo.xml @@ -2,7 +2,7 @@ <configuration default="false" name="go build requirements-manager and run print todo" type="GoApplicationRunConfiguration" factoryName="Go Application"> <module name="requirements-manager" /> <working_directory value="$PROJECT_DIR$/application/source" /> - <parameters value="todos print -p $PROJECT_DIR$/development/examples/example1" /> + <parameters value="tasks print -p $PROJECT_DIR$/development/examples/example1" /> <kind value="DIRECTORY" /> <package value="gitlab.schukai.com/oss/utilities/requirements-manager" /> <directory value="$PROJECT_DIR$/application/source" /> diff --git a/Makefile b/Makefile index e22a849263f82505e59d79dae015522fee916245..526a093afb4ebfc34f94103715277370a739bc4f 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,7 @@ SHELL = bash # path and binaries AWK := awk +GO := go CP := cp CD := cd KILL := /bin/kill @@ -91,7 +92,7 @@ NODE := node LN := ln -s # Executable Programs the Installed be have to -EXECUTABLES = $(AWK) $(CP) $(KILL) $(M4) $(MV) rm mkdir $(SED) $(SORT) $(TOUCH) $(WGET) $(CHMOD) $(NPX) $(FIND) $(XARGS) $(GREP) $(NPM) $(GIT) $(NPX) $(NODE) ln; +EXECUTABLES = $(AWK) $(CP) $(KILL) $(M4) $(MV) rm mkdir $(SED) $(SORT) $(TOUCH) $(WGET) $(CHMOD) $(NPX) $(FIND) $(XARGS) $(GREP) $(NPM) $(GIT) $(NPX) $(NODE) $(GO) ln; K := $(foreach exec,$(EXECUTABLES),\ $(if $(shell which $(exec)),some string,$(error "Missing $(exec) in PATH; please install"))) @@ -179,7 +180,8 @@ SCRIPTS_PATH := $(THIS_DIR)development/scripts/ DOCUMENTATION_PATH := $(THIS_DIR)documentation/ ## Build path -BUILD_PATH = $(THIS_DIR)deployment/build/ +BUILD_PATH = $(DEPLOYMENT_PATH)build/ + ############################################################################################# @@ -209,17 +211,6 @@ BUILD_PATH = $(THIS_DIR)deployment/build/ ############################################################################################# ############################################################################################# - - -############################################################################################# -############################################################################################# -## -## DIRECTORIES -## -############################################################################################# -############################################################################################# - - ############################################################################################# ############################################################################################# ## @@ -228,9 +219,21 @@ BUILD_PATH = $(THIS_DIR)deployment/build/ ############################################################################################# ############################################################################################# +## Compiling for every OS and Platform compile: echo "Compiling for every OS and Platform" - GOOS=linux GOARCH=arm $(GO) build -o $(BUILD_PATH)/reqman-linux-arm main.go - GOOS=linux GOARCH=arm32 $(GO) build -o $(BUILD_PATH)/reqman-linux-arm32 main.go - GOOS=linux GOARCH=arm64 $(GO) build -o $(BUILD_PATH)/reqman-linux-arm64 main.go - GOOS=freebsd GOARCH=386 $(GO) build -o $(BUILD_PATH)/reqman-freebsd-386 main.go \ No newline at end of file + + cd $(SOURCE_PATH); GOOS=linux GOARCH=arm $(GO) build -o $(BUILD_PATH)reqman-linux-arm; cd - + cd $(SOURCE_PATH); GOOS=linux GOARCH=amd64 $(GO) build -o $(BUILD_PATH)reqman-linux-amd64; cd - + cd $(SOURCE_PATH); GOOS=linux GOARCH=arm64 $(GO) build -o $(BUILD_PATH)reqman-linux-arm64; cd - + cd $(SOURCE_PATH); GOOS=linux GOARCH=386 $(GO) build -o $(BUILD_PATH)reqman-linux-386; cd - + cd $(SOURCE_PATH); GOOS=windows GOARCH=amd64 $(GO) build -o $(BUILD_PATH)reqman-windows; cd - + +## compile and deplay to aws +deploy: compile + find $(BUILD_PATH) -iname reqman-* -exec aws s3 cp {} s3://download.schukai.com/tools/reqman/ \; + +## overview-to-aws +overview-to-aws: + aws s3 cp $(WEB_PATH)/index.html s3://download.schukai.com/tools/reqman/ + \ No newline at end of file diff --git a/README.md b/README.md index f04569adb31eb30f6d3e2a1c78747876069ce514..4a4e298d3b245613224410237e5e0482a69fd2eb 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,180 @@ This tool helps to manage requirements written in Markdown. -### Create Table +## Install + +Reqman is a binary file that must be stored in a directory. +The files can be found [here](http://download.schukai.com/tools/reqman/). + +For Linux, the execution bit must still be set. + +```bash +chmod u+x reqman +``` + +## Commands + +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 | +| 20060102 | yyyyMMdd | %Y%m%d | ISO 8601 | +| January 02, 2006 | MMMM dd, yyyy | %B %d, %Y | | +| 02 January 2006 | dd MMMM yyyy | %d %B %Y | | +| 02-Jan-2006 | dd-MMM-yyyy | %d-%b-%Y | | +| 01/02/06 | MM/dd/yy | %D | US | +| 01/02/2006 | MM/dd/yyyy | %m/%d/%Y | US | +| 010206 | MMddyy | %m%d%y | US | +| Jan-02-06 | MMM-dd-yy | %b-%d-%y | US | +| Jan-02-2006 | MMM-dd-yyyy | %b-%d-%Y | US | +| 06 | yy | %y | | +| Mon | EEE | %a | | +| Monday | EEEE | %A | | +| Jan-06 | MMM-yy | %b-%y | | + +### Help + +There is help on the command line for each individual command. + +```bash +reqman --help +``` + +### New Requiremants + +A new request can be created with the following command. + +```bash +reqman requirements add --id 1425 +``` + +A completely new file with a structure is created. The `--id 1425` is both the file name and the ID of the request. + +All available fields are listed in the new file. + +### Output a PDF + +A pdf can be created using the following command: + +```bash +reqman overview \ + print \ + --path=requirement/documents \ + --column=ID \ + --column=Title \ + --template=template/schukai.md \ + --latex-template-path=requirement/template/schukai.latex \ + --output=report.pdf \ + --format=pdf +``` + +In this case the markdown files in the path `requirement/documents` are read. + +A table with all requirements is created in the file and the two columns +`ID` and `Title` are used. Additional columns can be added using additional options `--column`. + +File `template/schukai.md` is used as a template. + +The LaTeX template `requirement/template/schukai.latex` is used for the design of the pdf. + +The output format is PDF and the filename of the pdf document is `report.pdf`. + +You can use a complete directory or a subdirectory as the path. + +### Output of the tasks + +```bash +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 | + + +### Output of the items + +```bash +reqman requirements print --path examples/ --column ID --column Title +``` + +The output is then of the type: + +| ID | TITEL | +|-----|----------------| +| A1 | My requirement | + +More columns can be added with `--column`. + +### Output of requirements ```bash -requirements-manger table +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 | + + +### Output changelog + +```bash +reqman changelog print --path=example/ +``` + +The output is then of the type: + ``` +### 01.05.2022 + +- Requirement (R2) + +### 24.01.2022 + +- Requirement (R1) + +``` + + +## Structure + +### The Text + +The individual requirements are Markdown files with integrated YAML structure. The YAML structure must +be introduced with `---` and closed with `...`. + +The data from the YAML block can be integrated in the text via [placeholders](https://pkg.go.dev/text/template). + +For example, the following statement can be used to include the items within the document. + +```golang +{{ if .Items }} +**Items** + +| ID | Name | Delivery until | Provided on | +|--------------------|--------------|----------------------:|-----------------------------------------:| +{{ 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. + + +## Latex +Individual LaTeX commands can be looked up here: +* [tug.ctan.org/info/latex-refsheet/LaTeX_RefSheet.pdf](http://tug.ctan.org/info/latex-refsheet/LaTeX_RefSheet.pdf) +* [www.uni-frankfurt.de/53485609/latexsheet.pdf](https://www.uni-frankfurt.de/53485609/latexsheet.pdf) +* [www.latex4ei.de/downloads/LaTeX_CheatSheet.pdf](https://www.latex4ei.de/downloads/LaTeX_CheatSheet.pdf) +* [download.schukai.com/tools/reqman/](http://download.schukai.com/tools/reqman/) \ No newline at end of file diff --git a/application/source/changelog.go b/application/source/changelog.go new file mode 100644 index 0000000000000000000000000000000000000000..4c54ef52f8cc3126376371809f229dcc2e745c9c --- /dev/null +++ b/application/source/changelog.go @@ -0,0 +1,68 @@ +package main + +import ( + "fmt" + "sort" + "strings" +) + +type logs []string + +func buildChangelog(config *Configuration, pageMap map[string]requirement) (error, string, bool) { + + changelog := make(map[string]logs) + datemap := make(map[string]string) + + for _, p := range pageMap { + + e := strings.Trim(p.Title+" ("+p.ID+")", " ") + + d := p.Created.String() + datemap[d] = p.Created.Format(config.Locale.DateFormat) + if p.Created.Before(p.LastUpdate) { + d = p.LastUpdate.String() + datemap[d] = p.LastUpdate.Format(config.Locale.DateFormat) + } + + changelog[d] = append(changelog[d], e) + + } + + hasChangelog := false + result := "" + + var sortedKeys sort.StringSlice + for k := range changelog { + sortedKeys = append(sortedKeys, k) + } + + sort.Sort(sort.Reverse(sortedKeys)) + + for _, k := range sortedKeys { + + result += "### " + datemap[k] + "\n\n" + + for _, m := range changelog[k] { + result += "- " + m + "\n" + } + + result += "\n" + hasChangelog = true + + } + + return nil, result, hasChangelog + +} + +func printChangelog(config *Configuration) error { + + err, pageData := collectStructureFromFiles(config.Path) + if err != nil { + return err + } + + err, table, _ := buildChangelog(config, pageData) + fmt.Println(table) + return err +} diff --git a/application/source/commandline.go b/application/source/commandline.go index 89b5c0cdb2b3a51fa483968f08d7aca8d4e547ff..85f8d8a82ee1c1f6c94f12350ea244a73742139f 100644 --- a/application/source/commandline.go +++ b/application/source/commandline.go @@ -1,10 +1,18 @@ package main -import "fmt" +import ( + "fmt" + "os" + "path" + "path/filepath" + + "github.com/jessevdk/go-flags" +) type commandLineOptions struct { + Config string `short:"c" long:"config" description:"file with configuration values"` Path string `short:"p" long:"path" description:"define the path where the specifications are located" default:"."` - DateFormat string `short:"f" long:"date-format" description:"date format" default:"2006-01-02"` + DateFormat string `long:"date-format" description:"date format" default:"2006-01-02"` Requirements struct { Print struct { Columns []string `short:"c" long:"column" description:"defines the columns used"` @@ -21,12 +29,21 @@ type commandLineOptions struct { Print struct { } `command:"print"` } `command:"items"` + Changelog struct { + Print struct { + } `command:"print"` + } `command:"changelog"` + Privacy struct { + Print struct { + } `command:"print"` + } `command:"privacy"` Overview struct { Print struct { - Columns []string `short:"c" long:"column" description:"defines the columns used"` - TemplatePath string `short:"t" long:"template" description:"file name of the template of the overview page"` - Output string `short:"o" long:"output" description:"redirect output to a file"` - Format string `short:"f" long:"format" description:"the desired output format (pdf, md)"` + Columns []string `short:"c" long:"column" description:"defines the columns used"` + TemplatePath string `short:"t" long:"template" description:"file name of the template of the overview page"` + Output string `short:"o" long:"output" description:"redirect output to a file"` + Format string `short:"f" long:"format" description:"the desired output format" choice:"pdf" choice:"md"` + LatexTemplatePath string `short:"l" long:"latex-template-path" description:"latex template"` } `command:"print"` } `command:"overview"` Version struct { @@ -35,7 +52,24 @@ type commandLineOptions struct { func executeCommand() { - activeCommand, arguments, config := NewConfiguration() + arguments := new(commandLineOptions) + p := flags.NewParser(arguments, flags.Default) + _, err := p.Parse() + if err != nil { + os.Exit(-1) + } + + config := NewConfiguration(arguments.Config) + + if arguments.Path != "" { + config.Path = arguments.Path + } + + if arguments.DateFormat != "" { + config.Locale.DateFormat = arguments.DateFormat + } + + activeCommand := p.Command.Active version = "development" build = "1.1.1" @@ -44,10 +78,45 @@ func executeCommand() { case "version": fmt.Println("Version " + version + " (" + build + ")") + case "changelog": + subcommand := activeCommand.Active + switch subcommand.Name { + case "print": + err := printChangelog(config) + if err != nil { + printErrorAndExit(2, err.Error()) + } + } + case "privacy": + subcommand := activeCommand.Active + switch subcommand.Name { + case "print": + err := printPrivacy(config) + if err != nil { + printErrorAndExit(2, err.Error()) + } + } case "overview": subcommand := activeCommand.Active switch subcommand.Name { case "print": + + if len(arguments.Overview.Print.Columns) > 0 { + config.Requirement.Table.Columns = validateColumns(arguments.Overview.Print.Columns) + } + + if arguments.Overview.Print.TemplatePath != "" { + config.Overview.Template.Internal.MarkdownContent = readTemplate(arguments.Overview.Print.TemplatePath) + } else if config.Overview.Template.Markdown != "" { + config.Overview.Template.Internal.MarkdownContent = readTemplate(config.Overview.Template.Markdown) + } else { + config.Overview.Template.Internal.MarkdownContent = defaultOverviewTemplate + } + + if arguments.Overview.Print.LatexTemplatePath != "" { + config.Overview.Template.Latex = arguments.Overview.Print.LatexTemplatePath + } + err := PrintOverview(config, arguments) if err != nil { printErrorAndExit(2, err.Error()) @@ -58,11 +127,15 @@ func executeCommand() { subcommand := activeCommand.Active switch subcommand.Name { case "add": + config.Requirement.Template.Add = defaultNewRequirementTemplate err := addRequirement(config, arguments) if err != nil { printErrorAndExit(2, err.Error()) } case "print": + if len(arguments.Requirements.Print.Columns) > 0 { + config.Requirement.Table.Columns = validateColumns(arguments.Requirements.Print.Columns) + } err := printRequirements(config) if err != nil { printErrorAndExit(2, err.Error()) @@ -91,3 +164,25 @@ func executeCommand() { } } + +func readTemplate(argPath string) string { + + current, err := os.Getwd() + if err != nil { + printErrorAndExit(2, "Unknown Error", err.Error()) + } + + p := argPath + + if !filepath.IsAbs(p) { + p = path.Clean(current + "/" + p) + } + + template, err := os.ReadFile(p) + if err != nil { + printErrorAndExit(exitCodeCatchAll, + "the specified template", argPath) + } + + return convertTemplateImages(string(template), path.Dir(p)) +} diff --git a/application/source/config.go b/application/source/config.go index c37593a4b9fe3a4e618fc13a7c788f64e65ab06b..2ddd00d2f360bcec02542c8c683eeebfd7d6cba1 100644 --- a/application/source/config.go +++ b/application/source/config.go @@ -1,24 +1,18 @@ package main import ( - "log" "os" "os/user" "path" - "path/filepath" - "regexp" - "strings" - "github.com/jessevdk/go-flags" - "gopkg.in/yaml.v3" + "gopkg.in/yaml.v2" ) -const exitCodeParseArgumentError = 2 - type configPathsStruct struct { - current string - user string - main string + argument string + current string + user string + main string } var ( @@ -27,28 +21,32 @@ var ( } ) -// Exporting interface instead of struct -//type Configuration interface{} - // Configuration type Configuration struct { - Path string `yaml:"path"` + Path string `yaml:"Path"` Locale struct { - DateFormat string `yaml:"date-format"` + DateFormat string `yaml:"DateFormat"` } `yaml:"Locale"` - Table struct { - Columns []string `yaml:"columns"` - } `yaml:"table"` - Overview struct { - Template string `yaml:"template"` - } `yaml:"overview"` + Template struct { + Markdown string `yaml:"Markdown"` + Latex string `yaml:"Latex"` + Internal struct { + MarkdownContent string + } + } `yaml:"Template"` + } `yaml:"Overview"` Requirement struct { - Template string `yaml:"template"` - } `yaml:"requirement"` + Table struct { + Columns []string `yaml:"Columns"` + } `yaml:"Table"` + Template struct { + Add string `yaml:"Add"` + } `yaml:"Template"` + } `yaml:"Requirement"` } func fileExists(name string) (found bool) { @@ -59,14 +57,7 @@ func fileExists(name string) (found bool) { } // NewConfiguration -func NewConfiguration() (*flags.Command, *commandLineOptions, *Configuration) { - - arguments := new(commandLineOptions) - p := flags.NewParser(arguments, flags.Default) - _, err := p.Parse() - if err != nil { - os.Exit(-1) - } +func NewConfiguration(argConfigPath string) *Configuration { current, err := os.Getwd() if err != nil { @@ -82,10 +73,16 @@ func NewConfiguration() (*flags.Command, *commandLineOptions, *Configuration) { configPaths.user = usr.HomeDir + "/.config/requirements-manager/config.yaml" } + if argConfigPath != "" { + configPaths.argument = argConfigPath + } + switch { + case fileExists(configPaths.argument): + readFile(&cfg, configPaths.argument) case fileExists(filename): readFile(&cfg, filename) - case err == nil && fileExists(current): + case fileExists(current): readFile(&cfg, current) case fileExists(configPaths.user): readFile(&cfg, configPaths.user) @@ -93,155 +90,7 @@ func NewConfiguration() (*flags.Command, *commandLineOptions, *Configuration) { readFile(&cfg, configPaths.main) } - //readEnv(&cfg) - - if arguments.Path != "" { - cfg.Path = arguments.Path - } - - if arguments.DateFormat != "" { - cfg.Locale.DateFormat = arguments.DateFormat - } - - activeCommand := p.Command.Active - - switch activeCommand.Name { - - case "version": - - case "overview": - subcommand := activeCommand.Active - switch subcommand.Name { - case "print": - - if len(arguments.Overview.Print.Columns) > 0 { - cfg.Table.Columns = validateColumns(arguments.Overview.Print.Columns) - } - - if arguments.Overview.Print.TemplatePath != "" { - p := arguments.Overview.Print.TemplatePath - - current, err := os.Getwd() - if err != nil { - log.Println(err) - } - - if !filepath.IsAbs(p) { - p = path.Clean(current + "/" + p) - } - - template, err := os.ReadFile(p) - if err != nil { - printErrorAndExit(exitCodeCatchAll, - "the specified template", arguments.Overview.Print.TemplatePath) - } - - cfg.Overview.Template = convertTemplateImages(string(template), path.Dir(p)) - } else { - cfg.Overview.Template = defaultOverviewTemplate - } - } - case "requirements": - subcommand := activeCommand.Active - switch subcommand.Name { - case "add": - cfg.Requirement.Template = defaultNewRequirementTemplate - - case "print": - if len(arguments.Requirements.Print.Columns) > 0 { - cfg.Table.Columns = validateColumns(arguments.Requirements.Print.Columns) - } - } - } - - return p.Command.Active, arguments, &cfg -} - -func convertTemplateLogo(content string, absolute string) string { - todoRegEx := regexp.MustCompile(`(?m)^(?P<match>logo:\s*"?(?P<path>[^"\n]*)"?\s*)$`) - - matches := todoRegEx.FindAllStringSubmatch(content, -1) - if matches == nil { - return content - } - - for _, match := range matches { - result := make(map[string]string) - for i, name := range todoRegEx.SubexpNames() { - if i != 0 && name != "" { - result[name] = match[i] - } - } - - if filepath.IsAbs(result["path"]) { - continue - } - - path := path.Clean(absolute + "/" + result["path"]) - content = strings.Replace(content, result["match"], "logo: \""+path+"\"", -1) - - } - - return content -} -func convertTemplateLatexLogo(content string, absolute string) string { - todoRegEx := regexp.MustCompile(`(?m)(?P<match>\\includegraphics[^{]*\{(?P<path>[^}]*)\})`) - - matches := todoRegEx.FindAllStringSubmatch(content, -1) - if matches == nil { - return content - } - - for _, match := range matches { - result := make(map[string]string) - for i, name := range todoRegEx.SubexpNames() { - if i != 0 && name != "" { - result[name] = match[i] - } - } - - if filepath.IsAbs(result["path"]) { - continue - } - - path := path.Clean(absolute + "/" + result["path"]) - a := strings.Replace(result["match"], result["path"], path, -1) - - content = strings.Replace(content, result["match"], a, -1) - - } - - return content -} - -func convertTemplateImages(content string, absolute string) string { - content = convertTemplateLogo(content, absolute) - content = convertTemplateLatexLogo(content, absolute) - - return content - -} - -func validateColumns(columns []string) []string { - - //for i, column := range columns { - // columns[i] = printer.Sprintf(column) - //} - - // VALIDATE COLUMS NAME - - // - //for _, name := range config.Requirements.Columns { - // - // field := reflect.Indirect(r).FieldByName(name) - // if field == (reflect.Value{}) { - // printError("the specified column " + name + " for the table does not exist") - // continue - - // } - - return columns - + return &cfg } func readFile(cfg *Configuration, filename string) { diff --git a/application/source/defaults.go b/application/source/defaults.go index e88fb778d0009863cbe080c4487b65e69e4fafb2..be57e322e3518f778e4b18c18621682c20907260 100644 --- a/application/source/defaults.go +++ b/application/source/defaults.go @@ -6,58 +6,206 @@ const exitOK = 0 const exitCodeCatchAll = 1 // Invalid argument to exit -const exitCodeInvalidArgument = 128 +// const exitCodeInvalidArgument = 128 const defaultOverviewTemplate = ` ---- -titlepage: false -... +{{ if .HasChangelog }} +## Changelog + +{{.Changelog}} +{{ end}}{{ if .HasPrivacy }} +## Privacy + +{{.Privacy}} + +{{ end}}{{ if .HasMeta }} ## Overview {{.Meta}} +{{ end}}{{ if .HasTasks }} ## Tasks {{.Tasks}} +{{ end}}{{ if .HasItems }} ## Items {{.Items}} +{{ end}}{{ if .HasRequirements }} ## Requirements {{.Requirements}} +{{ end}} + + ` // const defaultNewRequirementTemplate = ` --- ID: {{ .ID }} -title: -subtitle: -tags: [] -percent: +Title: null + +# Reference to other requirements +References: null + +# Display, Functional, Performance, Printing, Report, Testing or Validation +Type: null + +Alias: null + +Keywords: + - Requirement + +# First and last name of the authors as a list +Author: + - null + +# Proposed (The requirement has been requested by an authorized source.), +# In Progress (A business analyst is actively working on crafting the requirement.), +# Drafted (The initial version of the requirement has been written.), +# Approved (The requirement has been analyzed, its impact on the project has been estimated, and it has been allocated to the baseline for a specific release. ), +# Implemented (The code that implements the requirement has been designed, written, and unit tested. The requirement has been traced to the pertinent design and code elements. It’s now ready for review or other verification.), +# Verified (The requirement has satisfied its acceptance criteria, meaning that the correct functioning of the implemented requirement has been confirmed.), +# Deferred (An approved requirement is now planned for implementation in a later release.), +# Deleted (An approved requirement has been removed from the baseline.) or +# Rejected (The requirement was proposed but was never approved and is not planned for implementation in any upcoming release.) +Status: "Proposed" + +# Low, Medium, Hi +Complexity: null +# Low, Medium, Hi +Difficulty: null +# Nice to have, Low, Medium, Hi or Blocker +Priority: null +Version: 0.0.1 +Milestone: null + +# 0 (means that a task has already been completed), 1 (is a very small task), 2, 3, 5 (are rather smaller tasks), +# 8, 13, 20, 40, 100 Estimation: -items: - - - Group: - ID: - Name: - Description: - Delivery until: - Provided by: - Provided on: - Type: + +# The time required for this requirement +# Valid time units are “ns”, “us” (or “µs”), “ms”, “s”, “m”, “h”. +TimeSpent: + +# who is the source of the demand +Source: null +Created: {{ .Created.Format "2006-02-01" }} +Last Update: null + +# the individual items as a list +Items: + - ID: null + Name: null + # what is it, a image, font, legal information, access data, texts, decisions, ... + Type: null + # does this belong to a group + Group: null + Description: null + Delivery until: null + # when was the project items delivered and by whom? + Provided on: null + Provided by: null + +# https://gdpr-info.eu/art-30-gdpr/ +Privacy: + - ID: null + + # Purpose of the data processing, + # for example, shipping an order and handing it over to a shipping service provider. + Purposes: null + + # More detailed description of the reason and process of data processing. + Description: null + + # Who is responsible for data protection + Contact: null + + # But working with these categories might end up being a bad idea since doing so might + # mean packing different things into one. This leads to either oversimplifications or + # a lot of specifications within a category. It might be advisable to split some of them + # up or to add additional ones to make them fit your business reality. + # Examples: Employees, Suppliers, Customers, Job applicants, Consultants, Visitors, Prospects, Contractors, Trainees + Affected Groups: null + + # + Category: + + # Example: 5 years from the payment of the salary + Data Retention Period: null + + # On what legal basis is the data collected + # Special legal regulation outside the GDPR + # Consent of the data subject (Art. 6 para. 1 a) DSG-VO) use Consent field + # Collective agreement (e.g. company agreement, collective agreement) + # Establishment, performance or termination of an employment relationship (nationally regulated in the BDSG) + # Contract or initiation of a contract with the data subject (Art. 6 para. 1 b) DSG-VO.) + # Balancing of interests (Art. 6 para. 1 f) DSG-VO): Please name the overriding interests + Legal Basis: null + + # “Consent” of the data subject refers to any freely given specific, informed and unambiguous indication of his or + # her wishes in the form of a statement or other unambiguous affirmative act by which the data subject signifies + # his or her agreement to personal data relating to him or her being processed. + Consent: null + + # Where applicable, transfers of personal data to a third country or an international organisation, including + # the identification of that third country or international organisation and, in the case of transfers referred + # to in the second subparagraph of Article 49(1), the documentation of suitable safeguards; + Transfers: + + # Where possible, a general description of the technical and organisational + # security measures referred to in Article 32(1). + TOM: null + ... -## Headline +### {{ .ID }} {{ .Title }} -### Subheading +#### Subheading - [ ] task 1 - [ ] task 2 + +{{ if .hasItems }} +**Items** + +| ID | Name | Delivery until | Provided on | +|--------------------|--------------|----------------------:|-----------------------------------------:| +{{ range .Items + }}| {{ .ID }} | {{ .Name }} | {{ .DeliveryUntil.Format "02.Jan" }} | {{ .ProvidedOn.Format "02.Jan" }} | +{{ end }} + +{{ end }} + + +{{ if .Privacy }} +#### Privacy + +{{ range .Privacy }} +**{{ .Purpose }} ({{ .ID }})** + +{{ .Description }} + +| | | +|--|--| +| Category | {{ .Category }} | +| Data Retention Period | {{ .DataRetentionPeriod }} | +| Legal Basis | {{ .LegalBasis }} | +| Transfers | {{ .Transfers }} | +{{ end }} + +{{ end }} + + + + + + ` diff --git a/application/source/files.go b/application/source/files.go index 073fe9bb9e9a39561b3085d3b2c0fdeaf3fd05b1..9e6213f05c7d87ad3d195ebb73e6a868845c9cad 100644 --- a/application/source/files.go +++ b/application/source/files.go @@ -1,18 +1,14 @@ package main import ( - "errors" "io/ioutil" "os" "path" "path/filepath" - "strings" - - "gopkg.in/yaml.v3" ) // -func GetPageData(directory string) (error, map[string]requirement) { +func collectStructureFromFiles(directory string) (error, map[string]requirement) { cleanedDirectory := path.Clean(directory) @@ -43,10 +39,10 @@ func GetPageData(directory string) (error, map[string]requirement) { return err } - err, p := importData(content) + err, p := splitYamlParts(content) if err != nil { - printError("does not contain a valid yaml definition", cleanedPath) + printWarning("the file contains structural errors. check the YAML and if necessary the template.", cleanedPath, err) return nil } @@ -54,46 +50,16 @@ func GetPageData(directory string) (error, map[string]requirement) { bp := []byte(cleanedPath) bs := string(bp[len(bd):len(bp)]) - p.File = "." + bs - p.Absolute = cleanedPath - p.ToDos = findTask(content) - //requirement[cleanedPath] = requirement + p.data.File = "." + bs + p.data.Absolute = cleanedPath + p.data.ToDos = findTask(content) k := cleanedPath - pageMap[k] = p + pageMap[k] = p.data return nil }) return err, pageMap } - -func importData(content []byte) (error, requirement) { - - data := requirement{} - - s := string(content) - a := strings.Index(s, "\n---") - if a == -1 { - return errors.New("the file does not contain a definition block"), requirement{} - } - s = s[a+4 : len(s)-1] - b := strings.Index(s, "\n...") - - if b == -1 { - b = strings.Index(s, "\n---") - } - - if b > -1 { - s = s[0:b] - } - - err := yaml.Unmarshal([]byte(s), &data) - - if err != nil { - return err, requirement{} - } - - return nil, data -} diff --git a/application/source/go.mod b/application/source/go.mod index 2c19d654f33e4ceab288cc0b9e414a4180e58def..bd325504785f6ca008b43f5cbeba9f00bd5fb340 100644 --- a/application/source/go.mod +++ b/application/source/go.mod @@ -6,18 +6,16 @@ require ( github.com/gookit/color v1.5.0 github.com/jessevdk/go-flags v1.5.0 github.com/olekukonko/tablewriter v0.0.5 - go.uber.org/zap v1.21.0 golang.org/x/text v0.3.7 + gopkg.in/yaml.v2 v2.2.8 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b ) require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/kr/pretty v0.1.0 // indirect github.com/mattn/go-runewidth v0.0.9 // indirect github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect - go.uber.org/atomic v1.9.0 // indirect - go.uber.org/multierr v1.8.0 // indirect - golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 // indirect - golang.org/x/tools v0.1.10 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect + gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect ) diff --git a/application/source/go.sum b/application/source/go.sum index a888c8dfe1b17ed9342bbc319b9f486391a9427d..7be91803fe864a956a0b1b357f6eebe3c9ef3525 100644 --- a/application/source/go.sum +++ b/application/source/go.sum @@ -1,5 +1,3 @@ -github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -16,64 +14,19 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= -github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE= -go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= -go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8= -go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak= -go.uber.org/zap v1.21.0 h1:WefMeulhovoZ2sYXz7st6K0sLj7bBhpiFaud4r4zST8= -go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= -golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007 h1:gG67DSER+11cZvqIMb8S8bt0vZtiN6xWYARwirrOSfE= -golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886 h1:eJv7u3ksNXoLbGSKuv2s/SIO4tJVxc/A+MTpzxDgz/Q= golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.10 h1:QjFRCZxdOhBJ/UNgnBZLbNV13DlbnK0quyivTnXJM20= -golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/application/source/items.go b/application/source/items.go index 7dd0ff6a4ac210068ddd3052c4b96be55b72125c..5213f22f33c9453676e4ec071eb3259e602f1131 100644 --- a/application/source/items.go +++ b/application/source/items.go @@ -19,9 +19,10 @@ type Item struct { ProvidedBy string `yaml:"Provided by"` } -func buildItemOverviewTable(config *Configuration, pageMap map[string]requirement, extended bool) (error, string) { +func buildItemOverviewTable(config *Configuration, pageMap map[string]requirement, extended bool) (error, string, bool) { buf := new(bytes.Buffer) + has := false table := tablewriter.NewWriter(buf) @@ -91,35 +92,8 @@ func buildItemOverviewTable(config *Configuration, pageMap map[string]requiremen id = info.ID } - //text := info.Description + ", " - //text += printer.Sprintf("Group") + ": " + info.Group + ", " - //text += printer.Sprintf("File") + ": " + requirement.File - var col []string - /* - header = []string{ - printer.Sprintf("ID"), - printer.Sprintf("Name"), - printer.Sprintf("Delivery until"), - printer.Sprintf("Checked"), - } - } else { - header = []string{ - printer.Sprintf("ID"), - printer.Sprintf("Group"), - printer.Sprintf("Name"), - printer.Sprintf("Type"), - printer.Sprintf("Description"), - printer.Sprintf("RequirementID"), - printer.Sprintf("Delivery until"), - printer.Sprintf("Checked"), - printer.Sprintf("Provided on"), - printer.Sprintf("Provided by"), - } - - */ - if extended { col = []string{id, info.Group, info.Name, info.Type, info.Description, deliveryUntilFormatted, checked, providedOnDate, info.ProvidedBy, pageData.File} } else { @@ -127,7 +101,8 @@ func buildItemOverviewTable(config *Configuration, pageMap map[string]requiremen } tableData = append(tableData, col) - //tableData = append(tableData, []string{text, deliveryUntilFormatted, checked, info.ProvidedBy}) + has = true + } } @@ -136,16 +111,16 @@ func buildItemOverviewTable(config *Configuration, pageMap map[string]requiremen table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) table.Render() - return nil, buf.String() + return nil, buf.String(), has } func printItemTable(config *Configuration) error { - err, pageMap := GetPageData(config.Path) + err, pageMap := collectStructureFromFiles(config.Path) if err != nil { return err } - err, table := buildItemOverviewTable(config, pageMap, true) + err, table, _ := buildItemOverviewTable(config, pageMap, true) fmt.Println(table) return nil diff --git a/application/source/l10n.go b/application/source/l10n.go index 7bdcc26586f761ab21033b4a542b12876576fab0..cce6829522a7210ea9e98c7b5c1a4b9f8b730e5f 100644 --- a/application/source/l10n.go +++ b/application/source/l10n.go @@ -26,7 +26,7 @@ var l10nMap = []l10nKeyTranslation{ { "the specified template", []l10nLocaleTranslation{ - {"de", "Das angegebene Template \"%s\" wurde nicht gefunden."}, + {"de", "Das angegebene AddTemplate \"%s\" wurde nicht gefunden."}, {"en", "the specified template \"%s\" was not found."}, }, }, @@ -252,13 +252,48 @@ var l10nMap = []l10nKeyTranslation{ {"de", "Die ID muss angegeben werden"}, {"en", "the id must not be empty"}, }, - }, { + }, + { "the request with id already exists", []l10nLocaleTranslation{ {"de", "Die Anforderung mit der ID %s existiert bereits (%s)."}, {"en", "the request with id %s already exists (%s)."}, }, }, + { + "YAML parse error", + []l10nLocaleTranslation{ + {"de", "YAML Fehler: %s "}, + {"en", "YAML parse error: %s ."}, + }, + }, + { + "if the type is pdf, the output option must be specified", + []l10nLocaleTranslation{ + {"de", "Der Tpy PDF benötigt die Option --output"}, + {"en", "if the type is pdf, the output option must be specified"}, + }, + }, + { + "Unknown Error", + []l10nLocaleTranslation{ + {"de", "Unbekannter Fehler: %s"}, + {"en", "Unknown Error %s"}, + }, + }, + { + "the file contains structural errors. check the YAML and if necessary the template.", + []l10nLocaleTranslation{ + {"de", "Die Datei %s enthält strukturelle Fehler (%s). Überprüfen Sie die Datei."}, + {"en", "the file %s contains structural errors (%s). Check the if necessary the file."}, + }, + }, { + "the file is empty", + []l10nLocaleTranslation{ + {"de", "Die Datei enthält keinen Inhalt."}, + {"en", "the file is empty."}, + }, + }, } func initL10n() { diff --git a/application/source/main.go b/application/source/main.go index 16d1ece5ecbea05e85c94bae34ce4a1866f02f2d..039971fa1eb0f8dbc1593dcf20017eb373fa3010 100644 --- a/application/source/main.go +++ b/application/source/main.go @@ -1,6 +1,7 @@ package main import ( + //"crypto/tls" "os" "golang.org/x/text/language" @@ -38,24 +39,8 @@ func init() { printer = message.NewPrinter(tag) initL10n() - // - //p := message.NewPrinter(language.English) - //p.Printf("archive(noun)") // Prints "archive" - //p.Printf("archive(verb)") // Prints "archive" - - // p2 := message.NewPrinter(language.German) - //fmt.Println(printer.Sprintf("Due")) // Prints "Archiv" - // p2.Printf("archive(verb)") // Prints "archivieren" - //initLogger() -} -//func initLogger() { -// logger, _ := zap.NewDevelopment() -// defer logger.Sync() // flushes buffer, if any -// -// sugar = logger.Sugar() -// sugar.Infow("failed to fetch URL") -//} +} func initEnvironment() { } diff --git a/application/source/message.go b/application/source/message.go index f9ecdfc63ed7c856551bb63d68a6f63a2304934a..a57a9bd715cf6c86a6342a060355a9e02814806e 100644 --- a/application/source/message.go +++ b/application/source/message.go @@ -29,3 +29,16 @@ func printError(message string, a ...interface{}) { color.Error.Block(message) } + +func printWarning(message string, a ...interface{}) { + + message = printer.Sprintf(message, a...) + + if lastBlock == "warning" { + color.Warn.Println(" " + message) + return + } + lastBlock = "warning" + + color.Warn.Block(message) +} diff --git a/application/source/overview.go b/application/source/overview.go index a91be6437776fce29ec6b28318f66ba9e978cc7b..801e45b5719c53765a6fbf5b4879bb8c35bc0fc9 100644 --- a/application/source/overview.go +++ b/application/source/overview.go @@ -1,7 +1,6 @@ package main import ( - "html/template" "io/ioutil" "os" "path" @@ -9,42 +8,61 @@ import ( "regexp" "sort" "strings" + "text/template" "time" ) type Dataset struct { - Config *Configuration - Meta string - Tasks string - Items string - Requirements string - Created time.Time - CreatedFormat string + Config *Configuration + Meta string + HasChangelog bool + Changelog string + HasPrivacy bool + Privacy string + HasMeta bool + Tasks string + HasTasks bool + Items string + HasItems bool + Requirements string + HasRequirements bool + Created time.Time + CreatedFormat string } func PrintOverview(config *Configuration, arguments *commandLineOptions) error { - err, pageData := GetPageData(config.Path) + err, pageData := collectStructureFromFiles(config.Path) if err != nil { return err } - err, meta := buildRequirements(config, pageData) + err, meta, hasMeta := buildRequirements(config, pageData) if err != nil { return err } - err, tasks := buildTasksTable(config, pageData, false) + err, changelog, hasChangelog := buildChangelog(config, pageData) if err != nil { return err } - err, items := buildItemOverviewTable(config, pageData, false) + err, privacy, hasPrivacy := buildPrivacy(config, pageData) if err != nil { return err } - t, err := template.New("overview").Parse(config.Overview.Template) + err, tasks, hasTasks := buildTasksTable(config, pageData, false) + if err != nil { + return err + } + + err, items, hasItems := buildItemOverviewTable(config, pageData, false) + if err != nil { + return err + } + + t, err := template.New("overview").Parse(config.Overview.Template.Internal.MarkdownContent) if err != nil { return err } @@ -58,32 +76,47 @@ func PrintOverview(config *Configuration, arguments *commandLineOptions) error { sort.Strings(keys) + hasRequirements := false for _, k := range keys { + hasRequirements = true p := pageData[k] requirements = requirements + getAdjustedContent(p.Absolute) } d := new(Dataset) + + d.Changelog = changelog + d.HasChangelog = hasChangelog + + d.Privacy = privacy + d.HasPrivacy = hasPrivacy + d.Meta = meta + d.HasMeta = hasMeta + d.Tasks = tasks - d.Config = config + d.HasTasks = hasTasks + d.Items = items + d.HasItems = hasItems + d.Requirements = requirements + d.HasRequirements = hasRequirements + + d.Config = config d.Created = time.Now() d.CreatedFormat = time.Now().Format(config.Locale.DateFormat) //d.requirement = requirement - if arguments.Overview.Print.Output == "" { - err = t.Execute(os.Stdout, d) - if err != nil { - return err - } - } - outputName := arguments.Overview.Print.Output if arguments.Overview.Print.Format == "pdf" { - file, err := ioutil.TempFile(os.TempDir(), "prefix") + + if outputName == "" { + printErrorAndExit(2, "if the type is pdf, the output option must be specified") + } + + file, err := ioutil.TempFile(os.TempDir(), "reqman") if err != nil { printErrorAndExit(2, "A temporary file cannot be created", err.Error()) } @@ -94,25 +127,34 @@ func PrintOverview(config *Configuration, arguments *commandLineOptions) error { return err } - convertToPDF(file.Name(), outputName) + convertToPDF(file.Name(), outputName, config.Overview.Template.Latex) } else { - file, err := os.Create(outputName) - if err != nil { - printErrorAndExit(2, "The output file cannot be written", err.Error()) - } - - // close fo on exit and check for its returned error - defer func() { - if err := file.Close(); err != nil { + if outputName != "" { + file, err := os.Create(outputName) + if err != nil { printErrorAndExit(2, "The output file cannot be written", err.Error()) } - }() - err = t.Execute(file, d) - if err != nil { - return err + // close fo on exit and check for its returned error + defer func() { + if err := file.Close(); err != nil { + printErrorAndExit(2, "The output file cannot be written", err.Error()) + } + }() + + err = t.Execute(file, d) + if err != nil { + return err + } + + } else { + + err = t.Execute(os.Stdout, d) + if err != nil { + return err + } } } @@ -129,24 +171,13 @@ func getAdjustedContent(absolute string) string { return "" } - s := string(content) - a := strings.Index(s, "\n---") - if a == -1 { - return s - } - - s = s[a+4 : len(s)-1] - b := strings.Index(s, "\n...") - - if b == -1 { - b = strings.Index(s, "\n---") - } - - if b > -1 { - s = s[b+4 : len(s)-1] + err, def := splitYamlParts(content) + if err != nil { + printError(err.Error()) + return "" } - s = convertImages(s, path.Dir(absolute)) + s := convertImages(def.content, path.Dir(absolute)) return s } @@ -179,3 +210,91 @@ func convertImages(content string, absolute string) string { return content } + +func convertTemplateLogo(content string, absolute string) string { + todoRegEx := regexp.MustCompile(`(?m)^(?P<match>logo:\s*"?(?P<path>[^"\n]*)"?\s*)$`) + + matches := todoRegEx.FindAllStringSubmatch(content, -1) + if matches == nil { + return content + } + + for _, match := range matches { + result := make(map[string]string) + for i, name := range todoRegEx.SubexpNames() { + if i != 0 && name != "" { + result[name] = match[i] + } + } + + if filepath.IsAbs(result["path"]) { + continue + } + + path := path.Clean(absolute + "/" + result["path"]) + content = strings.Replace(content, result["match"], "logo: \""+path+"\"", -1) + + } + + return content +} + +func convertTemplateLatexLogo(content string, absolute string) string { + todoRegEx := regexp.MustCompile(`(?m)(?P<match>\\includegraphics[^{]*\{(?P<path>[^}]*)\})`) + + matches := todoRegEx.FindAllStringSubmatch(content, -1) + if matches == nil { + return content + } + + for _, match := range matches { + result := make(map[string]string) + for i, name := range todoRegEx.SubexpNames() { + if i != 0 && name != "" { + result[name] = match[i] + } + } + + if filepath.IsAbs(result["path"]) { + continue + } + + path := path.Clean(absolute + "/" + result["path"]) + a := strings.Replace(result["match"], result["path"], path, -1) + + content = strings.Replace(content, result["match"], a, -1) + + } + + return content +} + +func convertTemplateImages(content string, absolute string) string { + content = convertTemplateLogo(content, absolute) + content = convertTemplateLatexLogo(content, absolute) + + return content + +} + +func validateColumns(columns []string) []string { + + //for i, column := range columns { + // columns[i] = printer.Sprintf(column) + //} + + // VALIDATE COLUMS NAME + + // + //for _, name := range config.Requirements.Columns { + // + // field := reflect.Indirect(r).FieldByName(name) + // if field == (reflect.Value{}) { + // printError("the specified column " + name + " for the table does not exist") + // continue + + // } + + return columns + +} diff --git a/application/source/pandoc.go b/application/source/pandoc.go index 192f6e43a995fc06b61c8d71e8946325d40fa5fb..95ebac5f3bf8f5195fa71b7b7eb78a9dc122a456 100644 --- a/application/source/pandoc.go +++ b/application/source/pandoc.go @@ -5,7 +5,7 @@ import ( "os/exec" ) -func convertToPDF(source string, output string) string { +func convertToPDF(source string, outputName string, latexPath string) string { arguments := "/bin/env pandoc " @@ -16,15 +16,27 @@ func convertToPDF(source string, output string) string { arguments += source + " " arguments += "--pdf-engine=xelatex " arguments += "--listings " - arguments += "--template /home/volker.schukai/Downloads/eisvogel/eisvogel.latex " + + if latexPath != "" { + arguments += "--template=" + latexPath + " " + } + arguments += "--columns=5 " arguments += "--highlight-style espresso " arguments += "--toc " - arguments += "--output=" + output + arguments += "--output=" + outputName + " " cmd, err := exec.Command("bash", "-c", arguments).Output() if err != nil { - printErrorAndExit(2, err.Error()) + + exitErr, ok := err.(*exec.ExitError) + if ok { + printErrorAndExit(2, string(exitErr.Stderr)) + + } else { + printErrorAndExit(2, err.Error()) + } + } fmt.Println(string(cmd)) diff --git a/application/source/privacy.go b/application/source/privacy.go new file mode 100644 index 0000000000000000000000000000000000000000..ae9742915ad68a066cd7fd03ba18549949050a73 --- /dev/null +++ b/application/source/privacy.go @@ -0,0 +1,95 @@ +package main + +import ( + "fmt" + "strings" +) + +type Privacy struct { + ID string `yaml:"ID"` + Purposes string `yaml:"Purposes"` + Description string `yaml:"Description"` + Contact string `yaml:"Contact"` + AffectedGroups string `yaml:"Affected Groups"` // Employees, Suppliers, Customers, Job applicants, Consultants, Visitors, Prospects, Contractors, Trainees + Category string `yaml:"Category"` + DataRetentionPeriod string `yaml:"Data Retention Period"` + LegalBasis string `yaml:"Legal Basis"` + Consent string `yaml:"Consent"` + Transfers string `yaml:"Transfers"` + TOM string `yaml:"TOM"` +} + +func buildPrivacy(config *Configuration, pageMap map[string]requirement) (error, string, bool) { + + hasPrivacy := false + text := "" + + for _, pageData := range pageMap { + for _, data := range pageData.Privacy { + + text += strings.Trim(data.Purposes+" ("+data.ID+")", " ") + "\n\n" + + d := strings.Trim(data.Description, " \n") + if d != "" { + text += d + "\n\n" + } + + d = strings.Trim(data.Contact, " \n") + if d != "" { + text += d + "\n\n" + } + + d = strings.Trim(data.AffectedGroups, " \n") + if d != "" { + text += d + "\n\n" + } + + d = strings.Trim(data.Category, " \n") + if d != "" { + text += d + "\n\n" + } + + d = strings.Trim(data.DataRetentionPeriod, " \n") + if d != "" { + text += d + "\n\n" + } + + d = strings.Trim(data.LegalBasis, " \n") + if d != "" { + text += d + "\n\n" + } + + d = strings.Trim(data.Consent, " \n") + if d != "" { + text += d + "\n\n" + } + + d = strings.Trim(data.Transfers, " \n") + if d != "" { + text += d + "\n\n" + } + + d = strings.Trim(data.TOM, " \n") + if d != "" { + text += d + "\n\n" + } + + hasPrivacy = true + } + } + + return nil, text, hasPrivacy + +} + +func printPrivacy(config *Configuration) error { + + err, pageData := collectStructureFromFiles(config.Path) + if err != nil { + return err + } + + err, data, _ := buildPrivacy(config, pageData) + fmt.Println(data) + return err +} diff --git a/application/source/requirements.go b/application/source/requirements.go index 2667ffd89005bd9fed585c25094447ae12c4e798..de89a4c4bdc0c77fc866c36c12fc0e66c792f084 100644 --- a/application/source/requirements.go +++ b/application/source/requirements.go @@ -16,7 +16,8 @@ type requirement struct { ToDos []task Absolute string File string - Items []Item `yaml:"items"` + Items []Item `yaml:"Items"` + Privacy []Privacy `yaml:"Privacy"` ID string `yaml:"ID"` References []string `yaml:"References"` @@ -24,7 +25,7 @@ type requirement struct { Title string `yaml:"Title"` Alias []string `yaml:"Alias"` Keywords []string `yaml:"Keywords"` - Author string `yaml:"Author"` + Author []string `yaml:"Author"` Status string `yaml:"Status"` Complexity string `yaml:"Complexity"` Difficulty string `yaml:"Difficulty"` // Low, Medium, High @@ -32,15 +33,12 @@ type requirement struct { Version string `yaml:"Version"` Milestone string `yaml:"Milestone"` Estimation int `yaml:"Estimation"` // 0, 1, 2, 3, 5, 8, 13, 20, 40, 100 + TimeSpent string `yaml:"TimeSpent"` // 3h2m20s Source string `yaml:"Source"` Created time.Time `yaml:"Created"` LastUpdate time.Time `yaml:"Last Update"` } -type addRequirementDataset struct { - ID string -} - func addRequirement(config *Configuration, arguments *commandLineOptions) error { if arguments.Requirements.Add.ID == "" { @@ -52,12 +50,12 @@ func addRequirement(config *Configuration, arguments *commandLineOptions) error printErrorAndExit(2, "the request with id already exists", arguments.Requirements.Add.ID, p) } - t, err := template.New("requirement").Parse(config.Requirement.Template) + t, err := template.New("requirement").Parse(config.Requirement.Template.Add) if err != nil { return err } - d := new(addRequirementDataset) + d := requirement{} d.ID = arguments.Requirements.Add.ID f, err := os.Create(p) @@ -87,13 +85,15 @@ func translateRequirementHeaders(columns []string) []string { } -func buildRequirements(config *Configuration, pageMap map[string]requirement) (error, string) { +func buildRequirements(config *Configuration, pageMap map[string]requirement) (error, string, bool) { buf := new(bytes.Buffer) + hasRequirements := false + table := tablewriter.NewWriter(buf) - translateMetaColumns := translateRequirementHeaders(config.Table.Columns) + translateMetaColumns := translateRequirementHeaders(config.Requirement.Table.Columns) table.SetHeader(translateMetaColumns) table.SetBorders(tablewriter.Border{Left: true, Top: false, Right: true, Bottom: false}) @@ -107,7 +107,7 @@ func buildRequirements(config *Configuration, pageMap map[string]requirement) (e var row []string found := false - for _, name := range config.Table.Columns { + for _, name := range config.Requirement.Table.Columns { field := reflect.Indirect(r).FieldByName(name) if field == (reflect.Value{}) { @@ -154,6 +154,7 @@ func buildRequirements(config *Configuration, pageMap map[string]requirement) (e if found { tableData = append(tableData, row) + hasRequirements = true } } @@ -162,17 +163,17 @@ func buildRequirements(config *Configuration, pageMap map[string]requirement) (e table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) table.Render() - return nil, buf.String() + return nil, buf.String(), hasRequirements } func printRequirements(config *Configuration) error { - err, pageData := GetPageData(config.Path) + err, pageData := collectStructureFromFiles(config.Path) if err != nil { return err } - err, table := buildRequirements(config, pageData) + err, table, _ := buildRequirements(config, pageData) fmt.Println(table) return err } diff --git a/application/source/tasks.go b/application/source/tasks.go index 09e662eb1537525550cd4707884a97c24893bfcb..a7a87037cceef78f81250d72f3be4167d1ea92d8 100644 --- a/application/source/tasks.go +++ b/application/source/tasks.go @@ -72,11 +72,12 @@ func findTask(content []byte) []task { return toDos } -func buildTasksTable(config *Configuration, pageMap map[string]requirement, extended bool) (error, string) { +func buildTasksTable(config *Configuration, pageMap map[string]requirement, extended bool) (error, string, bool) { buf := new(bytes.Buffer) table := tablewriter.NewWriter(buf) + has := false header := []string{ printer.Sprintf("ToDo"), @@ -96,6 +97,8 @@ func buildTasksTable(config *Configuration, pageMap map[string]requirement, exte for _, pageData := range pageMap { for _, info := range pageData.ToDos { + has = true + var d string if info.due.IsZero() { @@ -124,16 +127,16 @@ func buildTasksTable(config *Configuration, pageMap map[string]requirement, exte table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) table.Render() - return nil, buf.String() + return nil, buf.String(), has } func printTaskTable(config *Configuration) error { - err, pageData := GetPageData(config.Path) + err, pageData := collectStructureFromFiles(config.Path) if err != nil { return err } - err, table := buildTasksTable(config, pageData, true) + err, table, _ := buildTasksTable(config, pageData, true) fmt.Println(table) return nil diff --git a/application/source/util.go b/application/source/util.go new file mode 100644 index 0000000000000000000000000000000000000000..db20f614840e3a320856ffc2521a612051ef00c3 --- /dev/null +++ b/application/source/util.go @@ -0,0 +1,86 @@ +package main + +import ( + "bytes" + "errors" + "strings" + "text/template" + + "gopkg.in/yaml.v3" +) + +type contentRequirement struct { + content string + data requirement +} + +func splitYamlParts(content []byte) (error, contentRequirement) { + + origin := string(content) + + meta := "" + text := "" + + before, remaining, found := strings.Cut(origin, "---") + if !found { + + t := strings.TrimSpace(origin) + if len(t) == 0 { + return errors.New("the file is empty"), contentRequirement{ + content: origin, + data: requirement{}, + } + } + + return errors.New("the file does not contain a definition block"), contentRequirement{ + content: origin, + data: requirement{}, + } + } + + text += before + + a, b, found := strings.Cut(remaining, "...") + if !found { + a, b, found = strings.Cut(remaining, "---") + + if !found { + return errors.New("the file does not contain a definition block"), contentRequirement{} + } + + } + + meta = a + text += b + + t, err := template.New("overview").Parse(text) + if err != nil { + return err, contentRequirement{} + } + + data := requirement{} + err = yaml.Unmarshal([]byte(meta), &data) + if err != nil { + printError("YAML parse error", err.Error()) + return err, contentRequirement{} + } + + for i, _ := range data.Items { + data.Items[i].ID = data.ID + "-" + data.Items[i].ID + } + + req := contentRequirement{} + req.data = data + + var buffer bytes.Buffer + err = t.Execute(&buffer, data) + if err != nil { + printError(err.Error()) + return err, contentRequirement{} + } + + req.content = buffer.String() + + return nil, req + +} diff --git a/application/web/index.html b/application/web/index.html new file mode 100644 index 0000000000000000000000000000000000000000..21c134375f672490e78972602a3c1b4be26931f4 --- /dev/null +++ b/application/web/index.html @@ -0,0 +1,82 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" + integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> + + <style> + + body { + background-color: #ffffff; + } + + </style> + <title>Download Portal schukai GmbH</title> +</head> +<body> + + +<div class="d-flex flex-column align-items-center justify-content-center" + style="height:100vh;"> + + <div class="text-center"> + <a href="https://www.schukai.com" class="text-decoration-none text-white text-decoration"><img + src="https://cdn.alvine.io/image/logo/schukai-rot.svg" width="300px"></a> + <br> + + <div class="card mt-5"> + <div class="card-header"> + ReqMan + </div> + <ul class="list-group"> + <li class="list-group-item"><a class="text-decoration-none link-danger" href="./reqman-linux-386">reqman-linux-386</a></li> + <li class="list-group-item"><a class="text-decoration-none link-danger" href="./reqman-linux-386">reqman-linux-amd64</a></li> + <li class="list-group-item"><a class="text-decoration-none link-danger" href="./reqman-linux-386">reqman-linux-arm</a></li> + <li class="list-group-item"><a class="text-decoration-none link-danger" href="./reqman-linux-386">reqman-linux-arm64</a></li> + <li class="list-group-item"><a class="text-decoration-none link-danger" href="./reqman-linux-386">reqman-windows</a></li> + </ul> + </div> + + <p class="mt-5"> + <a href="https://about.schukai.com/de/impressum/" class="text-decoration-none text-decoration" + style="color:#c10000">Imprint</a></p> + + </div> + + +</div> + + +<!-- +<div class="d-flex flex-column align-items-center justify-content-center" + style="height:100vh;"> + +<div class="d-block"> + +<div><img src="signet.svg" height="10%"></div> +<div> + +</div> +</div> +</div> + + + +<div class="text-center mb-2 fixed-bottom"> + <div class="row"> + <div class="col"> + + </div> + </div> +</div> --> + + +<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" + integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" + crossorigin="anonymous"></script> + +</body> +</html> diff --git a/deployment/scripts b/deployment/scripts new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/deployment/upload.sh b/deployment/upload.sh new file mode 100644 index 0000000000000000000000000000000000000000..2d62512b8f87c0c3008d7fdf1c5b53acba08f11f --- /dev/null +++ b/deployment/upload.sh @@ -0,0 +1,4 @@ +#!/bin/bash +# shellcheck shell=bash + +$(command -v aws) s3 ls --recursive s3://doc.alvine.io/de/ --region eu-central-1 > "$(THIS_DIR)s3-temp/inventory.txt" \ No newline at end of file diff --git a/development/examples/example1/144444.md b/development/examples/example1/144444.md deleted file mode 100644 index 82e9da34f420fa385c8ffc6f27f4afba5eafa84e..0000000000000000000000000000000000000000 --- a/development/examples/example1/144444.md +++ /dev/null @@ -1,28 +0,0 @@ - ---- -ID: 144444 -title: -subtitle: -tags: [] -percent: -Estimation: -items: - - - Group: - ID: - Name: - Description: - Delivery until: - Provided by: - Provided on: - Type: -... - -## - -### - - -- [ ] task 1 -- [ ] task 2 - diff --git a/development/examples/example1/req1/00-00-001-text.md b/development/examples/example1/req1/00-00-001-text.md new file mode 100644 index 0000000000000000000000000000000000000000..e1aef95ce28a25ba6c25ef445c5c4c3cfb46a145 --- /dev/null +++ b/development/examples/example1/req1/00-00-001-text.md @@ -0,0 +1,7 @@ +--- +ID: 1425 + +... + + +### !!{{ .ID }}!! \ No newline at end of file diff --git a/development/examples/example1/req1/001-1425.md b/development/examples/example1/req1/001-1425.md index 6d2e15ecc75778bb3aeb7a6be87f1f4970008c62..da3cd70c89739c75f2c6b24d46a528e6fc67491c 100644 --- a/development/examples/example1/req1/001-1425.md +++ b/development/examples/example1/req1/001-1425.md @@ -9,7 +9,7 @@ Version: 1.0 ID: 9999 ... -## Anforderung 1425 +### {{ .ID }} {{ .Title }} das ist ein test @@ -31,7 +31,7 @@ isn't indented. - [x ] 2020-12-03 das ist das erste todo 3 -### Headline 1 +#### Headline 1 HIER IST EIN BILD @@ -39,6 +39,6 @@ HIER IST EIN BILD Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -### Headline 2 +#### Headline 2 Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. diff --git a/development/examples/example1/req1/002.md b/development/examples/example1/req1/002.md index cc782b759dc5c9769b515803fd5d6c22266cafbb..4b587b0d0ec00c92c74f153b202ae08bb0635e7e 100644 --- a/development/examples/example1/req1/002.md +++ b/development/examples/example1/req1/002.md @@ -8,10 +8,11 @@ Title: My Name22 Created: 2022-02-21 Version: 2.2.2 ID: a1 +Last Update: 2022-04-01 --- -## Anforderung 1426-A1 +### {{ .ID }} {{ .Title }} Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. @@ -21,10 +22,10 @@ Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod - [ ] 2020-12-03 das ist das erste todo 3 sdfkjasdfk jasdkfjasd löfjasdklöfj asdkjfasdf jasdklf jasdfklöjasdfklöjasdklö -### Headline 1111 +#### Headline 1111 lorem in hendrerit in vulputate velit esse moles -### Headline 2222 +#### Headline 2222 Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. diff --git a/development/examples/example1/req1/002/002-01.md b/development/examples/example1/req1/002/002-01.md index fc8957c8268068965b1f30b5b30d0fe516c4c261..0a774e9e44187bc86ed817e130cdb9e2872ba136 100644 --- a/development/examples/example1/req1/002/002-01.md +++ b/development/examples/example1/req1/002/002-01.md @@ -1,30 +1,119 @@ - - - - --- Key1: Value1 Title: My Name -Created: 2022-02-21 +Created: 2022-02-24 Version: 2.0.2 ID: 23423 + +Items: + - + Group: A1 + ID: Beistellung1 + Name: Beistellung eines Bildes + Description: Großes Logo + Delivery until: 2022-12-12 + Provided by: Me + Provided on: 2022-12-01 + Type: Bild + - + ID: XXX + Group: Logo (klein) + Description: kleines Logo + +Privacy: + + - ID: P01 + + # Purpose of the data processing, + # for example, shipping an order and handing it over to a shipping service provider. + Purposes: Versand von Daten + + # More detailed description of the reason and process of data processing. + Description: null + + # Who is responsible for data protection + Contact: null + + # But working with these categories might end up being a bad idea since doing so might + # mean packing different things into one. This leads to either oversimplifications or + # a lot of specifications within a category. It might be advisable to split some of them + # up or to add additional ones to make them fit your business reality. + # Examples: Employees, Suppliers, Customers, Job applicants, Consultants, Visitors, Prospects, Contractors, Trainees + Affected Groups: null + + # + Category: Anschrift + + # Example: 5 years from the payment of the salary + Data Retention Period: null + + # On what legal basis is the data collected + # Special legal regulation outside the GDPR + # Consent of the data subject (Art. 6 para. 1 a) DSG-VO) use Consent field + # Collective agreement (e.g. company agreement, collective agreement) + # Establishment, performance or termination of an employment relationship (nationally regulated in the BDSG) + # Contract or initiation of a contract with the data subject (Art. 6 para. 1 b) DSG-VO.) + # Balancing of interests (Art. 6 para. 1 f) DSG-VO): Please name the overriding interests + Legal Basis: null + + # “Consent” of the data subject refers to any freely given specific, informed and unambiguous indication of his or + # her wishes in the form of a statement or other unambiguous affirmative act by which the data subject signifies + # his or her agreement to personal data relating to him or her being processed. + Consent: null + + # Where applicable, transfers of personal data to a third country or an international organisation, including + # the identification of that third country or international organisation and, in the case of transfers referred + # to in the second subparagraph of Article 49(1), the documentation of suitable safeguards; + Transfers: + + # Where possible, a general description of the technical and organisational + # security measures referred to in Article 32(1). + TOM: null + --- +### {{ .ID }} {{ .Title }} !?!?!?1------ -## Anforderung 1426 +#### Subheading -Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. +- [ ] task 1 +- [ ] task 2 +!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +{{ if .Items }} +**Items222** + +| ID | Name | Delivery until | Provided on | +|--------------------|--------------|----------------------:|-----------------------------------------:| +{{ range .Items +}}| {{ .ID }} | {{ .Name }} | {{ .DeliveryUntil.Format "02.Jan" }} | {{ .ProvidedOn.Format "02.Jan" }} | +{{ end }} + +{{ end }} + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore +magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd +gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing +elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et +accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit +amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et +dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd +gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. - [ ] 2020-12-01 das ist das erste todo 1 - [ ] 2020-12-02 das ist das erste todo 2 - [ ] 2020-12-03 das ist das erste todo 3 sdfkjasdfk jasdkfjasd löfjasdklöfj asdkjfasdf jasdklf jasdfklöjasdfklöjasdklö - -### Headline 1111 +#### Headline 1111 lorem in hendrerit in vulputate velit esse moles -### Headline 2222 +#### Headline 2222 -Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. +Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat +nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis +dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh +euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. diff --git a/development/examples/example1/req1/002/empty.md b/development/examples/example1/req1/002/empty.md new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/development/examples/example1/req1/002/noyaml.md b/development/examples/example1/req1/002/noyaml.md new file mode 100644 index 0000000000000000000000000000000000000000..5c42695b8b0e5564896cfe17b529d2156bd57b64 --- /dev/null +++ b/development/examples/example1/req1/002/noyaml.md @@ -0,0 +1,6 @@ + + + +## Das ist eine einfache Datei + +diese datei enhält keine YAML Struktur. \ No newline at end of file diff --git a/development/examples/example1/req999/999.md b/development/examples/example1/req999/999.md index 49abd91b9cbca57df6594a16c3b4803c66efd2ab..d737d689f46f0062230a7e0ab18e5a869d36c481 100644 --- a/development/examples/example1/req999/999.md +++ b/development/examples/example1/req999/999.md @@ -1,6 +1,3 @@ - - - --- ID: 22.5 title: Test 1 @@ -12,31 +9,17 @@ list: - entry 1 - entry 2 - entry 3 -items: - - - Group: A1 - ID: Beistellung1 - Name: Beistellung eines Bildes - Description: Großes Logo - Delivery until: 2022-12-12 - Provided by: Me - Provided on: 2022-12-01 - Type: Bild - - - - - Group: Logo (klein) - Description: kleines Logo + ... -## Anforderung test1 +### {{ .ID }} {{ .Title }} -### Headline 1XXXX +#### Headline 1XXXX Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. -### Headline 2XXX +#### Headline 2XXX Duis autem vel eum iriure dolor in hendrerit in vulputate velit esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. diff --git a/development/examples/overview.template b/development/examples/overview.template index 651360fcaa50410dd2db7b3bc09ea70549e21149..61054c5f8761343854d369583185f69012cb9797 100644 --- a/development/examples/overview.template +++ b/development/examples/overview.template @@ -36,24 +36,27 @@ Der Kunde wird, sofern die Leistungen nur mit Unterstützung Dritter erbracht we ## Management Summary - +{{ if .HasMeta }} ## Overview {{.Meta}} +{{ end}}{{ if .HasTasks }} ## Tasks {{.Tasks}} +{{ end}}{{ if .HasItems }} ## Items {{.Items}} +{{ end}}{{ if .HasRequirements }} ## Requirements {{.Requirements}} - +{{ end}} \newpage ## diff --git a/documentation/assets/.gitkeep b/documentation/assets/.gitkeep new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391