grim/convey

Bump the version
v0.14.0-alpha4
2018-02-20, Gary Kramlich
89afa53fab1b
Bump the version
// Convey
// Copyright 2016-2018 Gary Kramlich <grim@reaperworld.com>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package codebuild
import (
"fmt"
"path/filepath"
"strings"
"github.com/go-yaml/yaml"
"bitbucket.org/rw_grim/convey/config"
"bitbucket.org/rw_grim/convey/docker"
"bitbucket.org/rw_grim/convey/plans"
"bitbucket.org/rw_grim/convey/script"
"bitbucket.org/rw_grim/convey/stages"
"bitbucket.org/rw_grim/convey/state"
"bitbucket.org/rw_grim/convey/tasks"
)
// Loader defines an AWS CodeBuild configuration.
type Loader struct {
region string
image string
accountID string
}
func (l *Loader) loadOptions(options []string) error {
for _, opt := range options {
parts := strings.SplitN(opt, "=", 2)
if len(parts) != 2 {
return fmt.Errorf("invalid option '%s'", opt)
}
switch parts[0] {
case "region":
l.region = parts[1]
case "image":
l.image = parts[1]
case "account-id":
l.accountID = parts[1]
}
}
if l.image == "" {
return fmt.Errorf("no image specified")
}
return nil
}
// Load loads an AWS CodeBuild buildspec.yml.
func (l *Loader) Load(path, base string, data []byte, options []string, disableDeprecated bool) (*config.Config, error) {
err := l.loadOptions(options)
if err != nil {
return nil, err
}
var cb CodeBuild
err = yaml.Unmarshal(data, &cb)
if err != nil {
return nil, err
}
cfg := &config.Config{
Tasks: map[string]tasks.Task{
"import": &docker.Import{
Files: []string{"."},
},
},
Plans: map[string]plans.Plan{},
}
// create our plan and add our tasks
plan := plans.Plan{
Stages: []stages.Stage{
{
Name: "import",
Enabled: true,
Run: "on-success",
Tasks: []string{"import"},
},
},
}
// TODO put the right image here
err = l.addPhases(cb, cfg, l.image, &plan)
if err != nil {
return nil, err
}
l.createExportTask(cb, cfg, &plan)
cfg.Plans["default"] = plan
return cfg, nil
}
func (l *Loader) addPhase(cb CodeBuild, cfg *config.Config, phaseName, imageName string, plan *plans.Plan) error {
phase, ok := cb.Phases[phaseName]
// ignore phases that are not in the yaml
if !ok {
return nil
}
parsedTasks, err := script.Parse(imageName, "/bin/sh", phase.Commands)
if err != nil {
return err
}
// create our stage
stage := stages.Stage{
Name: phaseName,
Enabled: true,
Run: "on-success",
}
// now add the tasks to the config and the stage
for idx, task := range parsedTasks {
name := fmt.Sprintf("%s-%d", phaseName, idx)
cfg.Tasks[name] = task
stage.Tasks = append(stage.Tasks, name)
}
// add the stage to the plan
plan.Stages = append(plan.Stages, stage)
return nil
}
func (l *Loader) addPhases(cb CodeBuild, cfg *config.Config, imageName string, plan *plans.Plan) error {
phases := []string{"install", "pre_build", "build", "post_build"}
// load all of the phases scripts into a single slice
for _, phase := range phases {
err := l.addPhase(cb, cfg, phase, imageName, plan)
if err != nil {
return err
}
}
return nil
}
func (l *Loader) createExportTask(cb CodeBuild, cfg *config.Config, plan *plans.Plan) {
if len(cb.Artifacts.Files) == 0 {
return
}
export := &docker.Export{
Files: cb.Artifacts.Files,
}
cfg.Tasks["artifacts"] = export
if cb.Artifacts.DiscardPaths == "yes" {
for idx, name := range cb.Artifacts.Files {
cb.Artifacts.Files[idx] = filepath.Base(name)
}
}
exportStage := stages.Stage{
Name: "artifacts",
Enabled: true,
Run: "on-success",
Tasks: []string{"artifacts"},
}
plan.Stages = append(plan.Stages, exportStage)
}
// LoadOverride just satisfies the Loader interface an is not implemented.
func (l *Loader) LoadOverride(path, base string, data []byte, config *config.Config, disableDeprecated bool) {
}
// Filenames returns the filenames defining AWS CodeBuild configurations.
func (l *Loader) Filenames() []string {
return []string{"buildspec.yml"}
}
// OverrideSuffix just satisfies the Loader interface and is not used.
func (l *Loader) OverrideSuffix() string {
return ""
}
// DefaultPlan returns the default plan to use when an AWS CodeBuild
// configuration is loaded.
func (l *Loader) DefaultPlan() string {
return "default"
}
// ResolvePlanName satisfies the LoaderInterface and returns the default value.
func (l *Loader) ResolvePlanName(plan string, cfg *config.Config, st *state.State) string {
return plan
}