Skip to content

Commit

Permalink
fix: add makefile rule
Browse files Browse the repository at this point in the history
  • Loading branch information
jstrachan committed Jun 19, 2020
1 parent e326af3 commit d80703a
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 5 deletions.
11 changes: 8 additions & 3 deletions pkg/apis/boot/v1alpha1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,14 @@ type MakefileSpec struct {
// Path the path to the Makefile to modify. If none specified it defaults to `Makefile` in the root of the source repository
Path string `json:"path,omitempty"`

// Namespace specifies the namespace to deploy applications if using kpt. If specified this value will be used instead
// of the Environment.Spec.Namespace in the Environment CRD
Namespace string `json:"namespace,omitempty"`
// InsertAfterPrefix insert after the last command with this prefix
InsertAfterPrefix string `json:"insertAfterPrefix,omitempty"`

// UpdatePrefixTemplate the prefix command string to find to update if upgrading a version
UpdatePrefixTemplate string `json:"updatePrefixTemplate,omitempty"`

// CommandTemplate the command template
CommandTemplate string `json:"commandTemplate,omitempty"`
}

// PromoteList contains a list of Promote
Expand Down
113 changes: 111 additions & 2 deletions pkg/promote/rules/makefile_rule.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,116 @@
package rules

import "github.com/jenkins-x/jx-promote/pkg/apis/boot/v1alpha1"
import (
"io/ioutil"
"path/filepath"
"strings"
"text/template"

func MakefileRule(dir string, config *v1alpha1.Promote) error {
"github.com/jenkins-x/jx-logging/pkg/log"
"github.com/jenkins-x/jx/pkg/util"
"github.com/pkg/errors"
)

var (
makeLinePrefix = "\t"
)

// MakefileRule applies the Makefile rule to the file
func MakefileRule(r *PromoteRule) error {
config := r.Config
if config.Spec.MakefileRule == nil {
return errors.Errorf("no makefile rule configured")
}
rule := config.Spec.MakefileRule
path := rule.Path
if path == "" {
path = "Makefile"
}
path = filepath.Join(r.Dir, path)
exists, err := util.FileExists(path)
if err != nil {
return errors.Wrapf(err, "failed to check if file exists %s", path)
}
if !exists {
return errors.Errorf("file does not exist: %s", path)
}

data, err := ioutil.ReadFile(path)
if err != nil {
return errors.Wrapf(err, "failed to read file %s", path)
}

lines := strings.Split(string(data), "\n")

line, err := evaluateTemplate(r, rule.CommandTemplate)
if err != nil {
return errors.Wrapf(err, "failed to create Makefile statement")
}
line = makeLinePrefix + line
updatePrefix, err := evaluateTemplate(r, rule.UpdatePrefixTemplate)
if err != nil {
return errors.Wrapf(err, "failed to create update prefix")
}
insertAfterPrefix := rule.InsertAfterPrefix

updated := false
if updatePrefix != "" {
updatePrefix = makeLinePrefix + updatePrefix
}
if insertAfterPrefix != "" {
insertAfterPrefix = makeLinePrefix + insertAfterPrefix
}
insertIdx := -1
for i, line := range lines {
if updatePrefix != "" && strings.HasPrefix(line, updatePrefix) {
updated = true
lines[i] = line
break
}
if insertAfterPrefix != "" && strings.HasPrefix(line, insertAfterPrefix) {
insertIdx = i
}
}
if insertIdx >= 0 {
updated = true
lines = insertItem(lines, insertIdx+1, line)
}
if !updated {
lines = append(lines, line)
}

data = []byte(strings.Join(lines, "\n"))
err = ioutil.WriteFile(path, data, util.DefaultFileWritePermissions)
if err != nil {
return errors.Wrapf(err, "failed to write file %s", path)
}
log.Logger().Infof("modified file %s", util.ColorInfo(path))
return nil
}

func insertItem(a []string, index int, value string) []string {
if index >= len(a) {
return append(a, value)
}
a = append(a[:index+1], a[index:]...) // index < len(a)
a[index] = value
return a
}

func evaluateTemplate(r *PromoteRule, templateText string) (string, error) {
tmpl, err := template.New("test").Parse(templateText)
if err != nil {
return "", errors.Wrapf(err, "failed to parse go template: %s", templateText)
}
ctx := TemplateContext{
GitURL: r.GitURL,
Version: r.Version,
AppName: r.AppName,
}
buf := &strings.Builder{}
err = tmpl.Execute(buf, &ctx)
if err != nil {
return buf.String(), errors.Wrapf(err, "failed to evaluate template with %#v", ctx)
}
return buf.String(), nil
}
48 changes: 48 additions & 0 deletions pkg/promote/rules/makefile_rule_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package rules

import (
"io/ioutil"
"path/filepath"
"testing"

"github.com/jenkins-x/jx-promote/pkg/promoteconfig"
"github.com/jenkins-x/jx-promote/pkg/testhelpers"
"github.com/jenkins-x/jx/pkg/util"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestMakefileRules(t *testing.T) {
dir, err := ioutil.TempDir("", "")
require.NoError(t, err, "could not make a temp dir")

err = util.CopyDirOverwrite("test_data", dir)
require.NoError(t, err, "could not copy source data to %s", dir)

makefile := filepath.Join(dir, "Makefile")
assert.FileExists(t, makefile)

expectedFile := filepath.Join("test_data", "Makefile.1.expected")
assert.FileExistsf(t, expectedFile, "should have expected file")

config, _, err := promoteconfig.LoadPromote(dir, true)
require.NoError(t, err, "failed to load config dir %s", dir)
require.NotNil(t, config, "no project config found in dir %s", dir)
require.NotNil(t, config.Spec.MakefileRule, "config.Spec.MakefileRule")
require.NotEmpty(t, config.Spec.MakefileRule.InsertAfterPrefix, "config.Spec.MakefileRule.InsertAfterPrefix")
require.NotEmpty(t, config.Spec.MakefileRule.UpdatePrefixTemplate, "config.Spec.MakefileRule.UpdatePrefixTemplate")
require.NotEmpty(t, config.Spec.MakefileRule.CommandTemplate, "config.Spec.MakefileRule.CommandTemplate")

r := &PromoteRule{
Dir: dir,
Config: *config,
GitURL: "https://github.com/myorg/myapp.git",
Version: "1.2.3",
AppName: "myapp",
}

err = MakefileRule(r)
require.NoError(t, err, "failed to run MakefileRule at dir %s", dir)

testhelpers.AssertTextFilesEqual(t, expectedFile, makefile, "makefile")
}
7 changes: 7 additions & 0 deletions pkg/promote/rules/test_data/.jx/promote.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
apiVersion: promote.jenkins-x.io/v1alpha1
kind: Promote
spec:
makefileRule:
insertAfterPrefix: "kpt pkg get"
updatePrefixTemplate: "kpt pkg get {{.GitURL}}@"
commandTemplate: "kpt pkg get {{.GitURL}}/kubernetess@v{{.Version}} $(FETCH_DIR)/namespaces/jx"
24 changes: 24 additions & 0 deletions pkg/promote/rules/test_data/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
FETCH_DIR := build/base
OUTPUT_DIR := config-root

.PHONY: clean
clean:
rm -rf build $(OUTPUT_DIR)

init:
mkdir -p $(FETCH_DIR)
mkdir -p $(OUTPUT_DIR)/namespaces/jx
cp -r src/* build
mkdir -p $(FETCH_DIR)/cluster/crds
mkdir -p $(FETCH_DIR)/namespaces/nginx
mkdir -p $(FETCH_DIR)/namespaces/vault-infra


.PHONY: fetch
fetch: init
kpt pkg get https://github.com/jenkins-x/jxr-kube-resources.git/jx-labs/jenkins-x-crds@master $(FETCH_DIR)/cluster/crds
- kpt pkg get https://github.com/jenkins-x/jxr-kube-resources.git/jenkins-x/jx@master $(FETCH_DIR)/namespaces/jx
kpt pkg get https://github.com/jenkins-x/jxr-kube-resources.git/jenkins-x/jxboot-helmfile-resources@master $(FETCH_DIR)/namespaces/jx

# this step is not required if using `helm template --namespace` for each chart
jx-gitops namespace --dir-mode --dir $(FETCH_DIR)/namespaces
25 changes: 25 additions & 0 deletions pkg/promote/rules/test_data/Makefile.1.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
FETCH_DIR := build/base
OUTPUT_DIR := config-root

.PHONY: clean
clean:
rm -rf build $(OUTPUT_DIR)

init:
mkdir -p $(FETCH_DIR)
mkdir -p $(OUTPUT_DIR)/namespaces/jx
cp -r src/* build
mkdir -p $(FETCH_DIR)/cluster/crds
mkdir -p $(FETCH_DIR)/namespaces/nginx
mkdir -p $(FETCH_DIR)/namespaces/vault-infra


.PHONY: fetch
fetch: init
kpt pkg get https://github.com/jenkins-x/jxr-kube-resources.git/jx-labs/jenkins-x-crds@master $(FETCH_DIR)/cluster/crds
- kpt pkg get https://github.com/jenkins-x/jxr-kube-resources.git/jenkins-x/jx@master $(FETCH_DIR)/namespaces/jx
kpt pkg get https://github.com/jenkins-x/jxr-kube-resources.git/jenkins-x/jxboot-helmfile-resources@master $(FETCH_DIR)/namespaces/jx
kpt pkg get https://github.com/myorg/myapp.git/[email protected] $(FETCH_DIR)/namespaces/jx

# this step is not required if using `helm template --namespace` for each chart
jx-gitops namespace --dir-mode --dir $(FETCH_DIR)/namespaces
19 changes: 19 additions & 0 deletions pkg/promote/rules/types.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package rules

import "github.com/jenkins-x/jx-promote/pkg/apis/boot/v1alpha1"

// PromoteRule represents a profile rule
type PromoteRule struct {
Dir string
Config v1alpha1.Promote
GitURL string
Version string
AppName string
}

// TemplateContext expressions used in templates
type TemplateContext struct {
GitURL string
Version string
AppName string
}

0 comments on commit d80703a

Please sign in to comment.