woodpecker/cncd/pipeline/pipec/compile.go

508 lines
11 KiB
Go

package main
import (
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"strings"
"github.com/woodpecker-ci/woodpecker/cncd/pipeline/pipeline/frontend"
"github.com/woodpecker-ci/woodpecker/cncd/pipeline/pipeline/frontend/yaml"
"github.com/woodpecker-ci/woodpecker/cncd/pipeline/pipeline/frontend/yaml/compiler"
"github.com/urfave/cli"
)
var compileCommand = cli.Command{
Name: "compile",
Usage: "compile the yaml file",
Action: compileAction,
Flags: []cli.Flag{
cli.StringFlag{
Name: "in",
Value: "pipeline.yml",
},
cli.StringFlag{
Name: "out",
Value: "pipeline.json",
},
cli.StringSliceFlag{
Name: "volumes",
},
cli.StringSliceFlag{
Name: "privileged",
Value: &cli.StringSlice{
"plugins/docker",
"plugins/gcr",
"plugins/ecr",
},
},
cli.StringFlag{
Name: "prefix",
Value: "pipeline",
},
cli.BoolFlag{
Name: "local",
},
//
// volume caching
//
cli.BoolFlag{
Name: "volume-cache",
EnvVar: "CI_VOLUME_CACHE",
},
cli.StringFlag{
Name: "volume-cache-base",
Value: "/var/lib/drone",
EnvVar: "CI_VOLUME_CACHE_BASE",
},
//
// s3 caching
//
cli.BoolFlag{
Name: "aws-cache",
EnvVar: "CI_AWS_CACHE",
},
cli.StringFlag{
Name: "aws-region",
EnvVar: "AWS_REGION",
},
cli.StringFlag{
Name: "aws-bucket",
EnvVar: "AWS_BUCKET",
},
cli.StringFlag{
Name: "aws-access-key-id",
EnvVar: "AWS_ACCESS_KEY_ID",
},
cli.StringFlag{
Name: "aws-secret-access-key",
EnvVar: "AWS_SECRET_ACCESS_KEY",
},
//
// registry credentials
//
cli.StringFlag{
Name: "registry-hostname",
EnvVar: "CI_REGISTRY_HOSTNAME",
},
cli.StringFlag{
Name: "registry-username",
EnvVar: "CI_REGISTRY_USERNAME",
},
cli.StringFlag{
Name: "registry-password",
EnvVar: "CI_REGISTRY_PASSWORD",
},
//
// workspace default
//
cli.StringFlag{
Name: "workspace-base",
Value: "/pipeline",
},
cli.StringFlag{
Name: "workspace-path",
Value: "src",
},
//
// netrc parameters
//
cli.StringFlag{
Name: "netrc-username",
EnvVar: "CI_NETRC_USERNAME",
},
cli.StringFlag{
Name: "netrc-password",
EnvVar: "CI_NETRC_PASSWORD",
},
cli.StringFlag{
Name: "netrc-machine",
EnvVar: "CI_NETRC_MACHINE",
},
//
// resource limit parameters
//
cli.Int64Flag{
Name: "limit-mem-swap",
EnvVar: "CI_LIMIT_MEM_SWAP",
},
cli.Int64Flag{
Name: "limit-mem",
EnvVar: "CI_LIMIT_MEM",
},
cli.Int64Flag{
Name: "limit-shm-size",
EnvVar: "CI_LIMIT_SHM_SIZE",
},
cli.Int64Flag{
Name: "limit-cpu-quota",
EnvVar: "CI_LIMIT_CPU_QUOTA",
},
cli.Int64Flag{
Name: "limit-cpu-shares",
EnvVar: "CI_LIMIT_CPU_SHARES",
},
cli.StringFlag{
Name: "limit-cpu-set",
EnvVar: "CI_LIMIT_CPU_SET",
},
//
// metadata parameters
//
cli.StringFlag{
Name: "system-arch",
Value: "linux/amd64",
EnvVar: "CI_SYSTEM_ARCH",
},
cli.StringFlag{
Name: "system-name",
Value: "pipec",
EnvVar: "CI_SYSTEM_NAME",
},
cli.StringFlag{
Name: "system-link",
Value: "https://github.com/cncd/pipec",
EnvVar: "CI_SYSTEM_LINK",
},
cli.StringFlag{
Name: "repo-name",
EnvVar: "CI_REPO_NAME",
},
cli.StringFlag{
Name: "repo-link",
EnvVar: "CI_REPO_LINK",
},
cli.StringFlag{
Name: "repo-remote-url",
EnvVar: "CI_REPO_REMOTE",
},
cli.StringFlag{
Name: "repo-private",
EnvVar: "CI_REPO_PRIVATE",
},
cli.IntFlag{
Name: "build-number",
EnvVar: "CI_BUILD_NUMBER",
},
cli.Int64Flag{
Name: "build-created",
EnvVar: "CI_BUILD_CREATED",
},
cli.Int64Flag{
Name: "build-started",
EnvVar: "CI_BUILD_STARTED",
},
cli.Int64Flag{
Name: "build-finished",
EnvVar: "CI_BUILD_FINISHED",
},
cli.StringFlag{
Name: "build-status",
EnvVar: "CI_BUILD_STATUS",
},
cli.StringFlag{
Name: "build-event",
EnvVar: "CI_BUILD_EVENT",
},
cli.StringFlag{
Name: "build-link",
EnvVar: "CI_BUILD_LINK",
},
cli.StringFlag{
Name: "build-target",
EnvVar: "CI_BUILD_TARGET",
},
cli.StringFlag{
Name: "commit-sha",
EnvVar: "CI_COMMIT_SHA",
},
cli.StringFlag{
Name: "commit-ref",
EnvVar: "CI_COMMIT_REF",
},
cli.StringFlag{
Name: "commit-refspec",
EnvVar: "CI_COMMIT_REFSPEC",
},
cli.StringFlag{
Name: "commit-branch",
EnvVar: "CI_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "commit-message",
EnvVar: "CI_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "commit-author-name",
EnvVar: "CI_COMMIT_AUTHOR_NAME",
},
cli.StringFlag{
Name: "commit-author-avatar",
EnvVar: "CI_COMMIT_AUTHOR_AVATAR",
},
cli.StringFlag{
Name: "commit-author-email",
EnvVar: "CI_COMMIT_AUTHOR_EMAIL",
},
cli.IntFlag{
Name: "prev-build-number",
EnvVar: "CI_PREV_BUILD_NUMBER",
},
cli.Int64Flag{
Name: "prev-build-created",
EnvVar: "CI_PREV_BUILD_CREATED",
},
cli.Int64Flag{
Name: "prev-build-started",
EnvVar: "CI_PREV_BUILD_STARTED",
},
cli.Int64Flag{
Name: "prev-build-finished",
EnvVar: "CI_PREV_BUILD_FINISHED",
},
cli.StringFlag{
Name: "prev-build-status",
EnvVar: "CI_PREV_BUILD_STATUS",
},
cli.StringFlag{
Name: "prev-build-event",
EnvVar: "CI_PREV_BUILD_EVENT",
},
cli.StringFlag{
Name: "prev-build-link",
EnvVar: "CI_PREV_BUILD_LINK",
},
cli.StringFlag{
Name: "prev-commit-sha",
EnvVar: "CI_PREV_COMMIT_SHA",
},
cli.StringFlag{
Name: "prev-commit-ref",
EnvVar: "CI_PREV_COMMIT_REF",
},
cli.StringFlag{
Name: "prev-commit-refspec",
EnvVar: "CI_PREV_COMMIT_REFSPEC",
},
cli.StringFlag{
Name: "prev-commit-branch",
EnvVar: "CI_PREV_COMMIT_BRANCH",
},
cli.StringFlag{
Name: "prev-commit-message",
EnvVar: "CI_PREV_COMMIT_MESSAGE",
},
cli.StringFlag{
Name: "prev-commit-author-name",
EnvVar: "CI_PREV_COMMIT_AUTHOR_NAME",
},
cli.StringFlag{
Name: "prev-commit-author-avatar",
EnvVar: "CI_PREV_COMMIT_AUTHOR_AVATAR",
},
cli.StringFlag{
Name: "prev-commit-author-email",
EnvVar: "CI_PREV_COMMIT_AUTHOR_EMAIL",
},
cli.IntFlag{
Name: "job-number",
EnvVar: "CI_JOB_NUMBER",
},
// cli.StringFlag{
// Name: "job-matrix",
// EnvVar: "CI_JOB_MATRIX",
// },
},
}
func compileAction(c *cli.Context) (err error) {
file := c.Args().First()
if file == "" {
file = c.String("in")
}
conf, err := yaml.ParseFile(file)
if err != nil {
return err
}
// configure volumes for local execution
volumes := c.StringSlice("volumes")
if c.Bool("local") {
var (
workspaceBase = conf.Workspace.Base
workspacePath = conf.Workspace.Path
)
if workspaceBase == "" {
workspaceBase = c.String("workspace-base")
}
if workspacePath == "" {
workspacePath = c.String("workspace-path")
}
dir, _ := filepath.Abs(filepath.Dir(file))
volumes = append(volumes, dir+":"+path.Join(workspaceBase, workspacePath))
}
// secrets from environment variable
var secrets []compiler.Secret
for _, env := range os.Environ() {
parts := strings.Split(env, "=")
secrets = append(secrets, compiler.Secret{
Name: parts[0],
Value: parts[1],
})
}
// compiles the yaml file
compiled := compiler.New(
compiler.WithResourceLimit(
c.Int64("limit-mem-swap"),
c.Int64("limit-mem"),
c.Int64("limit-shm-size"),
c.Int64("limit-cpu-quota"),
c.Int64("limit-cpu-shares"),
c.String("limit-cpu-set"),
),
compiler.WithRegistry(
compiler.Registry{
Hostname: c.String("registry-hostname"),
Username: c.String("registry-username"),
Password: c.String("registry-password"),
},
),
compiler.WithEscalated(
c.StringSlice("privileged")...,
),
compiler.WithSecret(secrets...),
compiler.WithVolumes(volumes...),
compiler.WithWorkspace(
c.String("workspace-base"),
c.String("workspace-path"),
),
compiler.WithPrefix(
c.String("prefix"),
),
compiler.WithProxy(),
compiler.WithLocal(
c.Bool("local"),
),
compiler.WithNetrc(
c.String("netrc-username"),
c.String("netrc-password"),
c.String("netrc-machine"),
),
compiler.WithMetadata(
metadataFromContext(c),
),
compiler.WithOption(
compiler.WithVolumeCacher(
c.String("volume-cache-base"),
),
c.Bool("volume-cache"),
),
compiler.WithOption(
compiler.WithS3Cacher(
c.String("aws-access-key-id"),
c.String("aws-secret-access-key"),
c.String("aws-region"),
c.String("aws-bucket"),
),
c.Bool("aws-cache"),
),
).Compile(conf)
// marshal the compiled spec to formatted yaml
out, err := json.MarshalIndent(compiled, "", " ")
if err != nil {
return err
}
// create output file with option to dump to stdout
var writer = os.Stdout
output := c.String("out")
if output != "-" {
writer, err = os.Create(output)
if err != nil {
return err
}
}
defer writer.Close()
_, err = writer.Write(out)
if err != nil {
return err
}
if writer != os.Stdout {
fmt.Fprintf(os.Stdout, "Successfully compiled %s to %s\n", file, output)
}
return nil
}
// return the metadata from the cli context.
func metadataFromContext(c *cli.Context) frontend.Metadata {
return frontend.Metadata{
Repo: frontend.Repo{
Name: c.String("repo-name"),
Link: c.String("repo-link"),
Remote: c.String("repo-remote-url"),
Private: c.Bool("repo-private"),
},
Curr: frontend.Build{
Number: c.Int("build-number"),
Created: c.Int64("build-created"),
Started: c.Int64("build-started"),
Finished: c.Int64("build-finished"),
Status: c.String("build-status"),
Event: c.String("build-event"),
Link: c.String("build-link"),
Target: c.String("build-target"),
Commit: frontend.Commit{
Sha: c.String("commit-sha"),
Ref: c.String("commit-ref"),
Refspec: c.String("commit-refspec"),
Branch: c.String("commit-branch"),
Message: c.String("commit-message"),
Author: frontend.Author{
Name: c.String("commit-author-name"),
Email: c.String("commit-author-email"),
Avatar: c.String("commit-author-avatar"),
},
},
},
Prev: frontend.Build{
Number: c.Int("prev-build-number"),
Created: c.Int64("prev-build-created"),
Started: c.Int64("prev-build-started"),
Finished: c.Int64("prev-build-finished"),
Status: c.String("prev-build-status"),
Event: c.String("prev-build-event"),
Link: c.String("prev-build-link"),
Commit: frontend.Commit{
Sha: c.String("prev-commit-sha"),
Ref: c.String("prev-commit-ref"),
Refspec: c.String("prev-commit-refspec"),
Branch: c.String("prev-commit-branch"),
Message: c.String("prev-commit-message"),
Author: frontend.Author{
Name: c.String("prev-commit-author-name"),
Email: c.String("prev-commit-author-email"),
Avatar: c.String("prev-commit-author-avatar"),
},
},
},
Job: frontend.Job{
Number: c.Int("job-number"),
// Matrix: ,
},
Sys: frontend.System{
Name: c.String("system-name"),
Link: c.String("system-link"),
Arch: c.String("system-arch"),
},
}
}