Skip to content

Commit

Permalink
fix: http.target template (#1371)
Browse files Browse the repository at this point in the history
* fix: http.target template

refs #1357

Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>

* fix: remove unused struct

Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>

* fix: test

Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>

* fix: tests

Signed-off-by: Carlos Alexandro Becker <caarlos0@gmail.com>
  • Loading branch information
caarlos0 committed Mar 4, 2020
1 parent 0204293 commit 70c9e29
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 53 deletions.
49 changes: 6 additions & 43 deletions internal/http/http.go
Expand Up @@ -2,11 +2,9 @@
package http

import (
"bytes"
"crypto/tls"
"crypto/x509"
"fmt"
"html/template"
"io"
h "net/http"
"os"
Expand All @@ -19,6 +17,7 @@ import (
"github.com/goreleaser/goreleaser/internal/artifact"
"github.com/goreleaser/goreleaser/internal/pipe"
"github.com/goreleaser/goreleaser/internal/semerrgroup"
"github.com/goreleaser/goreleaser/internal/tmpl"
"github.com/goreleaser/goreleaser/pkg/config"
"github.com/goreleaser/goreleaser/pkg/context"
)
Expand Down Expand Up @@ -351,51 +350,15 @@ func executeHTTPRequest(ctx *context.Context, upload *config.Upload, req *h.Requ
return resp, err
}

// targetData is used as a template struct for
// Artifactory.Target
type targetData struct {
Version string
Tag string
ProjectName string
ArtifactName string

// Only supported in mode binary
Os string
Arch string
Arm string
}

// resolveTargetTemplate returns the resolved target template with replaced variables
// Those variables can be replaced by the given context, goos, goarch, goarm and more
// TODO: replace this with our internal template pkg
func resolveTargetTemplate(ctx *context.Context, upload *config.Upload, artifact *artifact.Artifact) (string, error) {
data := targetData{
Version: ctx.Version,
Tag: ctx.Git.CurrentTag,
ProjectName: ctx.Config.ProjectName,
ArtifactName: artifact.Name,
}

var replacements = map[string]string{}
if upload.Mode == ModeBinary {
// TODO: multiple archives here
data.Os = replace(ctx.Config.Archives[0].Replacements, artifact.Goos)
data.Arch = replace(ctx.Config.Archives[0].Replacements, artifact.Goarch)
data.Arm = replace(ctx.Config.Archives[0].Replacements, artifact.Goarm)
}

var out bytes.Buffer
t, err := template.New(ctx.Config.ProjectName).Parse(upload.Target)
if err != nil {
return "", err
}
err = t.Execute(&out, data)
return out.String(), err
}

func replace(replacements map[string]string, original string) string {
result := replacements[original]
if result == "" {
return original
replacements = ctx.Config.Archives[0].Replacements
}
return result
return tmpl.New(ctx).
WithArtifact(artifact, replacements).
Apply(upload.Target)
}
41 changes: 37 additions & 4 deletions internal/http/http_test.go
Expand Up @@ -208,7 +208,11 @@ func TestUpload(t *testing.T) {
ctx := context.New(config.Project{
ProjectName: "blah",
Archives: []config.Archive{
{},
{
Replacements: map[string]string{
"linux": "Linux",
},
},
},
})
ctx.Env["TEST_A_SECRET"] = "x"
Expand All @@ -232,9 +236,11 @@ func TestUpload(t *testing.T) {
var file = filepath.Join(folder, "a."+a.ext)
require.NoError(t, ioutil.WriteFile(file, []byte("lorem ipsum"), 0644))
ctx.Artifacts.Add(&artifact.Artifact{
Name: "a." + a.ext,
Path: file,
Type: a.typ,
Name: "a." + a.ext,
Goos: "linux",
Goarch: "amd64",
Path: file,
Type: a.typ,
Extra: map[string]interface{}{
"ID": "foo",
},
Expand Down Expand Up @@ -307,6 +313,21 @@ func TestUpload(t *testing.T) {
check{"/blah/2.1.0/a.tar", "u1", "x", content, map[string]string{}},
),
},
{"archive_with_os_tmpl", true, true, false, false,
func(s *httptest.Server) (*context.Context, config.Upload) {
return ctx, config.Upload{
Mode: ModeArchive,
Name: "a",
Target: s.URL + "/{{.ProjectName}}/{{.Version}}/{{.Os}}/{{.Arch}}",
Username: "u1",
TrustedCerts: cert(s),
}
},
checks(
check{"/blah/2.1.0/linux/amd64/a.deb", "u1", "x", content, map[string]string{}},
check{"/blah/2.1.0/linux/amd64/a.tar", "u1", "x", content, map[string]string{}},
),
},
{"archive_with_ids", true, true, false, false,
func(s *httptest.Server) (*context.Context, config.Upload) {
return ctx, config.Upload{
Expand Down Expand Up @@ -335,6 +356,18 @@ func TestUpload(t *testing.T) {
},
checks(check{"/blah/2.1.0/a.ubi", "u2", "x", content, map[string]string{}}),
},
{"binary_with_os_tmpl", true, true, false, false,
func(s *httptest.Server) (*context.Context, config.Upload) {
return ctx, config.Upload{
Mode: ModeBinary,
Name: "a",
Target: s.URL + "/{{.ProjectName}}/{{.Version}}/{{.Os}}/{{.Arch}}",
Username: "u2",
TrustedCerts: cert(s),
}
},
checks(check{"/blah/2.1.0/Linux/amd64/a.ubi", "u2", "x", content, map[string]string{}}),
},
{"binary_with_ids", true, true, false, false,
func(s *httptest.Server) (*context.Context, config.Upload) {
return ctx, config.Upload{
Expand Down
2 changes: 1 addition & 1 deletion internal/pipe/artifactory/artifactory_test.go
Expand Up @@ -383,7 +383,7 @@ func TestRunPipe_TargetTemplateError(t *testing.T) {
})

assert.NoError(t, Pipe{}.Default(ctx))
assert.EqualError(t, Pipe{}.Publish(ctx), `artifactory: error while building the target url: template: mybin:1: unexpected "/" in operand`)
assert.EqualError(t, Pipe{}.Publish(ctx), `artifactory: error while building the target url: template: tmpl:1: unexpected "/" in operand`)
}

func TestRunPipe_BadCredentials(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion internal/pipe/upload/upload_test.go
Expand Up @@ -422,7 +422,7 @@ func TestRunPipe_TargetTemplateError(t *testing.T) {
})
err = Pipe{}.Publish(ctx)
assert.Error(t, err)
assert.Contains(t, err.Error(), `upload: error while building the target url: template: mybin:1: unexpected "/" in operand`)
assert.Contains(t, err.Error(), `upload: error while building the target url: template: tmpl:1: unexpected "/" in operand`)
}

func TestRunPipe_BadCredentials(t *testing.T) {
Expand Down
10 changes: 6 additions & 4 deletions www/content/upload.md
Expand Up @@ -30,7 +30,7 @@ Prerequisites:

### Target

The `target` is the URL to upload the artifacts to (_without_ the name of the artifact).
The `target` is the template of the URL to upload the artifacts to (_without_ the name of the artifact).

An example configuration for `goreleaser` in upload mode `binary` with the target can look like

Expand Down Expand Up @@ -66,7 +66,7 @@ The configured name of your HTTP server will be used to build the environment
variable name.
This way we support auth for multiple instances.
This also means that the `name` per configured instance needs to be unique
per goreleaser configuration.
per GoReleaser configuration.

The name of the environment variable will be `UPLOAD_NAME_USERNAME`.
If your instance is named `production`, you can store the username in the
Expand All @@ -82,7 +82,7 @@ The password will be stored in a environment variable.
The configured name of your HTTP server will be used.
This way we support auth for multiple instances.
This also means that the `name` per configured instance needs to be unique
per goreleaser configuration.
per GoReleaser configuration.

The name of the environment variable will be `UPLOAD_NAME_SECRET`.
If your instance is named `production`, you need to store the secret in the
Expand Down Expand Up @@ -144,7 +144,7 @@ uploads:
# Default is `archive`.
mode: archive

# URL to be used as target of the HTTP request
# Template of the URL to be used as target of the HTTP request
target: https://some.server/some/path/example-repo-local/{{ .ProjectName }}/{{ .Version }}/

# Custom artifact name (defaults to false)
Expand Down Expand Up @@ -178,3 +178,5 @@ uploads:
```

These settings should allow you to push your artifacts into multiple HTTP servers.

> Learn more about the [name template engine](/templates).

0 comments on commit 70c9e29

Please sign in to comment.