mirror of
https://github.com/harness-community/drone-helm-chart-container-registry.git
synced 2026-06-04 10:15:18 +08:00
using boilr template
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
// Copyright 2020 the Drone Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Blue Oak Model License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package plugin
|
||||
|
||||
// Pipeline provides Pipeline metadata from the environment.
|
||||
type Pipeline struct {
|
||||
// Build provides build metadata.
|
||||
Build struct {
|
||||
Branch string `envconfig:"DRONE_BUILD_BRANCH"`
|
||||
Number int `envconfig:"DRONE_BUILD_NUMBER"`
|
||||
Parent int `envconfig:"DRONE_BUILD_PARENT"`
|
||||
Event string `envconfig:"DRONE_BUILD_EVENT"`
|
||||
Action string `envconfig:"DRONE_BUILD_ACTION"`
|
||||
Status string `envconfig:"DRONE_BUILD_STATUS"`
|
||||
Created int64 `envconfig:"DRONE_BUILD_CREATED"`
|
||||
Started int64 `envconfig:"DRONE_BUILD_STARTED"`
|
||||
Finished int64 `envconfig:"DRONE_BUILD_FINISHED"`
|
||||
Link string `envconfig:"DRONE_BUILD_LINK"`
|
||||
}
|
||||
|
||||
// Calver provides the calver details parsed from the
|
||||
// git tag. If the git tag is empty or is not a valid
|
||||
// calver, the values will be empty.
|
||||
Calver struct {
|
||||
Version string `envconfig:"DRONE_CALVER"`
|
||||
Short string `envconfig:"DRONE_CALVER_SHORT"`
|
||||
MajorMinor string `envconfig:"DRONE_CALVER_MAJOR_MINOR"`
|
||||
Major string `envconfig:"DRONE_CALVER_MAJOR"`
|
||||
Minor string `envconfig:"DRONE_CALVER_MINOR"`
|
||||
Micro string `envconfig:"DRONE_CALVER_MICRO"`
|
||||
Modifier string `envconfig:"DRONE_CALVER_MODIFIER"`
|
||||
}
|
||||
|
||||
// Card provides adaptive card configuration options.
|
||||
Card struct {
|
||||
Path string `envconfig:"DRONE_CARD_PATH"`
|
||||
}
|
||||
|
||||
// Commit provides the commit metadata.
|
||||
Commit struct {
|
||||
Rev string `envconfig:"DRONE_COMMIT_SHA"`
|
||||
Before string `envconfig:"DRONE_COMMIT_BEFORE"`
|
||||
After string `envconfig:"DRONE_COMMIT_AFTER"`
|
||||
Ref string `envconfig:"DRONE_COMMIT_REF"`
|
||||
Branch string `envconfig:"DRONE_COMMIT_BRANCH"`
|
||||
Source string `envconfig:"DRONE_COMMIT_SOURCE"`
|
||||
Target string `envconfig:"DRONE_COMMIT_TARGET"`
|
||||
Link string `envconfig:"DRONE_COMMIT_LINK"`
|
||||
Message string `envconfig:"DRONE_COMMIT_MESSAGE"`
|
||||
|
||||
Author struct {
|
||||
Username string `envconfig:"DRONE_COMMIT_AUTHOR"`
|
||||
Name string `envconfig:"DRONE_COMMIT_AUTHOR_NAME"`
|
||||
Email string `envconfig:"DRONE_COMMIT_AUTHOR_EMAIL"`
|
||||
Avatar string `envconfig:"DRONE_COMMIT_AUTHOR_AVATAR"`
|
||||
}
|
||||
}
|
||||
|
||||
// Deploy provides the deployment metadata.
|
||||
Deploy struct {
|
||||
ID string `envconfig:"DRONE_DEPLOY_TO"`
|
||||
Target string `envconfig:"DRONE_DEPLOY_ID"`
|
||||
}
|
||||
|
||||
// Failed provides a list of failed steps and failed stages
|
||||
// for the current pipeline.
|
||||
Failed struct {
|
||||
Steps []string `envconfig:"DRONE_FAILED_STEPS"`
|
||||
Stages []string `envconfig:"DRONE_FAILED_STAGES"`
|
||||
}
|
||||
|
||||
// Git provides the git repository metadata.
|
||||
Git struct {
|
||||
HTTPURL string `envconfig:"DRONE_GIT_HTTP_URL"`
|
||||
SSHURL string `envconfig:"DRONE_GIT_SSH_URL"`
|
||||
}
|
||||
|
||||
// PullRequest provides the pull request metadata.
|
||||
PullRequest struct {
|
||||
Number int `envconfig:"DRONE_PULL_REQUEST"`
|
||||
}
|
||||
|
||||
// Repo provides the repository metadata.
|
||||
Repo struct {
|
||||
Branch string `envconfig:"DRONE_REPO_BRANCH"`
|
||||
Link string `envconfig:"DRONE_REPO_LINK"`
|
||||
Namespace string `envconfig:"DRONE_REPO_NAMESPACE"`
|
||||
Name string `envconfig:"DRONE_REPO_NAME"`
|
||||
Private bool `envconfig:"DRONE_REPO_PRIVATE"`
|
||||
Remote string `envconfig:"DRONE_GIT_HTTP_URL"`
|
||||
SCM string `envconfig:"DRONE_REPO_SCM"`
|
||||
Slug string `envconfig:"DRONE_REPO"`
|
||||
Visibility string `envconfig:"DRONE_REPO_VISIBILITY"`
|
||||
}
|
||||
|
||||
// Stage provides the stage metadata.
|
||||
Stage struct {
|
||||
Kind string `envconfig:"DRONE_STAGE_KIND"`
|
||||
Type string `envconfig:"DRONE_STAGE_TYPE"`
|
||||
Name string `envconfig:"DRONE_STAGE_NAME"`
|
||||
Number int `envconfig:"DRONE_STAGE_NUMBER"`
|
||||
Machine string `envconfig:"DRONE_STAGE_MACHINE"`
|
||||
OS string `envconfig:"DRONE_STAGE_OS"`
|
||||
Arch string `envconfig:"DRONE_STAGE_ARCH"`
|
||||
Variant string `envconfig:"DRONE_STAGE_VARIANT"`
|
||||
Status string `envconfig:"DRONE_STAGE_STATUS"`
|
||||
Started int64 `envconfig:"DRONE_STAGE_STARTED"`
|
||||
Finished int64 `envconfig:"DRONE_STAGE_FINISHED"`
|
||||
DependsOn []string `envconfig:"DRONE_STAGE_DEPENDS_ON"`
|
||||
}
|
||||
|
||||
// Step provides the step metadata.
|
||||
Step struct {
|
||||
Number int `envconfig:"DRONE_STEP_NUMBER"`
|
||||
Name string `envconfig:"DRONE_STEP_NAME"`
|
||||
}
|
||||
|
||||
// Semver provides the semver details parsed from the
|
||||
// git tag. If the git tag is empty or is not a valid
|
||||
// semver, the values will be empty and the error field
|
||||
// will be populated with the parsing error.
|
||||
Semver struct {
|
||||
Version string `envconfig:"DRONE_SEMVER"`
|
||||
Short string `envconfig:"DRONE_SEMVER_SHORT"`
|
||||
Major string `envconfig:"DRONE_SEMVER_MAJOR"`
|
||||
Minor string `envconfig:"DRONE_SEMVER_MINOR"`
|
||||
Patch string `envconfig:"DRONE_SEMVER_PATCH"`
|
||||
Build string `envconfig:"DRONE_SEMVER_BUILD"`
|
||||
PreRelease string `envconfig:"DRONE_SEMVER_PRERELEASE"`
|
||||
Error string `envconfig:"DRONE_SEMVER_ERROR"`
|
||||
}
|
||||
|
||||
// System provides the Drone system metadata, including
|
||||
// the system version of details required to create the
|
||||
// drone website address.
|
||||
System struct {
|
||||
Proto string `envconfig:"DRONE_SYSTEM_PROTO"`
|
||||
Host string `envconfig:"DRONE_SYSTEM_HOST"`
|
||||
Hostname string `envconfig:"DRONE_SYSTEM_HOSTNAME"`
|
||||
Version string `envconfig:"DRONE_SYSTEM_VERSION"`
|
||||
}
|
||||
|
||||
// Tag provides the git tag details.
|
||||
Tag struct {
|
||||
Name string `envconfig:"DRONE_TAG"`
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
// Copyright 2020 the Drone Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Blue Oak Model License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"helm.sh/helm/v3/pkg/action"
|
||||
"helm.sh/helm/v3/pkg/cli"
|
||||
"helm.sh/helm/v3/pkg/downloader"
|
||||
"helm.sh/helm/v3/pkg/getter"
|
||||
"helm.sh/helm/v3/pkg/registry"
|
||||
)
|
||||
|
||||
// Args provides plugin execution arguments.
|
||||
type Args struct {
|
||||
Pipeline
|
||||
|
||||
// Level defines the plugin log level.
|
||||
Level string `envconfig:"PLUGIN_LOG_LEVEL"`
|
||||
|
||||
RegistryUrl string `envconfig:"PLUGIN_REGISTRY_URL"`
|
||||
Username string `envconfig:"PLUGIN_REGISTRY_USERNAME"`
|
||||
Password string `envconfig:"PLUGIN_REGISTRY_PASSWORD"`
|
||||
ChartPath string `envconfig:"PLUGIN_CHART_PATH"`
|
||||
Namespace string `envconfig:"PLUGIN_REGISTRY_NAMESPACE"`
|
||||
ProjectId string `envconfig:"PLUGIN_PROJECT_ID"`
|
||||
}
|
||||
|
||||
// Exec executes the plugin.
|
||||
func Exec(ctx context.Context, args Args) error {
|
||||
if err := VerifyArgs(&args); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
packageRun, err := packageChart(&args)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
opts := []registry.ClientOption{
|
||||
registry.ClientOptWriter(os.Stdout),
|
||||
}
|
||||
|
||||
err = registryLogin(&args, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = registryPush(&args, opts, packageRun)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func VerifyArgs(args *Args) error {
|
||||
if args.RegistryUrl == "" {
|
||||
return fmt.Errorf("registry url is required")
|
||||
}
|
||||
if args.Username == "" {
|
||||
return fmt.Errorf("username is required")
|
||||
}
|
||||
if args.Password == "" {
|
||||
return fmt.Errorf("password is required")
|
||||
}
|
||||
if args.ChartPath == "" {
|
||||
return fmt.Errorf("chart path is required")
|
||||
}
|
||||
if args.Namespace == "" {
|
||||
return fmt.Errorf("namespace is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func packageChart(args *Args) (string, error) {
|
||||
helmClient := action.NewPackage()
|
||||
helmClient.DependencyUpdate = true
|
||||
helmClient.Destination = args.ChartPath
|
||||
|
||||
settings := cli.New()
|
||||
getters := getter.All(settings)
|
||||
|
||||
registryClient, err := registry.NewClient()
|
||||
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to create registry client")
|
||||
}
|
||||
|
||||
downloadManager := &downloader.Manager{
|
||||
Out: os.Stdout,
|
||||
ChartPath: args.ChartPath,
|
||||
Debug: false,
|
||||
Getters: getters,
|
||||
RepositoryConfig: settings.RepositoryConfig,
|
||||
RepositoryCache: settings.RepositoryCache,
|
||||
RegistryClient: registryClient,
|
||||
}
|
||||
|
||||
if err := downloadManager.Build(); err != nil {
|
||||
return "", fmt.Errorf("failed to retrieve chart")
|
||||
}
|
||||
|
||||
packageRun, err := helmClient.Run(args.ChartPath, nil)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to package chart")
|
||||
}
|
||||
|
||||
fmt.Print("Successfully packaged chart\n")
|
||||
|
||||
return packageRun, nil
|
||||
}
|
||||
|
||||
func registryLogin(args *Args, opts []registry.ClientOption) error {
|
||||
registryClient, err := registry.NewClient(opts...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create registry client")
|
||||
}
|
||||
|
||||
cfg := new(action.Configuration)
|
||||
cfg.RegistryClient = registryClient
|
||||
|
||||
err = action.NewRegistryLogin(cfg).Run(
|
||||
os.Stdout,
|
||||
args.RegistryUrl,
|
||||
args.Username,
|
||||
args.Password,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to login to registry")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func registryPush(args *Args, opts []registry.ClientOption, packageRun string) error {
|
||||
registryClient, err := registry.NewClient(opts...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create registry client")
|
||||
}
|
||||
|
||||
cfg := new(action.Configuration)
|
||||
cfg.RegistryClient = registryClient
|
||||
|
||||
client := action.NewPushWithOpts(action.WithPushConfig(cfg))
|
||||
|
||||
settings := new(cli.EnvSettings)
|
||||
client.Settings = settings
|
||||
|
||||
var remoteURL string
|
||||
|
||||
if args.ProjectId != "" {
|
||||
remoteURL = fmt.Sprintf("oci://%s/%s/%s", args.RegistryUrl, args.ProjectId, args.Namespace)
|
||||
} else {
|
||||
remoteURL = fmt.Sprintf("oci://%s/%s", args.RegistryUrl, args.Namespace)
|
||||
}
|
||||
|
||||
_, err = client.Run(packageRun, remoteURL)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to push chart")
|
||||
}
|
||||
|
||||
fmt.Print("Successfully pushed chart\n")
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
// Copyright 2020 the Drone Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Blue Oak Model License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"helm.sh/helm/v3/pkg/registry"
|
||||
)
|
||||
|
||||
func TestVerifyArgs(t *testing.T) {
|
||||
var err error
|
||||
|
||||
err = VerifyArgs(&Args{
|
||||
RegistryUrl: "https://registry.hub.docker.com",
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
err = VerifyArgs(&Args{
|
||||
Username: "octocat",
|
||||
Password: "pass",
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
err = VerifyArgs(&Args{
|
||||
RegistryUrl: "https://registry.hub.docker.com",
|
||||
Username: "octocat",
|
||||
Password: "pass",
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPackageChart(t *testing.T) {
|
||||
var err error
|
||||
|
||||
_, err = packageChart(&Args{
|
||||
ChartPath: "test-chart",
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = packageChart(&Args{
|
||||
ChartPath: "test-chart-fail",
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryLogin(t *testing.T) {
|
||||
|
||||
err := registryLogin(&Args{
|
||||
RegistryUrl: "https://registry.hub.docker.com",
|
||||
Username: "octocat",
|
||||
Password: "pass",
|
||||
}, []registry.ClientOption{})
|
||||
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryPush(t *testing.T) {
|
||||
|
||||
err := registryPush(&Args{
|
||||
RegistryUrl: "https://registry.hub.docker.com",
|
||||
Username: "octocat",
|
||||
Password: "pass",
|
||||
}, []registry.ClientOption{}, "test-chart")
|
||||
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
apiVersion: v2
|
||||
name: mywebapp
|
||||
description: a simple web app
|
||||
version: 5.0.0
|
||||
appVersion: 5.0.0
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2020 the Drone Authors. All rights reserved.
|
||||
// Use of this source code is governed by the Blue Oak Model License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
func writeCard(path, schema string, card interface{}) {
|
||||
data, _ := json.Marshal(map[string]interface{}{
|
||||
"schema": schema,
|
||||
"data": card,
|
||||
})
|
||||
switch {
|
||||
case path == "/dev/stdout":
|
||||
writeCardTo(os.Stdout, data)
|
||||
case path == "/dev/stderr":
|
||||
writeCardTo(os.Stderr, data)
|
||||
case path != "":
|
||||
ioutil.WriteFile(path, data, 0644)
|
||||
}
|
||||
}
|
||||
|
||||
func writeCardTo(out io.Writer, data []byte) {
|
||||
encoded := base64.StdEncoding.EncodeToString(data)
|
||||
io.WriteString(out, "\u001B]1338;")
|
||||
io.WriteString(out, encoded)
|
||||
io.WriteString(out, "\u001B]0m")
|
||||
io.WriteString(out, "\n")
|
||||
}
|
||||
Reference in New Issue
Block a user