Skip to content

Commit b71e472

Browse files
Diresidejb55
authored andcommitted
CI Templates
- Added CI files. - Added tests. Refactored code to make it more testable.
1 parent a767988 commit b71e472

File tree

11 files changed

+353
-0
lines changed

11 files changed

+353
-0
lines changed

cmd/generate.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"sync"
66

77
"github.com/commitdev/commit0/internal/config"
8+
"github.com/commitdev/commit0/internal/generate/ci"
89
"github.com/commitdev/commit0/internal/generate/docker"
910
"github.com/commitdev/commit0/internal/generate/golang"
1011
"github.com/commitdev/commit0/internal/generate/http"
@@ -67,6 +68,10 @@ var generateCmd = &cobra.Command{
6768

6869
util.TemplateFileIfDoesNotExist("", "README.md", t.Readme, &wg, cfg)
6970

71+
if cfg.CI.System != "" {
72+
ci.Generate(t.CI, cfg, ".", &wg)
73+
}
74+
7075
if cfg.Network.Http.Enabled {
7176
http.GenerateHTTPGW(t, cfg, &wg)
7277
docker.GenerateGoHTTPGWDockerFile(t, cfg, &wg)

go.mod

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,22 @@ require (
88
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
99
github.com/k0kubun/pp v3.0.1+incompatible
1010
github.com/mattn/go-colorable v0.1.2 // indirect
11+
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect
12+
github.com/pelletier/go-toml v1.4.0 // indirect
13+
github.com/pkg/errors v0.8.1 // indirect
14+
github.com/prometheus/client_golang v1.1.0 // indirect
15+
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 // indirect
16+
github.com/rogpeppe/fastuuid v1.2.0 // indirect
1117
github.com/rogpeppe/go-internal v1.5.0 // indirect
18+
github.com/russross/blackfriday v2.0.0+incompatible // indirect
19+
github.com/smartystreets/goconvey v0.0.0-20190731233626-505e41936337 // indirect
20+
github.com/spf13/afero v1.2.2 // indirect
1221
github.com/spf13/cobra v0.0.5
1322
github.com/stretchr/testify v1.4.0 // indirect
1423
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect
1524
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e // indirect
1625
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect
26+
google.golang.org/grpc v1.24.0 // indirect
1727
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
1828
gopkg.in/yaml.v2 v2.2.4
1929
)

go.sum

Lines changed: 83 additions & 0 deletions
Large diffs are not rendered by default.

internal/config/config.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ type Service struct {
4545
Description string
4646
}
4747

48+
type CI struct {
49+
System string `yaml:"system"`
50+
BuildImage string `yaml:"build-image"`
51+
BuildCommand string `yaml:"build-command"`
52+
TestCommand string `yaml:"test-command"`
53+
LanguageVersion string `yaml:"language-version"`
54+
}
55+
4856
type Commit0Config struct {
4957
Language string `yaml:"string"`
5058
Organization string `yaml:"organization"`
@@ -57,6 +65,7 @@ type Commit0Config struct {
5765
Services []Service `yaml:"services"`
5866
React React `yaml:"react"`
5967
Kubernetes Kubernetes `yaml:"kubernetes"`
68+
CI CI `yaml:"ci"`
6069
}
6170

6271
type Kubernetes struct {

internal/generate/ci/generate.go

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
package ci
2+
3+
import (
4+
"fmt"
5+
"sync"
6+
7+
"github.com/commitdev/commit0/internal/config"
8+
"github.com/commitdev/commit0/internal/templator"
9+
"github.com/commitdev/commit0/internal/util"
10+
)
11+
12+
const (
13+
defaultGoDockerImage = "golang/golang"
14+
defaultGoVersion = "1.12"
15+
defaultBuildCommand = "make build"
16+
defaultTestCommand = "make test"
17+
)
18+
19+
type CIGenerationError struct {
20+
err string
21+
config *config.Commit0Config
22+
}
23+
24+
func (e *CIGenerationError) Error() string {
25+
return fmt.Sprintf("Error: %s. Unable to Generate CI/CD Pipeline with config:\n%v\n", e.err, e.config)
26+
}
27+
28+
// Generate a CI configuration file based on your language and CI system
29+
func Generate(templator *templator.CITemplator, config *config.Commit0Config, basePath string, wg *sync.WaitGroup) error {
30+
switch config.Language {
31+
case "go":
32+
if config.CI.LanguageVersion == "" {
33+
config.CI.LanguageVersion = defaultGoVersion
34+
}
35+
if config.CI.BuildImage == "" {
36+
config.CI.BuildImage = fmt.Sprintf("%s:%s", defaultGoDockerImage, config.CI.LanguageVersion)
37+
}
38+
if config.CI.BuildCommand == "" {
39+
config.CI.BuildCommand = defaultBuildCommand
40+
}
41+
if config.CI.TestCommand == "" {
42+
config.CI.TestCommand = defaultTestCommand
43+
}
44+
default:
45+
return &CIGenerationError{"Unsupported Language", config}
46+
}
47+
48+
var ciConfigPath string
49+
var ciFilename string
50+
51+
switch config.CI.System {
52+
case "jenkins":
53+
ciConfigPath = basePath
54+
ciFilename = "Jenkinsfile"
55+
case "circleci":
56+
ciConfigPath = fmt.Sprintf("%s/%s", basePath, ".circleci/")
57+
ciFilename = "config.yml"
58+
case "travisci":
59+
ciConfigPath = basePath
60+
ciFilename = ".travis.yml"
61+
default:
62+
return &CIGenerationError{"Unsupported CI System", config}
63+
}
64+
65+
util.TemplateFileIfDoesNotExist(ciConfigPath, ciFilename, templator.TravisCI, wg, config)
66+
67+
return nil
68+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package ci_test
2+
3+
import (
4+
"sync"
5+
"testing"
6+
"text/template"
7+
8+
"github.com/commitdev/commit0/internal/config"
9+
"github.com/commitdev/commit0/internal/generate/ci"
10+
"github.com/commitdev/commit0/internal/templator"
11+
)
12+
13+
func TestGenerateJenkins(t *testing.T) {
14+
testConf := &config.Commit0Config{
15+
Language: "go",
16+
CI: config.CI{
17+
System: "jenkins",
18+
},
19+
}
20+
testTemp := &templator.CITemplator{
21+
Jenkins: &template.Template{},
22+
CircleCI: &template.Template{},
23+
TravisCI: &template.Template{},
24+
}
25+
var wg sync.WaitGroup
26+
err := ci.Generate(testTemp, testConf, "/dev/null", &wg)
27+
if err != nil {
28+
t.Errorf("Error when executing test. %s", err)
29+
}
30+
31+
expectedBuildImage := "golang/golang:1.12"
32+
actualBuildImage := testConf.CI.BuildImage
33+
if actualBuildImage != expectedBuildImage {
34+
t.Errorf("want: %s, got: %s", expectedBuildImage, actualBuildImage)
35+
}
36+
37+
expectedBuildCommand := "make build"
38+
actualBuildCommand := testConf.CI.BuildCommand
39+
if actualBuildCommand != expectedBuildCommand {
40+
t.Errorf("want: %s, got: %s", expectedBuildCommand, actualBuildCommand)
41+
}
42+
43+
expectedTestCommand := "make test"
44+
actualTestCommand := testConf.CI.TestCommand
45+
if actualTestCommand != expectedTestCommand {
46+
t.Errorf("want: %s, got: %s", expectedTestCommand, actualTestCommand)
47+
}
48+
}
49+
50+
func TestGenerateInvalidLanguage(t *testing.T) {
51+
testConf := &config.Commit0Config{
52+
Language: "invalidLanguage",
53+
}
54+
testTemp := &templator.CITemplator{
55+
Jenkins: &template.Template{},
56+
CircleCI: &template.Template{},
57+
TravisCI: &template.Template{},
58+
}
59+
var wg sync.WaitGroup
60+
err := ci.Generate(testTemp, testConf, "/dev/null", &wg)
61+
if err == nil {
62+
t.Errorf("Error should be thrown with invalid language specified. %s", err.Error())
63+
}
64+
}
65+
66+
func TestGenerateInvalidCISystem(t *testing.T) {
67+
testConf := &config.Commit0Config{
68+
Language: "go",
69+
CI: config.CI{
70+
System: "invalidCISystem",
71+
},
72+
}
73+
testTemp := &templator.CITemplator{
74+
Jenkins: &template.Template{},
75+
CircleCI: &template.Template{},
76+
TravisCI: &template.Template{},
77+
}
78+
var wg sync.WaitGroup
79+
err := ci.Generate(testTemp, testConf, "/dev/null", &wg)
80+
if err == nil {
81+
t.Errorf("Error should be thrown with invalid ci system specified. %s", err.Error())
82+
}
83+
}

internal/templator/templator.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,12 @@ import (
1212
"github.com/gobuffalo/packr/v2/file"
1313
)
1414

15+
type CITemplator struct {
16+
CircleCI *template.Template
17+
TravisCI *template.Template
18+
Jenkins *template.Template
19+
}
20+
1521
// DockerTemplator contains the templates relevent to docker
1622
type DockerTemplator struct {
1723
ApplicationDocker *template.Template
@@ -42,6 +48,7 @@ type Templator struct {
4248
Docker *DockerTemplator
4349
React *DirectoryTemplator
4450
Kubernetes *DirectoryTemplator
51+
CI *CITemplator
4552
}
4653

4754
func NewTemplator(box *packr.Box) *Templator {
@@ -56,6 +63,7 @@ func NewTemplator(box *packr.Box) *Templator {
5663
Docker: NewDockerFileTemplator(box),
5764
React: NewDirectoryTemplator(box, "react"),
5865
Kubernetes: NewDirectoryTemplator(box, "kubernetes"),
66+
CI: NewCITemplator(box),
5967
}
6068
}
6169

@@ -95,6 +103,25 @@ func NewSingleFileTemplator(box *packr.Box, file string) *template.Template {
95103
return t
96104
}
97105

106+
// NewCITemplator creates a build pipeline config file in your repository.
107+
// Only supports CircleCI for now, eventually will add Jenkins, Travis, etc
108+
func NewCITemplator(box *packr.Box) *CITemplator {
109+
circleciTemplateSource, _ := box.FindString("ci/circleci.tmpl")
110+
circleciTemplate, _ := template.New("CIConfig").Parse(circleciTemplateSource)
111+
112+
travisciTemplateSource, _ := box.FindString("ci/travis.tmpl")
113+
travisciTemplate, _ := template.New("CIConfig").Parse(travisciTemplateSource)
114+
115+
jenkinsTemplateSource, _ := box.FindString("ci/Jenkinsfile.tmpl")
116+
jenkinsTemplate, _ := template.New("CIConfig").Parse(jenkinsTemplateSource)
117+
118+
return &CITemplator{
119+
CircleCI: circleciTemplate,
120+
TravisCI: travisciTemplate,
121+
Jenkins: jenkinsTemplate,
122+
}
123+
}
124+
98125
type DirectoryTemplator struct {
99126
Templates []*template.Template
100127
}

templates/ci/Jenkinsfile.tmpl

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
pipeline {
2+
agent none
3+
stages {
4+
stage('Build and Test') {
5+
parallel {
6+
stage('Build') {
7+
agent {
8+
docker {
9+
image '{{ .CI.BuildImage }}'
10+
}
11+
}
12+
steps {
13+
sh '{{ .CI.BuildCommand }}'
14+
}
15+
}
16+
stage('Test') {
17+
agent {
18+
docker {
19+
image '{{ .CI.BuildImage }}'
20+
}
21+
}
22+
steps {
23+
sh '{{ .CI.TestCommand }}'
24+
}
25+
}
26+
}
27+
}
28+
}
29+
}

templates/ci/circleci.tmpl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
version: 2.1
2+
jobs:
3+
build:
4+
docker:
5+
- image: {{ .CI.BuildImage }}
6+
steps:
7+
- checkout
8+
- run:
9+
name: Build
10+
command: |
11+
{{ .CI.BuildCommand }}
12+
13+
test:
14+
docker:
15+
steps:
16+
- checkout
17+
- run:
18+
name: Test
19+
command: |
20+
{{ .CI.BuildCommand }}
21+
22+
23+
workflow:
24+
version: 2.1
25+
build_and_test:
26+
jobs:
27+
- build
28+
- test

templates/ci/travis.tmpl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
language: {{ .Language }}
2+
{{ .Language }}:
3+
- {{ .CI.LanguageVersion}}
4+
5+
scripts:
6+
- {{ .CI.BuildCommand }}
7+
- {{ .CI.TestCommand }}

0 commit comments

Comments
 (0)