1
0
mirror of https://github.com/goreleaser/goreleaser.git synced 2025-03-17 20:47:50 +02:00

refactor: Introduced name per artifactory instance for identification

This introduced a new property per Artifactory instance: Name
With this name we are able to

a) identify a instance
b) use the name to identify the secret (instead of a number)
c) use this name for logging
This commit is contained in:
Andy Grunwald 2017-12-09 18:17:37 +01:00
parent 13fea192c9
commit 27a9abc73b
4 changed files with 78 additions and 49 deletions

View File

@ -198,6 +198,7 @@ type Docker struct {
// Artifactory server configuration
type Artifactory struct {
Target string `yaml:",omitempty"`
Name string `yaml:",omitempty"`
Username string `yaml:",omitempty"`
// Capture all undefined fields and should be empty after loading

View File

@ -17,7 +17,8 @@ upload target and a usernameto your `.goreleaser.yml` file:
```yaml
artifactories:
- target: http://<Your-Instance>:8081/artifactory/example-repo-local/{{ .ProjectName }}/{{ .Version }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}
- name: production
target: http://<Your-Instance>:8081/artifactory/example-repo-local/{{ .ProjectName }}/{{ .Version }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}
username: goreleaser
```
@ -56,10 +57,15 @@ Support variables:
Your configured username needs to be authenticated against your Artifactory.
The password or API key will be stored in a environment variable.
If you have only one Artifactory configured, you will store the secret in `ARTIFACTORY_0_SECRET`.
The confgured name of your Artifactory instance will be used.
With this way we support auth for multiple instances.
This also means that the `name` per configured instance needs to be unique
per goreleaser configuration.
If you have multiple instances configured, you store the password for the second instance in `ARTIFACTORY_1_SECRET`,
for the third in `ARTIFACTORY_2_SECRET` and so on.
The name of the environment variable will be `ARTIFACTORY_NAME_SECRET`.
If your instance is named `production`, you need to store the secret in the
environment variable `ARTIFACTORY_PRODUCTION_SECRET`.
The name will be transformed to uppercase.
## Customization
@ -70,6 +76,8 @@ Of course, you can customize a lot of things:
artifactories:
# You can have multiple Artifactory instances.
-
# Unique name of your artifactory instance. Used to identify the instance
name: production
# URL of your Artifactory instance + path to deploy to
target: http://artifacts.company.com:8081/artifactory/example-repo-local/{{ .ProjectName }}/{{ .Version }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}{{ .Arm }}{{ end }}
# User that will be used for the deployment

View File

@ -58,26 +58,28 @@ func (Pipe) String() string {
//
// Docs: https://www.jfrog.com/confluence/display/RTF/Artifactory+REST+API#ArtifactoryRESTAPI-Example-DeployinganArtifact
func (Pipe) Run(ctx *context.Context) error {
instances := len(ctx.Config.Artifactories)
if instances == 0 {
if l := len(ctx.Config.Artifactories); l == 0 {
return pipeline.Skip("artifactory section is not configured")
}
// Check if for every instance we have a the target,
// the username and a secret (password or api key)
// If not, we can skip this pipeline
for i := 0; i < instances; i++ {
if ctx.Config.Artifactories[i].Target == "" {
return pipeline.Skip(fmt.Sprintf("artifactory section is not configured properly (missing target in artifactory %d)", i))
// Check requirements for every instance we have configured.
// If not fulfilled, we can skip this pipeline
for _, instance := range ctx.Config.Artifactories {
if instance.Target == "" {
return pipeline.Skip("artifactory section is not configured properly (missing target)")
}
if ctx.Config.Artifactories[i].Username == "" {
return pipeline.Skip(fmt.Sprintf("artifactory section is not configured properly (missing username in artifactory %d)", i))
if instance.Username == "" {
return pipeline.Skip("artifactory section is not configured properly (missing username)")
}
envName := fmt.Sprintf("ARTIFACTORY_%d_SECRET", i)
if instance.Name == "" {
return pipeline.Skip("artifactory section is not configured properly (missing name)")
}
envName := fmt.Sprintf("ARTIFACTORY_%s_SECRET", strings.ToUpper(instance.Name))
if os.Getenv(envName) == "" {
return pipeline.Skip(fmt.Sprintf("missing secret for artifactory %d: %s", i, ctx.Config.Artifactories[i].Target))
return pipeline.Skip(fmt.Sprintf("missing secret for artifactory instance %s", instance.Name))
}
}
@ -137,16 +139,15 @@ func upload(ctx *context.Context, build config.Build, target buildtarget.Target)
}
// Loop over all configured Artifactory instances
instances := len(ctx.Config.Artifactories)
for i := 0; i < instances; i++ {
artifactory := ctx.Config.Artifactories[i]
secret := os.Getenv(fmt.Sprintf("ARTIFACTORY_%d_SECRET", i))
for _, instance := range ctx.Config.Artifactories {
secret := os.Getenv(fmt.Sprintf("ARTIFACTORY_%s_SECRET", strings.ToUpper(instance.Name)))
// Generate name of target
uploadTarget, err := buildTargetName(ctx, artifactory, target)
uploadTarget, err := buildTargetName(ctx, instance, target)
if err != nil {
log.WithError(err).Error("Artifactory: Error while building the target name")
return errors.Wrap(err, "Artifactory: Error while building the target name")
msg := "artifactory: error while building the target name"
log.WithError(err).Error(msg)
return errors.Wrap(err, msg)
}
// The upload url to Artifactory needs the binary name
@ -163,19 +164,22 @@ func upload(ctx *context.Context, build config.Build, target buildtarget.Target)
}
defer file.Close() // nolint: errcheck
artifact, resp, err := uploadBinaryToArtifactory(ctx, uploadTarget, artifactory.Username, secret, file)
artifact, _, err := uploadBinaryToArtifactory(ctx, uploadTarget, instance.Username, secret, file)
if err != nil {
var msg string
if resp != nil {
msg = fmt.Sprintf("Artifactory: Upload to target %s failed (HTTP Status: %s)", uploadTarget, resp.Status)
} else {
msg = fmt.Sprintf("Artifactory: Upload to target %s failed", uploadTarget)
}
log.WithError(err).Error(msg)
msg := "artifactory: upload failed"
log.WithError(err).WithFields(log.Fields{
"instance": instance.Name,
"username": instance.Username,
}).Error(msg)
return errors.Wrap(err, msg)
}
log.WithField("uri", artifact.DownloadURI).WithField("target", target.PrettyString()).Info("uploaded successful")
log.WithFields(log.Fields{
"instance": instance.Name,
"target": target.PrettyString(),
"username": instance.Username,
"uri": artifact.DownloadURI,
}).Info("uploaded successful")
}
return nil

View File

@ -168,10 +168,10 @@ func TestRunPipe(t *testing.T) {
})
// Set secrets for artifactory instances
os.Setenv("ARTIFACTORY_0_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_0_SECRET")
os.Setenv("ARTIFACTORY_1_SECRET", "productionuser-apikey")
defer os.Unsetenv("ARTIFACTORY_1_SECRET")
os.Setenv("ARTIFACTORY_PRODUCTION-US_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_PRODUCTION-US_SECRET")
os.Setenv("ARTIFACTORY_PRODUCTION-EU_SECRET", "productionuser-apikey")
defer os.Unsetenv("ARTIFACTORY_PRODUCTION-EU_SECRET")
var ctx = &context.Context{
Version: "1.0.0",
@ -188,10 +188,12 @@ func TestRunPipe(t *testing.T) {
},
Artifactories: []config.Artifactory{
{
Name: "production-us",
Target: fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
Username: "deployuser",
},
{
Name: "production-eu",
Target: fmt.Sprintf("%s/production-repo-remote/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
Username: "productionuser",
},
@ -237,8 +239,8 @@ func TestRunPipe_BadCredentials(t *testing.T) {
})
// Set secrets for artifactory instances
os.Setenv("ARTIFACTORY_0_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_0_SECRET")
os.Setenv("ARTIFACTORY_PRODUCTION_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_PRODUCTION_SECRET")
var ctx = &context.Context{
Version: "1.0.0",
@ -255,6 +257,7 @@ func TestRunPipe_BadCredentials(t *testing.T) {
},
Artifactories: []config.Artifactory{
{
Name: "production",
Target: fmt.Sprintf("%s/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}", server.URL),
Username: "deployuser",
},
@ -271,8 +274,8 @@ func TestRunPipe_BadCredentials(t *testing.T) {
func TestRunPipe_NoFile(t *testing.T) {
// Set secrets for artifactory instances
os.Setenv("ARTIFACTORY_0_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_0_SECRET")
os.Setenv("ARTIFACTORY_PRODUCTION_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_PRODUCTION_SECRET")
var ctx = &context.Context{
Version: "1.0.0",
@ -289,6 +292,7 @@ func TestRunPipe_NoFile(t *testing.T) {
},
Artifactories: []config.Artifactory{
{
Name: "production",
Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
Username: "deployuser",
},
@ -315,8 +319,8 @@ func TestRunPipe_UnparsableTarget(t *testing.T) {
assert.NoError(t, err)
// Set secrets for artifactory instances
os.Setenv("ARTIFACTORY_0_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_0_SECRET")
os.Setenv("ARTIFACTORY_PRODUCTION_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_PRODUCTION_SECRET")
var ctx = &context.Context{
Version: "1.0.0",
@ -333,6 +337,7 @@ func TestRunPipe_UnparsableTarget(t *testing.T) {
},
Artifactories: []config.Artifactory{
{
Name: "production",
Target: "://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
Username: "deployuser",
},
@ -354,14 +359,10 @@ func TestRunPipe_DirUpload(t *testing.T) {
assert.NoError(t, os.Mkdir(dist, 0755))
assert.NoError(t, os.Mkdir(filepath.Join(dist, "mybin"), 0755))
var binPath = filepath.Join(dist, "mybin")
/*
d1 := []byte("hello\ngo\n")
err = ioutil.WriteFile(binPath, d1, 0666)
assert.NoError(t, err)
*/
// Set secrets for artifactory instances
os.Setenv("ARTIFACTORY_0_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_0_SECRET")
os.Setenv("ARTIFACTORY_PRODUCTION_SECRET", "deployuser-secret")
defer os.Unsetenv("ARTIFACTORY_PRODUCTION_SECRET")
var ctx = &context.Context{
Version: "1.0.0",
@ -378,6 +379,7 @@ func TestRunPipe_DirUpload(t *testing.T) {
},
Artifactories: []config.Artifactory{
{
Name: "production",
Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
Username: "deployuser",
},
@ -404,6 +406,7 @@ func TestNoArtifactoriesWithoutTarget(t *testing.T) {
assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{
Artifactories: []config.Artifactory{
{
Name: "production",
Username: "deployuser",
},
},
@ -414,16 +417,29 @@ func TestNoArtifactoriesWithoutUsername(t *testing.T) {
assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{
Artifactories: []config.Artifactory{
{
Name: "production",
Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
},
},
}))))
}
func TestNoArtifactoriesWithoutName(t *testing.T) {
assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{
Artifactories: []config.Artifactory{
{
Username: "deployuser",
Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
},
},
}))))
}
func TestNoArtifactoriesWithoutSecret(t *testing.T) {
assert.True(t, pipeline.IsSkip(Pipe{}.Run(context.New(config.Project{
Artifactories: []config.Artifactory{
{
Name: "production",
Target: "http://artifacts.company.com/example-repo-local/{{ .ProjectName }}/{{ .Os }}/{{ .Arch }}{{ if .Arm }}v{{ .Arm }}{{ end }}",
Username: "deployuser",
},