-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
7104c3b
commit 96e0636
Showing
12 changed files
with
1,268 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
// Copyright 2022 Harness, Inc. | ||
// | ||
// Licensed under the Apache License, Version 2.0 (the "License"); | ||
// you may not use this file except in compliance with the License. | ||
// You may obtain a copy of the License at | ||
// | ||
// http://www.apache.org/licenses/LICENSE-2.0 | ||
// | ||
// Unless required by applicable law or agreed to in writing, software | ||
// distributed under the License is distributed on an "AS IS" BASIS, | ||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
// See the License for the specific language governing permissions and | ||
// limitations under the License. | ||
|
||
package command | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
"io/ioutil" | ||
"log" | ||
"os" | ||
|
||
"github.com/drone/go-convert/convert/rio" | ||
|
||
"github.com/google/subcommands" | ||
) | ||
|
||
type Rio struct { | ||
name string | ||
proj string | ||
org string | ||
repoName string | ||
repoConn string | ||
kubeName string | ||
kubeConn string | ||
dockerConn string | ||
|
||
downgrade bool | ||
beforeAfter bool | ||
} | ||
|
||
func (*Rio) Name() string { return "rio" } | ||
func (*Rio) Synopsis() string { return "converts a rio pipeline" } | ||
func (*Rio) Usage() string { | ||
return `rio [-downgrade] <path to rio.yml> | ||
` | ||
} | ||
|
||
func (c *Rio) SetFlags(f *flag.FlagSet) { | ||
f.BoolVar(&c.downgrade, "downgrade", false, "downgrade to the legacy yaml format") | ||
f.BoolVar(&c.beforeAfter, "before-after", false, "print the befor and after") | ||
|
||
f.StringVar(&c.org, "org", "default", "harness organization") | ||
f.StringVar(&c.proj, "project", "default", "harness project") | ||
f.StringVar(&c.name, "pipeline", "default", "harness pipeline name") | ||
f.StringVar(&c.repoConn, "repo-connector", "", "repository connector") | ||
f.StringVar(&c.repoName, "repo-name", "", "repository name") | ||
f.StringVar(&c.kubeConn, "kube-connector", "", "kubernetes connector") | ||
f.StringVar(&c.kubeName, "kube-namespace", "", "kubernets namespace") | ||
f.StringVar(&c.dockerConn, "docker-connector", "", "dockerhub connector") | ||
} | ||
|
||
func (c *Rio) Execute(_ context.Context, f *flag.FlagSet, _ ...interface{}) subcommands.ExitStatus { | ||
path := f.Arg(0) | ||
|
||
fmt.Println("# v1 harness yaml is not supported for Rio pipelines. Converting to v0...") | ||
// if the user does not specify the path as | ||
// a command line arg, assume the default path. | ||
if path == "" { | ||
path = ".rio.yml" | ||
} | ||
|
||
// open the rio yaml | ||
before, err := ioutil.ReadFile(path) | ||
if err != nil { | ||
log.Println(err) | ||
return subcommands.ExitFailure | ||
} | ||
|
||
// convert the pipeline yaml from the rio | ||
// format to the harness yaml format. | ||
converter := rio.New( | ||
rio.WithDockerhub(c.dockerConn), | ||
rio.WithKubernetes(c.kubeName, c.kubeConn), | ||
rio.WithName(c.name), | ||
rio.WithIdentifier(c.name), | ||
rio.WithOrganization(c.org), | ||
rio.WithProject(c.proj), | ||
) | ||
after, err := converter.ConvertBytes(before) | ||
if err != nil { | ||
log.Println(err) | ||
return subcommands.ExitFailure | ||
} | ||
|
||
// downgrade from the v1 harness yaml format | ||
// to the v0 harness yaml format. | ||
if c.downgrade { | ||
fmt.Println("# downgrade for Rio pipeline is not supported") | ||
//// downgrade to the v0 yaml | ||
//d := downgrader.New( | ||
// downgrader.WithCodebase(c.repoName, c.repoConn), | ||
// downgrader.WithDockerhub(c.dockerConn), | ||
// downgrader.WithKubernetes(c.kubeName, c.kubeName), | ||
// downgrader.WithName(c.name), | ||
// downgrader.WithOrganization(c.org), | ||
// downgrader.WithProject(c.proj), | ||
//) | ||
//after, err = d.Downgrade(after) | ||
//if err != nil { | ||
// log.Println(err) | ||
// return subcommands.ExitFailure | ||
//} | ||
} | ||
|
||
if c.beforeAfter { | ||
os.Stdout.WriteString("---\n") | ||
os.Stdout.Write(before) | ||
os.Stdout.WriteString("\n---\n") | ||
} | ||
|
||
os.Stdout.Write(after) | ||
|
||
return subcommands.ExitSuccess | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,244 @@ | ||
package rio | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"io" | ||
"os" | ||
"strings" | ||
|
||
harness "github.com/drone/go-convert/convert/harness/yaml" | ||
rio "github.com/drone/go-convert/convert/rio/yaml" | ||
"github.com/drone/go-convert/internal/store" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
// as we walk the yaml, we store a | ||
// snapshot of the current node and | ||
// its parents. | ||
type context struct { | ||
config *rio.Config | ||
} | ||
|
||
// Converter converts a Rio pipeline to a Harness | ||
// v0 pipeline. | ||
type Converter struct { | ||
kubeEnabled bool | ||
kubeNamespace string | ||
kubeConnector string | ||
kubeOs string | ||
dockerhubConn string | ||
identifiers *store.Identifiers | ||
|
||
pipelineId string | ||
pipelineName string | ||
pipelineOrg string | ||
pipelineProj string | ||
} | ||
|
||
// New creates a new Converter that converts a Travis | ||
// pipeline to a Harness v1 pipeline. | ||
func New(options ...Option) *Converter { | ||
d := new(Converter) | ||
|
||
// create the unique identifier store. this store | ||
// is used for registering unique identifiers to | ||
// prevent duplicate names, unique index violations. | ||
d.identifiers = store.New() | ||
|
||
// loop through and apply the options. | ||
for _, option := range options { | ||
option(d) | ||
} | ||
|
||
// set the default kubernetes namespace. | ||
if d.kubeNamespace == "" { | ||
d.kubeNamespace = "default" | ||
} | ||
|
||
// set default kubernetes OS | ||
if d.kubeOs == "" { | ||
d.kubeOs = "Linux" | ||
} | ||
|
||
// set the runtime to kubernetes if the kubernetes | ||
// connector is configured. | ||
if d.kubeConnector != "" { | ||
d.kubeEnabled = true | ||
} | ||
|
||
// set default docker connector | ||
if d.dockerhubConn == "" { | ||
d.dockerhubConn = "account.harnessImage" | ||
} | ||
|
||
return d | ||
} | ||
|
||
// Convert converts a rio pipeline to v0. | ||
func (d *Converter) Convert(r io.Reader) ([]byte, error) { | ||
config, err := rio.Parse(r) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return d.convert(&context{ | ||
config: config, | ||
}) | ||
} | ||
|
||
// ConvertBytes converts a rio pipeline to v0. | ||
func (d *Converter) ConvertBytes(b []byte) ([]byte, error) { | ||
return d.Convert( | ||
bytes.NewBuffer(b), | ||
) | ||
} | ||
|
||
// ConvertString converts a rio pipeline to v0. | ||
func (d *Converter) ConvertString(s string) ([]byte, error) { | ||
return d.Convert( | ||
bytes.NewBufferString(s), | ||
) | ||
} | ||
|
||
// ConvertFile converts a rio pipeline to v0. | ||
func (d *Converter) ConvertFile(p string) ([]byte, error) { | ||
f, err := os.Open(p) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer f.Close() | ||
return d.Convert(f) | ||
} | ||
|
||
func (d *Converter) convertRunStep(p rio.Pipeline) harness.StepRun { | ||
step := new(harness.StepRun) | ||
step.Env = p.Machine.Env | ||
command := "" | ||
for _, s := range p.Build.Steps { | ||
command += fmt.Sprintf("%s\n", s) | ||
} | ||
step.Command = command | ||
step.Shell = "Sh" | ||
step.ConnRef = d.dockerhubConn | ||
step.Image = p.Machine.BaseImage | ||
return *step | ||
} | ||
|
||
func (d *Converter) convertDockerSteps(dockerfile rio.Dockerfile) []harness.StepDocker { | ||
steps := make([]harness.StepDocker, 0) | ||
for _, r := range dockerfile.Publish { | ||
step := new(harness.StepDocker) | ||
step.Context = dockerfile.Context | ||
step.Dockerfile = dockerfile.DockerfilePath | ||
step.Repo = r.Repo | ||
step.Tags = []string{dockerfile.Version} | ||
step.BuildsArgs = dockerfile.Env | ||
step.ConnectorRef = d.dockerhubConn | ||
steps = append(steps, *step) | ||
} | ||
return steps | ||
} | ||
|
||
func (d *Converter) convertExecution(p rio.Pipeline) harness.Execution { | ||
execution := harness.Execution{} | ||
|
||
executionSteps := make([]*harness.Steps, 0) | ||
// Append all commands in build attribute to one run step | ||
if len(p.Build.Steps) != 0 { | ||
steps := harness.Steps{ | ||
Step: &harness.Step{ | ||
Name: "run", | ||
ID: "run", | ||
Spec: d.convertRunStep(p), | ||
Type: "Run", | ||
}, | ||
} | ||
executionSteps = append(executionSteps, &steps) | ||
} | ||
|
||
dockerStepCounter := 1 | ||
if len(p.Pkg.Dockerfile) != 0 { | ||
if !p.Pkg.Release { | ||
fmt.Println("# [WARN]: release=false is not supported") | ||
} | ||
|
||
// Each entry in package.Dockerfile attribute is one build and push step | ||
for _, dockerfile := range p.Pkg.Dockerfile { | ||
// each dockerfile entry can have multiple repos | ||
dockerSteps := d.convertDockerSteps(dockerfile) | ||
|
||
// Append all docker steps | ||
for _, dStep := range dockerSteps { | ||
steps := harness.Steps{ | ||
Step: &harness.Step{ | ||
Name: fmt.Sprintf("docker_build_and_push_%d", dockerStepCounter), | ||
ID: fmt.Sprintf("docker_build_and_push_%d", dockerStepCounter), | ||
Spec: &dStep, | ||
Type: "BuildAndPushDockerRegistry", | ||
}, | ||
} | ||
executionSteps = append(executionSteps, &steps) | ||
dockerStepCounter++ | ||
} | ||
} | ||
} | ||
execution.Steps = executionSteps | ||
return execution | ||
} | ||
|
||
func (d *Converter) convertCIStage(p rio.Pipeline) harness.StageCI { | ||
stage := harness.StageCI{ | ||
Execution: d.convertExecution(p), | ||
} | ||
if d.kubeEnabled { | ||
infra := harness.Infrastructure{ | ||
Type: "KubernetesDirect", | ||
Spec: &harness.InfraSpec{ | ||
Namespace: d.kubeNamespace, | ||
Conn: d.kubeConnector, | ||
AutomountServiceToken: true, | ||
Os: d.kubeOs, | ||
}, | ||
} | ||
stage.Infrastructure = &infra | ||
} | ||
return stage | ||
} | ||
|
||
func convertNameToID(name string) string { | ||
ID := strings.ReplaceAll(name, " ", "_") | ||
ID = strings.ReplaceAll(ID, "-", "_") | ||
return ID | ||
} | ||
|
||
// converts converts a Travis pipeline to a Harness pipeline. | ||
func (d *Converter) convert(ctx *context) ([]byte, error) { | ||
// create the harness pipeline spec | ||
pipeline := &harness.Pipeline{} | ||
for _, p := range ctx.config.Pipelines { | ||
stage := harness.Stages{ | ||
Stage: &harness.Stage{ | ||
Name: p.Name, | ||
ID: convertNameToID(p.Name), | ||
Spec: d.convertCIStage(p), | ||
Type: "CI", | ||
}, | ||
} | ||
pipeline.Stages = append(pipeline.Stages, &stage) | ||
} | ||
pipeline.Name = d.pipelineName | ||
pipeline.ID = d.pipelineId | ||
pipeline.Org = d.pipelineOrg | ||
pipeline.Project = d.pipelineProj | ||
|
||
// create the harness pipeline resource | ||
config := &harness.Config{Pipeline: *pipeline} | ||
|
||
// marshal the harness yaml | ||
out, err := yaml.Marshal(config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return out, nil | ||
} |
Oops, something went wrong.