Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .dagger/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ func (m *BargeDev) TestsPass(
ctx context.Context,
// +optional
githubToken *dagger.Secret,
// +optional
githubRepo string,
) error {
if _, err := m.Test(ctx, githubToken); err != nil {
if _, err := m.Test(ctx, githubToken, githubRepo); err != nil {
return err
}

Expand Down
8 changes: 7 additions & 1 deletion .dagger/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ func (m *BargeDev) Test(
ctx context.Context,
// +optional
githubToken *dagger.Secret,
// +optional
githubRepo string,
) (string, error) {
return dag.Go(dagger.GoOpts{
Module: m.Source,
Expand All @@ -70,9 +72,13 @@ func (m *BargeDev) Test(
Container().
With(func(r *dagger.Container) *dagger.Container {
if githubToken != nil {
return r.
r = r.
WithSecretVariable("GITHUB_TOKEN", githubToken)
}
if githubRepo != "" {
r = r.
WithEnvVariable("GITHUB_REPOSITORY", githubRepo)
}
return r
}).
WithExec([]string{"go", "test", "-race", "-cover", "-test.v", "./..."}, dagger.ContainerWithExecOpts{ExperimentalPrivilegedNesting: true}).
Expand Down
2 changes: 2 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
bargeDev_test_githubToken=env://GITHUB_TOKEN
bargeDev_test_githubRepo=frantjc/barge
bargeDev_testsPass_githubToken=env://GITHUB_TOKEN
bargeDev_testsPass_githubRepo=frantjc/barge
bargeDev_release_githubToken=env://GITHUB_TOKEN
bargeDev_release_githubRepo=frantjc/barge
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,21 @@ barge cp https://github.com/frantjc/barge/raw/refs/heads/main/testdata/test-0.1.
```sh
barge cp oci://ghcr.io/frantjc/barge/charts/test ./test.tgz
```

- You want to do all of the above at once where `barge-sync.yml` looks like:

```yml
---
sources:
- url: repo://chartmuseum
charts:
chartmuseum:
- 3.9.0
chartsBySemver:
chartmuseum: ">= 3.10"
```

```sh
helm repo add chartmuseum https://chartmuseum.github.io/charts
barge sync barge-sync.yml oci://example.io
```
26 changes: 22 additions & 4 deletions cmd/barge/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ func newBarge() *cobra.Command {
Version: SemVer(),
SilenceErrors: true,
SilenceUsage: true,
PersistentPreRun: func(cmd *cobra.Command, args []string) {
PersistentPreRun: func(cmd *cobra.Command, _ []string) {
cmd.SetContext(
util.SloggerInto(
util.StdoutInto(
Expand All @@ -62,17 +62,17 @@ func newBarge() *cobra.Command {
},
}
)
cmd.Flags().BoolP("help", "h", false, "Help for "+cmd.Name())
cmd.PersistentFlags().BoolP("help", "h", false, "Help for "+cmd.Name())
cmd.Flags().Bool("version", false, "Version for "+cmd.Name())
cmd.SetVersionTemplate("{{ .Name }}{{ .Version }}")
slogConfig.AddFlags(cmd.PersistentFlags())
cmd.AddCommand(newCopy())
cmd.AddCommand(newCopy(), newSync())
return cmd
}

func newCopy() *cobra.Command {
cmd := &cobra.Command{
Use: "copy",
Use: "copy src dest",
Aliases: []string{"cp"},
SilenceErrors: true,
SilenceUsage: true,
Expand All @@ -84,3 +84,21 @@ func newCopy() *cobra.Command {
barge.AddFlags(cmd.Flags())
return cmd
}

func newSync() *cobra.Command {
var (
syncOpts = new(barge.SyncOpts)
cmd = &cobra.Command{
Use: "sync config dest",
SilenceErrors: true,
SilenceUsage: true,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
return barge.Sync(cmd.Context(), args[0], args[1])
},
}
)
cmd.Flags().BoolVar(&syncOpts.FailFast, "fail-fast", false, "Exit when the first source fails to sync")
barge.AddFlags(cmd.Flags())
return cmd
}
109 changes: 58 additions & 51 deletions copy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,16 @@ import (
"net/url"
"os"
"os/exec"
"strings"
"testing"

"dagger.io/dagger"
"github.com/frantjc/barge"
_ "github.com/frantjc/barge/internal/archive"
_ "github.com/frantjc/barge/internal/artifactory"
_ "github.com/frantjc/barge/internal/chartmuseum"
_ "github.com/frantjc/barge/internal/directory"
_ "github.com/frantjc/barge/internal/file"
_ "github.com/frantjc/barge/internal/http"
_ "github.com/frantjc/barge/internal/oci"
_ "github.com/frantjc/barge/internal/release"
_ "github.com/frantjc/barge/internal/repo"
"github.com/frantjc/barge/internal/util"
"github.com/frantjc/barge/testdata"
Expand All @@ -35,16 +32,65 @@ func Command(t testing.TB, name string, arg ...string) *exec.Cmd {
return cmd
}

func Context(t testing.TB) context.Context {
t.Helper()
return util.StdoutInto(util.StderrInto(t.Context(), t.Output()), t.Output())
}

func Chartmuseum(t testing.TB, dag *dagger.Client) *url.URL {
t.Helper()
ctx := t.Context()
chartmuseum, err := dag.Container().
From("ghcr.io/helm/chartmuseum:v0.16.3").
WithExposedPort(8080).
WithEnvVariable("DEBUG", "1").
WithEnvVariable("STORAGE", "local").
WithEnvVariable("STORAGE_LOCAL_ROOTDIR", "/tmp").
AsService().
Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
_, err = chartmuseum.Stop(context.WithoutCancel(ctx))
assert.NoError(t, err)
})
rawChartmuseumURL, err := chartmuseum.Endpoint(ctx, dagger.ServiceEndpointOpts{Scheme: "chartmuseum"})
require.NoError(t, err)
chartmuseumURL, err := url.Parse(rawChartmuseumURL)
chartmuseumURL.RawQuery = "insecure=1"
require.NoError(t, err)

return chartmuseumURL
}

func Registry(t testing.TB, dag *dagger.Client) *url.URL {
t.Helper()
ctx := t.Context()
registry, err := dag.Container().
From("docker.io/distribution/distribution:3").
WithExposedPort(5000).
AsService().
Start(ctx)
require.NoError(t, err)
t.Cleanup(func() {
_, err = registry.Stop(context.WithoutCancel(ctx))
assert.NoError(t, err)
})
rawRegistryURL, err := registry.Endpoint(ctx, dagger.ServiceEndpointOpts{Scheme: "oci"})
require.NoError(t, err)
registryURL, err := url.Parse(rawRegistryURL)
require.NoError(t, err)

return registryURL
}

func FuzzCopy(f *testing.F) {
ctx := util.StdoutInto(util.StderrInto(f.Context(), f.Output()), f.Output())
ctx := Context(f)

tmp, err := os.CreateTemp(f.TempDir(), "test-0.1.0.tgz")
require.NoError(f, err)
_, err = tmp.Write(testdata.ChartArchive)
require.NoError(f, err)
f.Cleanup(func() {
assert.NoError(f, tmp.Close())
})
require.NoError(f, tmp.Close())
chart, err := loader.LoadFile(tmp.Name())
require.NoError(f, err)
archive := fmt.Sprintf("archive://%s", tmp.Name())
Expand All @@ -61,25 +107,8 @@ func FuzzCopy(f *testing.F) {
assert.NoError(f, dag.Close())
})

chartmuseum, err := dag.Container().
From("ghcr.io/helm/chartmuseum:v0.16.3").
WithExposedPort(8080).
WithEnvVariable("DEBUG", "1").
WithEnvVariable("STORAGE", "local").
WithEnvVariable("STORAGE_LOCAL_ROOTDIR", "/tmp").
AsService().
Start(ctx)
require.NoError(f, err)
f.Cleanup(func() {
_, err = chartmuseum.Stop(context.WithoutCancel(ctx))
assert.NoError(f, err)
})
rawChartmuseumURL, err := chartmuseum.Endpoint(ctx, dagger.ServiceEndpointOpts{Scheme: "chartmuseum"})
require.NoError(f, err)
chartmuseumURL, err := url.Parse(rawChartmuseumURL)
chartmuseumURL.RawQuery = "insecure=1"
require.NoError(f, err)
f.Add(archive, chartmuseumURL.String())
chartmuseumURL := Chartmuseum(f, dag)
require.NoError(f, barge.Copy(ctx, archive, chartmuseumURL.String()))

if helm, err := exec.LookPath("helm"); assert.NoError(f, err) {
repo := "chartmuseum"
Expand All @@ -101,32 +130,17 @@ func FuzzCopy(f *testing.F) {
}
f.Add(httpURL.String(), f.TempDir())

registry, err := dag.Container().
From("docker.io/distribution/distribution:3").
WithExposedPort(5000).
AsService().
Start(ctx)
require.NoError(f, err)
f.Cleanup(func() {
_, err = registry.Stop(context.WithoutCancel(ctx))
assert.NoError(f, err)
})
rawRegistryURL, err := registry.Endpoint(ctx, dagger.ServiceEndpointOpts{Scheme: "oci"})
require.NoError(f, err)
registryURL, err := url.Parse(rawRegistryURL)
require.NoError(f, err)

registryURL := Registry(f, dag)
oci := registryURL.JoinPath("test")
f.Add(archive, oci.String())
f.Add(oci.String(), f.TempDir())

ociWithTag := registryURL.JoinPath("test:tag")
f.Add(archive, ociWithTag.String())
f.Add(ociWithTag.String(), f.TempDir())
}

if username, _, err := util.GetGitHubAuth(ctx); assert.NoError(f, err) {
ghcr := fmt.Sprintf("oci://ghcr.io/%s/barge/charts/%s", username, chart.Name())
if githubRepository := os.Getenv("GITHUB_REPOSITORY"); githubRepository != "" {
ghcr := fmt.Sprintf("oci://ghcr.io/%s/charts/%s", githubRepository, chart.Name())
ghcrWithTag := fmt.Sprintf("%s:%s", ghcr, chart.Metadata.Version)
f.Add(archive, ghcr)
f.Add(ghcr, f.TempDir())
Expand All @@ -135,13 +149,6 @@ func FuzzCopy(f *testing.F) {
}

f.Fuzz(func(t *testing.T, src, dest string) {
if strings.HasPrefix(src, "repo://") {
if helm, err := exec.LookPath("helm"); assert.NoError(f, err) {
update := Command(t, helm, "repo", "update")
require.NoError(t, update.Run())
}
}

require.NoError(t, barge.Copy(t.Context(), src, dest))
})
}
Expand Down
4 changes: 4 additions & 0 deletions destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,7 @@ func RegisterDestination(o Destination, scheme string, schemes ...string) {
destMux[s] = o
}
}

type SyncableDestination interface {
Sync(context.Context, *url.URL, *chart.Chart) error
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.25.4

require (
dagger.io/dagger v0.19.10
github.com/Masterminds/semver/v3 v3.4.0
github.com/cli/cli/v2 v2.83.2
github.com/fluxcd/pkg/auth v0.33.0
github.com/frantjc/x v0.0.0-20251203020658-a4e29ee5477f
Expand Down Expand Up @@ -56,7 +57,6 @@ require (
github.com/BurntSushi/toml v1.5.0 // indirect
github.com/MakeNowJust/heredoc v1.0.0 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.4.0 // indirect
github.com/Masterminds/sprig/v3 v3.3.0 // indirect
github.com/Masterminds/squirrel v1.5.4 // indirect
github.com/alecthomas/chroma/v2 v2.19.0 // indirect
Expand Down
4 changes: 4 additions & 0 deletions internal/artifactory/destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,7 @@ func (d *destination) Write(ctx context.Context, u *url.URL, c *chart.Chart) err

return nil
}

func (d *destination) Sync(ctx context.Context, u *url.URL, c *chart.Chart) error {
return d.Write(ctx, u, c)
}
4 changes: 4 additions & 0 deletions internal/chartmuseum/destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,7 @@ func (d *destination) Write(ctx context.Context, u *url.URL, c *chart.Chart) err

return nil
}

func (d *destination) Sync(ctx context.Context, u *url.URL, c *chart.Chart) error {
return d.Write(ctx, u, c)
}
5 changes: 5 additions & 0 deletions internal/directory/destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package directory

import (
"context"
"fmt"
"net/url"
"path/filepath"

Expand All @@ -23,3 +24,7 @@ type destination struct{}
func (d *destination) Write(ctx context.Context, u *url.URL, c *chart.Chart) error {
return util.WriteChartToDirectory(ctx, c, filepath.Join(u.Host, u.Path))
}

func (d *destination) Sync(ctx context.Context, u *url.URL, c *chart.Chart) error {
return util.WriteChartToFile(c, filepath.Join(u.Host, u.Path, fmt.Sprintf("%s-%s.tgz", c.Name(), c.Metadata.Version)))
}
13 changes: 13 additions & 0 deletions internal/file/destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package file

import (
"context"
"fmt"
"net/url"
"os"
"path/filepath"
Expand Down Expand Up @@ -33,3 +34,15 @@ func (d *destination) Write(ctx context.Context, u *url.URL, c *chart.Chart) err

return util.WriteChartToFile(c, name)
}

func (d *destination) Sync(ctx context.Context, u *url.URL, c *chart.Chart) error {
name := filepath.Join(u.Host, u.Path)

if fi, err := os.Stat(name); err != nil {
return err
} else if fi.IsDir() {
return d.Write(ctx, u.JoinPath(fmt.Sprintf("%s-%s.tgz", c.Name(), c.Metadata.Version)), c)
}

return fmt.Errorf("cannot sync to a file; try a directory")
}
10 changes: 10 additions & 0 deletions internal/oci/destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"io"
"net/url"
"strings"

"github.com/frantjc/barge"
"github.com/frantjc/barge/internal/util"
Expand Down Expand Up @@ -45,3 +46,12 @@ func (d *destination) Write(ctx context.Context, u *url.URL, c *chart.Chart) err

return nil
}

func (d *destination) Sync(ctx context.Context, u *url.URL, c *chart.Chart) error {
v := u.JoinPath()
v.Path, _, _ = strings.Cut(v.Path, ":")
q := v.Query()
q.Set("version", c.Metadata.Version)
v.RawQuery = q.Encode()
return d.Write(ctx, v.JoinPath(c.Name()), c)
}
Loading