First version
This commit is contained in:
commit
f13d7e9651
6 changed files with 227 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
*.exe
|
||||
.drone.yml
|
47
README.md
Normal file
47
README.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# drone-add
|
||||
|
||||
Easily add Drone.io to projects using Drone APIs and YAML templates.
|
||||
|
||||
## Getting started
|
||||
|
||||
### Install drone-add
|
||||
|
||||
```sh
|
||||
go get -u git.fromouter.space/Hamcha/drone-add
|
||||
```
|
||||
|
||||
or, if you have cloned the project locally, just `cd` to it and:
|
||||
|
||||
```sh
|
||||
go install .
|
||||
```
|
||||
|
||||
### Set environment variables
|
||||
|
||||
To authenticate with Drone you'll need to get your user token.
|
||||
If you have the `drone` CLI tool, the environment variables are the same (`DRONE_SERVER` / `DRONE_TOKEN`).
|
||||
|
||||
If you have drone secret you want to add, set them as environment variables using this format:
|
||||
|
||||
`DRONE_SECRET_SECRET_NAME` → `secret_name`
|
||||
|
||||
You can use template literals in your secrets, for example:
|
||||
|
||||
`DRONE_SECRET_DOCKER_REPO = "my-custom-registry.tld/{{.Namespace}}/{{.Name}}"` with project `testorg/my-repo` will create a secret called `docker_repo` with value `my-custom-registry.tld/testorg/my-repo`
|
||||
|
||||
### Change the template
|
||||
|
||||
If you have not downloaded the project locally, download the template file from [here](https://git.fromouter.space/Hamcha/drone-add/raw/branch/master/template.yml).
|
||||
|
||||
Change the template to fit what a starting `.drone.yml` for your projects would be like.
|
||||
Usually this means just populating common steps (like publish and deployment steps).
|
||||
|
||||
You can also use template literals in the template.
|
||||
|
||||
### Run the tool
|
||||
|
||||
Usage:
|
||||
|
||||
```sh
|
||||
drone-add [-t template.yml] [-o .drone.yml] namespace/repository
|
||||
```
|
8
go.mod
Normal file
8
go.mod
Normal file
|
@ -0,0 +1,8 @@
|
|||
module git.fromouter.space/Hamcha/drone-add
|
||||
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/drone/drone-go v1.1.0
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
|
||||
)
|
16
go.sum
Normal file
16
go.sum
Normal file
|
@ -0,0 +1,16 @@
|
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/99designs/httpsignatures-go v0.0.0-20170731043157-88528bf4ca7e/go.mod h1:Xa6lInWHNQnuWoF0YPSsx+INFA9qk7/7pTjwb3PInkY=
|
||||
github.com/drone/drone-go v1.1.0 h1:2mritc5b7PhQWvILNyzaImZMRWVbMmmZ5Q0UDwwO7SI=
|
||||
github.com/drone/drone-go v1.1.0/go.mod h1:GxyeGClYohaKNYJv/ZpsmVHtMJ7WhoT+uDaJNcDIrk4=
|
||||
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45 h1:SVwTIAaPC2U/AvvLNZ2a7OVsmBpC8L5BlwK1whH3hm0=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
133
main.go
Normal file
133
main.go
Normal file
|
@ -0,0 +1,133 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/drone/drone-go/drone"
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
const secretEnvPrefix = "DRONE_SECRET_"
|
||||
|
||||
func main() {
|
||||
tplpath := flag.String("t", "template.yml", "Template file")
|
||||
outpath := flag.String("o", ".drone.yml", "Output .drone.yml")
|
||||
flag.Parse()
|
||||
|
||||
// Get drone server and token
|
||||
|
||||
server := os.Getenv("DRONE_SERVER")
|
||||
if server == "" {
|
||||
fatal("DRONE_SERVER missing or empty")
|
||||
}
|
||||
|
||||
token := os.Getenv("DRONE_TOKEN")
|
||||
if token == "" {
|
||||
fatal("DRONE_TOKEN missing or empty")
|
||||
}
|
||||
|
||||
// Authenticate and connect to drone.io server
|
||||
|
||||
config := new(oauth2.Config)
|
||||
auther := config.Client(
|
||||
oauth2.NoContext,
|
||||
&oauth2.Token{
|
||||
AccessToken: token,
|
||||
},
|
||||
)
|
||||
|
||||
client := drone.NewClient(server, auther)
|
||||
|
||||
user, err := client.Self()
|
||||
if err != nil {
|
||||
fatal("Connection to drone.io failed: %s", err.Error())
|
||||
}
|
||||
|
||||
// Get project
|
||||
|
||||
projectname := flag.Arg(0)
|
||||
if projectname == "" {
|
||||
fatal("Repository name missing or empty")
|
||||
}
|
||||
|
||||
parts := strings.SplitN(projectname, "/", 2)
|
||||
if len(parts) < 2 {
|
||||
parts = []string{user.Login, projectname}
|
||||
}
|
||||
namespace := parts[0]
|
||||
reponame := parts[1]
|
||||
|
||||
// Enable repository on Drone.io
|
||||
repo, err := client.RepoEnable(namespace, reponame)
|
||||
if err != nil {
|
||||
fatal("Error enabling repository %s/%s: %s", namespace, reponame, err.Error())
|
||||
}
|
||||
|
||||
// Get secrets
|
||||
|
||||
for _, env := range os.Environ() {
|
||||
// Check for the magic prefix
|
||||
if !strings.HasPrefix(env, secretEnvPrefix) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Split key=val
|
||||
parts := strings.SplitN(env, "=", 2)
|
||||
|
||||
// Ignore weird values
|
||||
if len(parts) < 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
secretName := strings.ToLower(parts[0][len(secretEnvPrefix):])
|
||||
secretValue := parts[1]
|
||||
|
||||
tpl, err := template.New("secret-" + secretName).Parse(secretValue)
|
||||
if err != nil {
|
||||
fatal("Secret %s is an invalid template: %s", parts[0], err.Error())
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
err = tpl.Execute(&builder, repo)
|
||||
if err != nil {
|
||||
fatal("Error while building secret %s: %s", secretName, err.Error())
|
||||
}
|
||||
|
||||
// Add secret to project
|
||||
client.SecretCreate(repo.Namespace, repo.Name, &drone.Secret{
|
||||
Name: secretName,
|
||||
Data: secretValue,
|
||||
})
|
||||
}
|
||||
|
||||
// Read template file
|
||||
|
||||
tpl, err := template.ParseFiles(*tplpath)
|
||||
if err != nil {
|
||||
fatal("Cannot read template file: %s", err.Error())
|
||||
}
|
||||
|
||||
// Create output file
|
||||
|
||||
outfile, err := os.Create(*outpath)
|
||||
if err != nil {
|
||||
fatal("Cannot create output file: %s", err.Error())
|
||||
}
|
||||
defer outfile.Close()
|
||||
|
||||
// Generate output from template
|
||||
|
||||
err = tpl.Execute(outfile, repo)
|
||||
if err != nil {
|
||||
fatal("Error processing template: %s", err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func fatal(msg string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, "FATAL: "+msg+"\n", args...)
|
||||
os.Exit(1)
|
||||
}
|
21
template.yml
Normal file
21
template.yml
Normal file
|
@ -0,0 +1,21 @@
|
|||
kind: pipeline
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: publish
|
||||
image: plugins/docker
|
||||
settings:
|
||||
auto_tag: true
|
||||
registry:
|
||||
from_secret: docker_registry
|
||||
repo:
|
||||
from_secret: docker_repo
|
||||
username:
|
||||
from_secret: docker_username
|
||||
password:
|
||||
from_secret: docker_password
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
- tag
|
||||
branch: master
|
Loading…
Reference in a new issue