Print public HTTPS URL of uploaded artefact

After a successful S3 upload, log the HTTPS URL so the workflow run
output shows where the artefact was published. Uses the regional
virtual-hosted form for AWS S3 and path-style for custom endpoints,
matching how NewClient configures the client.

The URL is what the object would be served at if the bucket allows
public reads — the orchestrator does not assert anything about the
bucket's access policy.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Leon Mika 2026-05-02 13:54:57 +10:00
parent d8f5309a73
commit 78f63e640f
3 changed files with 57 additions and 0 deletions

View file

@ -174,6 +174,7 @@ func run(ctx context.Context) error {
if err != nil { if err != nil {
return err return err
} }
fmt.Println("Uploaded to:", upload.HTTPSURL(cfg.S3Bucket, key, cfg.S3Region, cfg.S3EndpointURL))
} }
// 8. Outputs (fixed order so partial-write failures are reproducible) // 8. Outputs (fixed order so partial-write failures are reproducible)

View file

@ -47,6 +47,19 @@ func Upload(ctx context.Context, c PutObjectAPI, o Opts) (string, error) {
return fmt.Sprintf("s3://%s/%s", o.Bucket, o.Key), nil return fmt.Sprintf("s3://%s/%s", o.Bucket, o.Key), nil
} }
// HTTPSURL returns the HTTPS form of an upload location. For AWS S3 it uses
// the regional virtual-hosted form; for a custom endpoint it appends the
// bucket and key path-style, matching how NewClient configures the client.
//
// The bucket may still be private — this is purely the URL where the object
// would be served if it (or its bucket) were publicly readable.
func HTTPSURL(bucket, key, region, endpointURL string) string {
if endpointURL != "" {
return strings.TrimRight(endpointURL, "/") + "/" + bucket + "/" + key
}
return fmt.Sprintf("https://%s.s3.%s.amazonaws.com/%s", bucket, region, key)
}
// WriteFileForTest is exposed for use from this package's tests. // WriteFileForTest is exposed for use from this package's tests.
func WriteFileForTest(path string, b []byte) error { func WriteFileForTest(path string, b []byte) error {
return os.WriteFile(path, b, 0o600) return os.WriteFile(path, b, 0o600)

View file

@ -29,6 +29,49 @@ func TestRenderKey(t *testing.T) {
} }
} }
func TestHTTPSURL(t *testing.T) {
cases := []struct {
name string
bucket, key string
region string
endpoint string
want string
}{
{
name: "aws regional virtual-hosted",
bucket: "my-bucket", key: "releases/1.2.3/App.app.zip",
region: "ap-southeast-2",
want: "https://my-bucket.s3.ap-southeast-2.amazonaws.com/releases/1.2.3/App.app.zip",
},
{
name: "aws us-east-1 still uses regional form",
bucket: "my-bucket", key: "k",
region: "us-east-1",
want: "https://my-bucket.s3.us-east-1.amazonaws.com/k",
},
{
name: "custom endpoint path-style",
bucket: "releases", key: "myapp/1.0.0/App.app.zip",
region: "auto", endpoint: "https://my-minio.example.com",
want: "https://my-minio.example.com/releases/myapp/1.0.0/App.app.zip",
},
{
name: "custom endpoint with trailing slash is normalised",
bucket: "b", key: "k",
region: "auto", endpoint: "https://example.com/",
want: "https://example.com/b/k",
},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
got := upload.HTTPSURL(c.bucket, c.key, c.region, c.endpoint)
if got != c.want {
t.Fatalf("got %q\nwant %q", got, c.want)
}
})
}
}
type fakePut struct { type fakePut struct {
calls []*s3.PutObjectInput calls []*s3.PutObjectInput
} }