Files
2020-06-27 09:15:53 -07:00

167 lines
3.7 KiB
Go

// Copyright (c) 2020, the Drone Plugins project authors.
// Please see the AUTHORS file for details. All rights reserved.
// Use of this source code is governed by an Apache 2.0 license that can be
// found in the LICENSE file.
package plugin
import (
"errors"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"runtime"
"strings"
"github.com/drone-plugins/drone-manifest/tagging"
"github.com/drone/drone-template-lib/template"
"github.com/urfave/cli/v2"
)
// Settings for the plugin.
type Settings struct {
Username string
Password string
Insecure bool
Platforms cli.StringSlice
Target string
Template string
Spec string
IgnoreMissing bool
Tags cli.StringSlice
AutoTag bool
}
// Validate handles the settings validation of the plugin.
func (p *Plugin) Validate() error {
if p.settings.Username == "" && p.settings.Password != "" {
return errors.New("you must provide a username")
}
if p.settings.Password == "" && p.settings.Username != "" {
return errors.New("you must provide a password")
}
if p.settings.Spec == "" {
if len(p.settings.Platforms.Value()) == 0 {
return errors.New("you must provide platforms")
}
if p.settings.Target == "" {
return errors.New("you must provide a target")
}
if p.settings.Template == "" {
return errors.New("you must provide a template")
}
}
return nil
}
// Execute provides the implementation of the plugin.
func (p *Plugin) Execute() error {
// Anonymous struct for the templating engine
var t struct {
Build struct {
Tag string
Tags []string
}
}
// Determine the tags
t.Build.Tag = p.pipeline.Build.Tag
if p.settings.AutoTag {
if tagging.UseDefaultTag(p.pipeline.Commit.Ref, p.pipeline.Repo.Branch) {
t.Build.Tags = tagging.DefaultTags(p.pipeline.Commit.Ref)
} else {
log.Printf("skipping automated tags for %s", p.pipeline.Commit.Ref)
return nil
}
} else {
t.Build.Tags = p.settings.Tags.Value()
}
args := []string{
fmt.Sprintf("--username=%s", p.settings.Username),
fmt.Sprintf("--password=%s", p.settings.Password),
}
if p.settings.Insecure {
args = append(args, "--insecure")
}
args = append(args, "push")
if p.settings.Spec != "" {
var raw []byte
// if spec is not a valid file, assume inlining
if _, err := os.Stat(p.settings.Spec); os.IsNotExist(err) {
raw = []byte(p.settings.Spec)
} else { // otherwise read it
raw, err = ioutil.ReadFile(p.settings.Spec)
if err != nil {
return fmt.Errorf("failed to read template: %w", err)
}
}
spec, err := template.RenderTrim(string(raw), t)
if err != nil {
return fmt.Errorf("failed to render template: %w", err)
}
tmpfile, err := ioutil.TempFile("", "manifest-")
if err != nil {
return fmt.Errorf("failed to create tempfile: %w", err)
}
defer os.Remove(tmpfile.Name())
if _, err := tmpfile.Write([]byte(spec)); err != nil {
return fmt.Errorf("failed to write tempfile: %w", err)
}
if err := tmpfile.Close(); err != nil {
return fmt.Errorf("failed to close tempfile: %w", err)
}
args = append(args, "from-spec")
args = append(args, tmpfile.Name())
} else {
args = append(
args,
"from-args",
fmt.Sprintf("--platforms=%s", strings.Join(p.settings.Platforms.Value(), ",")),
fmt.Sprintf("--target=%s", p.settings.Target),
fmt.Sprintf("--template=%s", p.settings.Template),
)
}
if p.settings.IgnoreMissing {
args = append(args, "--ignore-missing")
}
cmd := exec.Command(
mainfestToolPath(),
args...,
)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func mainfestToolPath() string {
if runtime.GOOS == "windows" {
return "C:/bin/manifest-tool.exe"
}
return "/bin/manifest-tool"
}