Skip to content

Commit

Permalink
Configuration file with comments (#18)
Browse files Browse the repository at this point in the history
* feature: generate configuration from templates

* test: jira config template test

* docs: Improve default-config documentation

* docs: header documentation on generated template

* test: metadata template test

* feat: add comment title in config

* refactor: use built in format instead of printf

* docs: remove sections already present in default config
  • Loading branch information
hielfx authored Oct 3, 2023
1 parent 00ce2d5 commit 2ad125b
Show file tree
Hide file tree
Showing 11 changed files with 257 additions and 65 deletions.
41 changes: 4 additions & 37 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,45 +51,12 @@ After installing this extension in your development environment, you can know th

## Configuration

Sherpa CLI can be configured using its own configuration file, stored in `$HOME/.config/sherpa/config.yml`.
Check the [`internal/config/default-config.yml`](internal/config/default-config.yml) file to see the available configuration parameters as well as the default values and some examples.
You can also find here the available GH Sherpa issue types. These values will be set if no other configuration override those values.

If no configuration file is found, the first time you run a command it will ask you to configure your Jira credentials (if you want to use Jira integration) and then proceed to create the configuration file.
In order to override the default values, you can use your own configuration file located in `$HOME/.config/sherpa/config.yml` for this.

Check the [`internal/config/default-config.yml`](internal/config/default-config.yml) file to see the available configuration parameters as well as the default values and some examples. This file should be the same as the one generated in your `$HOME/.config/sherpa/config.yml` file prior to any modification.

### Jira configuration

>NOTE: This configuration is only required if you want to use Jira integration.
| Parameter | Description | Default value |
| ------------------------------ | --------------------------------------------------- | ------------- |
| `jira.auth.host` | Jira host to connect to. | `""` |
| `jira.auth.token` | Jira already generated PAT | `""` |
| `jira.auth.skip_tls_verify` | Skip TLS verification for the given hos | `false` |
| `jira.issue_types.bugfix` | List of Jira issue type IDs related to bugfixes | `["1"]` |
| `jira.issue_types.feature` | List of Jira issue type IDs related to features | `["3", "5"]` |
| `jira.issue_types.improvement` | List of Jira issue type IDs related to improvements | `["4"]` |

>NOTE: You can get a list of the Jira issue type IDs making a request to `https://{your-jira-domain}/jira/rest/api/2/issuetype`. More information in the [Jira issue types REST API documentation](https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-types/#api-group-issue-types).
### GitHub configuration

| Parameter | Description | Default value |
| ----------------------------------- | --------------------------------------- | ------------------------ |
| `github.issue_labels` | Github issue labels related to tasks | *See lines below* |
| `github.issue_labels.bugfix` | List of labels related to bugfixes | `["kind/bug]` |
| `github.issue_labels.feature` | List of labels related to features | `["kind/feature"]` |
| `github.issue_labels.refactoring` | List of labels related to refactoring | `["kind/refactoring"]` |
| `github.issue_labels.documentation` | List of labels related to documentation | `["kind/documentation"]` |
| `github.issue_labels.improvement` | List of labels related to improvements | `["kind/improvement"]` |

### Branches configuration

| Parameter | Description | Default value |
| ------------------- | --------------------------------------- | ------------- |
| `branches.prefixes` | Branch prefix related to the issue type | `{}` |

>NOTE: By default it will match the issue type name with the branch prefix. For example, if the issue type name is `bugfix` it will match the branch prefix `bugfix`.
If no configuration file is found, the first time you run a command it will ask you to configure your Jira credentials (if you want to use Jira integration) and then proceed to create the configuration file with the provided Jira credentials.

## Contribute

Expand Down
27 changes: 25 additions & 2 deletions internal/config/configuration.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ import (
"fmt"
"os"
"path/filepath"
"time"

"github.com/InditexTech/gh-sherpa/internal/interactive"
"github.com/InditexTech/gh-sherpa/internal/logging"
"github.com/InditexTech/gh-sherpa/pkg/metadata"
"github.com/spf13/viper"
)

Expand Down Expand Up @@ -143,8 +145,29 @@ func writeConfigurationFile(cfgFile ConfigFile) error {
if err := os.MkdirAll(cfgFile.Path, os.ModePerm); err != nil {
return err
}
vip.SetConfigFile(cfgFile.getFilePath())
if err := vip.WriteConfig(); err != nil {
filePath := cfgFile.getFilePath()
vip.SetConfigFile(filePath)

f, err := os.Create(filePath)
if err != nil {
return err
}
defer f.Close()

if err := vip.Unmarshal(&cfg); err != nil {
return err
}

configFileTemplateData := configFileTemplateData{
Metadata: MetadataConfiguration{
Version: metadata.Version,
GeneratedAt: time.Now(),
},
JiraData: JiraTemplateConfiguration{
Jira: cfg.Jira,
},
}
if err := writeTemplatedConfigFile(f, configFileTemplateData); err != nil {
return err
}

Expand Down
21 changes: 9 additions & 12 deletions internal/config/configuration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,25 +66,22 @@ func (s *ConfigurationTestSuite) TestGetConfiguration() {
}

s.Run("Should panic if configuration is not initialized", func() {
defer func() { recover() }()

GetConfig()
resetConfigInitialization()

s.Fail("Should have panicked")
s.Panics(func() {
GetConfig()
})
})

s.Run("Loads default configuration if file doesn't exists", func() {
s.Run("Should return configuration without panic", func() {
resetConfigInitialization()

defaultConfig, err := parseConfiguration(defaultConfigBuff)
err := Initialize(false)
s.Require().NoError(err)

err = Initialize(false)
s.Require().NoError(err)

configuration := GetConfig()

s.Truef(reflect.DeepEqual(defaultConfig, configuration), "Expected: %v\nActual: %v", defaultConfig, configuration)
s.NotPanics(func() {
GetConfig()
})
})

s.Run("Loads configuration from file if file exists", func() {
Expand Down
75 changes: 61 additions & 14 deletions internal/config/default-config.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,77 @@
# Jira configuration -----------------------------------#
#============================= GH SHERPA CONFIG ===============================#
# #
# This is the default configuration file for GH Sherpa. These values will be #
# set if no other configuration override those values. You can override #
# the values by setting them in your `$HOME/.config/sherpa/config.yml` file. #
# #
#==============================================================================#

# GH Sherpa issue types ------------------------------------------------------#
# You can use the following issue types in the sections below that indicate it.
# - bugfix
# - dependency
# - deprecation
# - documentation
# - feature
# - hotfix
# - improvement
# - internal
# - refactoring
# - release
# - removal
# - revert
# - security
#-----------------------------------------------------------------------------#

# Jira configuration ---------------------------------------------------------#
jira:
# Jira authentication configuration
auth:
# Jira authentication url to generate PAT
# WARNING: Replace it with your actual Jira authentication url
host: https://jira.example.com
# Jira already generated PAT
# WARNING: Replace it with your actual Jira PAT
token: <Jira PAT>
# Jira insecure TLS configuration
# The URL to connect to your Jira instance.
host: ""
# This token will be used to authenticate to Jira.
# You can generate a PAT in your Jira instance if you didn't already
# have one generated by GH Sherpa.
token: ""
# Enable this setting to skip TLS verification.
# This is useful when you are using self-signed certificates
# or when you are authenticating to a non-HTTPS Jira instance.
# WARNING: It is not recommended to enable this option unless
# you are in a trusted network.
skip_tls_verify: false

# Jira issue types configuration
# You can find the issue types in your Jira instance by navigating to
# `https://{your-jira-domain}/jira/rest/api/2/issuetype`. More info in
# https://developer.atlassian.com/cloud/jira/platform/rest/v2/api-group-issue-types/#api-group-issue-types
issue_types:
# Jira issue types for bugfix
bugfix: ["1"]
# Jira issue types for features
feature: ["3", "5"]
# Jira issue types for improvements
improvement: ["4"]
# You can map here other issue types.

# Github configuration --------------------------------#
# Github configuration -------------------------------------------------------#
github:
# Github issue labels configuration
# Here you can configure the issue labels mapping between Github issues and
# GH Sherpa issue types.
issue_labels:
bugfix: ["kind/bug"]
feature: ["kind/feature"]
refactoring: ["kind/refactoring"]
documentation: ["kind/documentation"]
feature: ["kind/feature"]
improvement: ["kind/improvement"]
refactoring: ["kind/refactoring"]
# You can map here other issue types.

# Branches configuration -----------------------------------------------------#
branches:
# Branch prefixes configuration
# Here you can set the prefixes that will be used when creating the branches
# for the issues. By default it will use the issue type as prefix.
prefixes:
# We provide some examples below to help you configure your prefixes, select one
# issue type and map it to a custom prefix.
# Example: map `bugfix` type to a branch prefix `myfix/xxxx`:
# bugfix: myfix
# Example: map `feature` type to a branch prefix `feat/xxxx`:
# feature: feat
3 changes: 3 additions & 0 deletions internal/config/jira.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ type patResponseBody struct {

func configureJira() error {
configuredHost := vip.GetString("jira.auth.host")
if configuredHost == "" {
configuredHost = "https://jira.example.com"
}
host, pat, username, password, patName, err := interactive.AskUserForJiraInputs(configuredHost)
if err != nil {
return err
Expand Down
48 changes: 48 additions & 0 deletions internal/config/parser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package config

import (
"embed"
"io"
"text/template"
"time"
)

//go:embed templates/*.tmpl
var embeddedTemplates embed.FS

type configFileTemplateData struct {
Metadata MetadataConfiguration
JiraData JiraTemplateConfiguration
GithubData GithubTemplateConfiguration
BranchesData BranchesTemplateConfiguration
}

type MetadataConfiguration struct {
Version string
GeneratedAt time.Time
}

type JiraTemplateConfiguration struct {
Jira
}

type GithubTemplateConfiguration struct {
Github
}

type BranchesTemplateConfiguration struct {
Branches
}

func writeTemplatedConfigFile(wr io.Writer, templateData configFileTemplateData) error {
t, err := template.ParseFS(embeddedTemplates, "templates/*.tmpl")
if err != nil {
return err
}

if err := t.ExecuteTemplate(wr, "configuration", templateData); err != nil {
return err
}

return nil
}
76 changes: 76 additions & 0 deletions internal/config/parser_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package config

import (
"bytes"
"strings"
"testing"
"text/template"
"time"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestMetedataTemplateConfiguration(t *testing.T) {
tmpl, err := template.ParseFS(embeddedTemplates, "templates/*.tmpl")
require.NoError(t, err)

t.Run("Should render metadata", func(t *testing.T) {
var buff bytes.Buffer
templateCfg := configFileTemplateData{
Metadata: MetadataConfiguration{
Version: "1.0.0",
GeneratedAt: time.Date(2023, 10, 2, 17, 30, 0, 0, time.UTC),
},
}
err := tmpl.ExecuteTemplate(&buff, "configuration", templateCfg)
require.NoError(t, err)
assert.True(t, strings.Contains(buff.String(), "# This file was generated by GH Sherpa CLI v1.0.0 at 2023-10-02 17:30:00 +0000 UTC"))
})
}

func TestJiraTemplateConfiguration(t *testing.T) {
tmpl, err := template.ParseFS(embeddedTemplates, "templates/*.tmpl")
require.NoError(t, err)

t.Run("Should generate empty configuration", func(t *testing.T) {
jiraData := JiraTemplateConfiguration{
Jira: Jira{},
}

var buff bytes.Buffer
err := tmpl.ExecuteTemplate(&buff, "jiraConfiguration", jiraData)
require.NoError(t, err)

require.Equal(t, `jira:
auth:
host:
token:
skip_tls_verify: false
`, buff.String())
})

t.Run("Should generate configuration with values", func(t *testing.T) {
jiraData := JiraTemplateConfiguration{
Jira: Jira{
Auth: JiraAuth{
Host: "https://jira.example.com",
Token: "jira-pat",
InsecureTLS: true,
},
},
}

var buff bytes.Buffer
err := tmpl.ExecuteTemplate(&buff, "jiraConfiguration", jiraData)
require.NoError(t, err)

require.Equal(t, `jira:
auth:
host: https://jira.example.com
token: jira-pat
skip_tls_verify: true
`, buff.String())

})
}
9 changes: 9 additions & 0 deletions internal/config/templates/configuration.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{{define "configuration" -}}
#=============================== GH SHERPA CONFIG =================================#
# You can find more information about the configuration file in the documentation: #
# https://github.com/InditexTech/gh-sherpa/blob/main/docs/configuration.md #
#==================================================================================#
# This file was generated by GH Sherpa CLI v{{.Metadata.Version}} at {{.Metadata.GeneratedAt.Format "2006-01-02 15:04:05 -0700 MST"}}

{{if .JiraData.Auth.Host}}{{template "jiraConfiguration" .JiraData}}{{end}}
{{end}}
8 changes: 8 additions & 0 deletions internal/config/templates/jiraConfiguration.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{{ define "jiraConfiguration" -}}
jira:
auth:
host: {{.Auth.Host}}
token: {{.Auth.Token}}
skip_tls_verify: {{.Auth.InsecureTLS}}
{{end }}

4 changes: 4 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package main

import (
_ "embed"
"strings"

"github.com/InditexTech/gh-sherpa/cmd"
"github.com/InditexTech/gh-sherpa/pkg/metadata"
)

//go:embed version
Expand All @@ -14,6 +16,8 @@ func main() {
version = "Development Build"
}

metadata.Version = strings.TrimSpace(version)

cmd.SetVersion(version)
cmd.Execute()
}
Loading

0 comments on commit 2ad125b

Please sign in to comment.