diff --git a/cmd/oras/internal/display/handler.go b/cmd/oras/internal/display/handler.go index ccab31dc3..2db6834f1 100644 --- a/cmd/oras/internal/display/handler.go +++ b/cmd/oras/internal/display/handler.go @@ -20,7 +20,7 @@ import ( "os" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - fetcher "oras.land/oras-go/v2/content" + fetcher "github.com/oras-project/oras-go/v3/content" "oras.land/oras/cmd/oras/internal/display/content" "oras.land/oras/cmd/oras/internal/display/metadata" diff --git a/cmd/oras/internal/display/metadata/model/pull.go b/cmd/oras/internal/display/metadata/model/pull.go index 9392902c2..9be3cea69 100644 --- a/cmd/oras/internal/display/metadata/model/pull.go +++ b/cmd/oras/internal/display/metadata/model/pull.go @@ -22,7 +22,7 @@ import ( "sync" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content/file" + "github.com/oras-project/oras-go/v3/content/file" ) // File records metadata of a pulled file. diff --git a/cmd/oras/internal/display/metadata/table/discover.go b/cmd/oras/internal/display/metadata/table/discover.go index d9c77ee72..f9e76acd5 100644 --- a/cmd/oras/internal/display/metadata/table/discover.go +++ b/cmd/oras/internal/display/metadata/table/discover.go @@ -21,7 +21,7 @@ import ( "strings" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content" + "github.com/oras-project/oras-go/v3/content" "oras.land/oras/cmd/oras/internal/display/metadata" "oras.land/oras/cmd/oras/internal/output" ) diff --git a/cmd/oras/internal/display/status/discard.go b/cmd/oras/internal/display/status/discard.go index 2bb9cbd75..cd15a70c5 100644 --- a/cmd/oras/internal/display/status/discard.go +++ b/cmd/oras/internal/display/status/discard.go @@ -20,7 +20,7 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" + "github.com/oras-project/oras-go/v3" ) func discardStopTrack() error { diff --git a/cmd/oras/internal/display/status/interface.go b/cmd/oras/internal/display/status/interface.go index b9c9a5848..9360b25a7 100644 --- a/cmd/oras/internal/display/status/interface.go +++ b/cmd/oras/internal/display/status/interface.go @@ -20,7 +20,7 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" + "github.com/oras-project/oras-go/v3" ) // StopTrackTargetFunc is the function type to stop tracking a target. diff --git a/cmd/oras/internal/display/status/text.go b/cmd/oras/internal/display/status/text.go index f4ba703e4..d0902c088 100644 --- a/cmd/oras/internal/display/status/text.go +++ b/cmd/oras/internal/display/status/text.go @@ -25,8 +25,8 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" "oras.land/oras/cmd/oras/internal/output" ) diff --git a/cmd/oras/internal/display/status/text_test.go b/cmd/oras/internal/display/status/text_test.go index e3bf3477f..71a928b9c 100644 --- a/cmd/oras/internal/display/status/text_test.go +++ b/cmd/oras/internal/display/status/text_test.go @@ -23,7 +23,7 @@ import ( "testing" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content/memory" + "github.com/oras-project/oras-go/v3/content/memory" "oras.land/oras/cmd/oras/internal/output" "oras.land/oras/internal/testutils" ) diff --git a/cmd/oras/internal/display/status/track/target.go b/cmd/oras/internal/display/status/track/target.go index b424325fa..fa2179885 100644 --- a/cmd/oras/internal/display/status/track/target.go +++ b/cmd/oras/internal/display/status/track/target.go @@ -22,9 +22,9 @@ import ( "os" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry" sprogress "oras.land/oras/cmd/oras/internal/display/status/progress" "oras.land/oras/internal/progress" ) diff --git a/cmd/oras/internal/display/status/track/target_test.go b/cmd/oras/internal/display/status/track/target_test.go index 554b61a21..32e64e41a 100644 --- a/cmd/oras/internal/display/status/track/target_test.go +++ b/cmd/oras/internal/display/status/track/target_test.go @@ -26,10 +26,10 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content/memory" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry/remote" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content/memory" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry/remote" "oras.land/oras/internal/progress" "oras.land/oras/internal/testutils" ) @@ -87,8 +87,12 @@ func Test_referenceGraphTarget_PushReference(t *testing.T) { } } -func Test_referenceGraphTarget_Mount(_ *testing.T) { - target := graphTarget{GraphTarget: &remote.Repository{}} +func Test_referenceGraphTarget_Mount(t *testing.T) { + repo, err := remote.NewRepository("localhost/repo") + if err != nil { + t.Fatal(err) + } + target := graphTarget{GraphTarget: repo} _ = target.Mount(context.Background(), ocispec.Descriptor{}, "", nil) } diff --git a/cmd/oras/internal/display/status/tty.go b/cmd/oras/internal/display/status/tty.go index a2eb7bd98..ce384452c 100644 --- a/cmd/oras/internal/display/status/tty.go +++ b/cmd/oras/internal/display/status/tty.go @@ -23,8 +23,8 @@ import ( "oras.land/oras/internal/graph" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" "oras.land/oras/cmd/oras/internal/display/status/track" "oras.land/oras/internal/progress" ) diff --git a/cmd/oras/internal/display/status/tty_console_test.go b/cmd/oras/internal/display/status/tty_console_test.go index aac6ed16b..dd599b3bc 100644 --- a/cmd/oras/internal/display/status/tty_console_test.go +++ b/cmd/oras/internal/display/status/tty_console_test.go @@ -21,8 +21,8 @@ import ( "strconv" "testing" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content/memory" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content/memory" "oras.land/oras/internal/testutils" ) diff --git a/cmd/oras/internal/display/status/tty_test.go b/cmd/oras/internal/display/status/tty_test.go index 2f77ea7f9..4e748db92 100644 --- a/cmd/oras/internal/display/status/tty_test.go +++ b/cmd/oras/internal/display/status/tty_test.go @@ -22,7 +22,7 @@ import ( "testing" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content/memory" + "github.com/oras-project/oras-go/v3/content/memory" "oras.land/oras/internal/testutils" ) diff --git a/cmd/oras/internal/errors/errors.go b/cmd/oras/internal/errors/errors.go index e7e933e7f..dbb42f50a 100644 --- a/cmd/oras/internal/errors/errors.go +++ b/cmd/oras/internal/errors/errors.go @@ -20,11 +20,11 @@ import ( "fmt" "strings" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/registry/remote/auth" + "github.com/oras-project/oras-go/v3/registry/remote/errcode" "github.com/spf13/cobra" "github.com/spf13/pflag" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/registry/remote/auth" - "oras.land/oras-go/v2/registry/remote/errcode" ) // OperationType stands for certain type of operations. diff --git a/cmd/oras/internal/errors/errors_test.go b/cmd/oras/internal/errors/errors_test.go index 9b8e684a7..4c7abc36f 100644 --- a/cmd/oras/internal/errors/errors_test.go +++ b/cmd/oras/internal/errors/errors_test.go @@ -21,9 +21,9 @@ import ( "net/url" "testing" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/registry/remote/errcode" "github.com/spf13/pflag" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/registry/remote/errcode" ) func TestCheckMutuallyExclusiveFlags(t *testing.T) { diff --git a/cmd/oras/internal/option/binary_target.go b/cmd/oras/internal/option/binary_target.go index b5501806e..2bf6f1a9f 100644 --- a/cmd/oras/internal/option/binary_target.go +++ b/cmd/oras/internal/option/binary_target.go @@ -20,9 +20,9 @@ import ( "fmt" "sync" + "github.com/oras-project/oras-go/v3" "github.com/spf13/cobra" "github.com/spf13/pflag" - "oras.land/oras-go/v2" oerrors "oras.land/oras/cmd/oras/internal/errors" ) diff --git a/cmd/oras/internal/option/binary_target_test.go b/cmd/oras/internal/option/binary_target_test.go index e8eb7aaca..2b5dc5f94 100644 --- a/cmd/oras/internal/option/binary_target_test.go +++ b/cmd/oras/internal/option/binary_target_test.go @@ -19,8 +19,8 @@ import ( "errors" "testing" + "github.com/oras-project/oras-go/v3" "github.com/spf13/cobra" - "oras.land/oras-go/v2" ) func TestBinaryTarget_ModifyError(t *testing.T) { diff --git a/cmd/oras/internal/option/cache.go b/cmd/oras/internal/option/cache.go index 0012a4253..71c7d3362 100644 --- a/cmd/oras/internal/option/cache.go +++ b/cmd/oras/internal/option/cache.go @@ -18,8 +18,8 @@ package option import ( "os" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content/oci" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content/oci" "oras.land/oras/internal/cache" ) diff --git a/cmd/oras/internal/option/cache_test.go b/cmd/oras/internal/option/cache_test.go index 16afa019e..d261f96ef 100644 --- a/cmd/oras/internal/option/cache_test.go +++ b/cmd/oras/internal/option/cache_test.go @@ -19,9 +19,9 @@ import ( "reflect" "testing" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content/memory" - "oras.land/oras-go/v2/content/oci" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content/memory" + "github.com/oras-project/oras-go/v3/content/oci" "oras.land/oras/internal/cache" ) diff --git a/cmd/oras/internal/option/interface.go b/cmd/oras/internal/option/interface.go index dc2676d2c..bfec57fb4 100644 --- a/cmd/oras/internal/option/interface.go +++ b/cmd/oras/internal/option/interface.go @@ -16,9 +16,9 @@ limitations under the License. package option import ( - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/registry" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/registry" ) // ResolvableDeleter a target that resolve and delete diff --git a/cmd/oras/internal/option/packer.go b/cmd/oras/internal/option/packer.go index a82c893a8..21537b438 100644 --- a/cmd/oras/internal/option/packer.go +++ b/cmd/oras/internal/option/packer.go @@ -25,9 +25,9 @@ import ( "strings" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3/content" "github.com/spf13/cobra" "github.com/spf13/pflag" - "oras.land/oras-go/v2/content" oerrors "oras.land/oras/cmd/oras/internal/errors" "oras.land/oras/cmd/oras/internal/fileref" ) diff --git a/cmd/oras/internal/option/remote.go b/cmd/oras/internal/option/remote.go index 27179ccbe..82001ec3a 100644 --- a/cmd/oras/internal/option/remote.go +++ b/cmd/oras/internal/option/remote.go @@ -28,15 +28,15 @@ import ( "strings" "sync" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry/remote" + "github.com/oras-project/oras-go/v3/registry/remote/auth" + "github.com/oras-project/oras-go/v3/registry/remote/credentials" + "github.com/oras-project/oras-go/v3/registry/remote/errcode" + "github.com/oras-project/oras-go/v3/registry/remote/retry" "github.com/sirupsen/logrus" "github.com/spf13/cobra" "github.com/spf13/pflag" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry/remote" - "oras.land/oras-go/v2/registry/remote/auth" - "oras.land/oras-go/v2/registry/remote/credentials" - "oras.land/oras-go/v2/registry/remote/errcode" - "oras.land/oras-go/v2/registry/remote/retry" oerrors "oras.land/oras/cmd/oras/internal/errors" "oras.land/oras/internal/credential" "oras.land/oras/internal/crypto" @@ -264,7 +264,7 @@ func (remo *Remote) authClient(_ string, debug bool) (client *auth.Client, err e client = &auth.Client{ Client: &http.Client{ // http.RoundTripper with a retry using the DefaultPolicy - // see: https://pkg.go.dev/oras.land/oras-go/v2/registry/remote/retry#Policy + // see: https://pkg.go.dev/github.com/oras-project/oras-go/v3/registry/remote/retry#Policy Transport: retry.NewTransport(baseTransport), }, Cache: auth.NewCache(), @@ -276,8 +276,8 @@ func (remo *Remote) authClient(_ string, debug bool) (client *auth.Client, err e } cred := remo.Credential() - if cred != auth.EmptyCredential { - client.Credential = func(_ context.Context, _ string) (auth.Credential, error) { + if !cred.IsEmpty() { + client.CredentialFunc = func(_ context.Context, _ string) (credentials.Credential, error) { return cred, nil } } else { @@ -286,7 +286,7 @@ func (remo *Remote) authClient(_ string, debug bool) (client *auth.Client, err e if err != nil { return nil, err } - client.Credential = credentials.Credential(remo.store) + client.CredentialFunc = remo.store.Get } return } @@ -320,7 +320,7 @@ func (remo *Remote) parseCustomHeaders() error { } // Credential returns a credential based on the remote options. -func (remo *Remote) Credential() auth.Credential { +func (remo *Remote) Credential() credentials.Credential { return credential.Credential(remo.Username, remo.Secret) } @@ -365,17 +365,15 @@ func (remo *Remote) NewRepository(reference string, common Common, logger logrus } return nil, err } - registry := repo.Reference.Registry - repo.PlainHTTP = remo.isPlainHTTP(registry) - repo.HandleWarning = remo.handleWarning(registry, logger) - if repo.Client, err = remo.authClient(registry, common.Debug); err != nil { + registry := repo.Registry.Reference.Registry + repo.Registry.PlainHTTP = remo.isPlainHTTP(registry) + repo.Registry.HandleWarning = remo.handleWarning(registry, logger) + if repo.Registry.Client, err = remo.authClient(registry, common.Debug); err != nil { return nil, err } repo.SkipReferrersGC = true if remo.ReferrersAPI != ReferrersStateUnknown { - if err := repo.SetReferrersCapability(remo.ReferrersAPI == ReferrersStateSupported); err != nil { - return nil, err - } + repo.SetReferrersCapability(remo.ReferrersAPI == ReferrersStateSupported) } return } diff --git a/cmd/oras/internal/option/remote_test.go b/cmd/oras/internal/option/remote_test.go index 7887376e1..7d0fdba96 100644 --- a/cmd/oras/internal/option/remote_test.go +++ b/cmd/oras/internal/option/remote_test.go @@ -33,9 +33,9 @@ import ( "reflect" "testing" + "github.com/oras-project/oras-go/v3/registry/remote/credentials" "github.com/sirupsen/logrus" "github.com/spf13/pflag" - "oras.land/oras-go/v2/registry/remote/auth" ) var ts *httptest.Server @@ -131,7 +131,7 @@ func TestRemote_authClient_RawCredential(t *testing.T) { if _, err := rand.Read(password); err != nil { t.Fatalf("unexpected error: %v", err) } - want := auth.Credential{ + want := credentials.Credential{ Username: "mocked^^??oras-@@!#", Password: base64.StdEncoding.EncodeToString(password), } @@ -143,7 +143,7 @@ func TestRemote_authClient_RawCredential(t *testing.T) { if err != nil { t.Fatalf("unexpected error: %v", err) } - got, err := client.Credential(nil, "") + got, err := client.CredentialFunc(nil, "") if err != nil { t.Fatalf("unexpected error: %v", err) } diff --git a/cmd/oras/internal/option/spec.go b/cmd/oras/internal/option/spec.go index eb1d1c295..f36d7630a 100644 --- a/cmd/oras/internal/option/spec.go +++ b/cmd/oras/internal/option/spec.go @@ -19,8 +19,8 @@ import ( "fmt" "strings" + "github.com/oras-project/oras-go/v3" "github.com/spf13/pflag" - "oras.land/oras-go/v2" oerrors "oras.land/oras/cmd/oras/internal/errors" ) diff --git a/cmd/oras/internal/option/target.go b/cmd/oras/internal/option/target.go index 07be338ca..25ba88b58 100644 --- a/cmd/oras/internal/option/target.go +++ b/cmd/oras/internal/option/target.go @@ -29,13 +29,13 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content/oci" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry" - "oras.land/oras-go/v2/registry/remote" - "oras.land/oras-go/v2/registry/remote/auth" - "oras.land/oras-go/v2/registry/remote/errcode" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content/oci" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry/remote" + "github.com/oras-project/oras-go/v3/registry/remote/auth" + "github.com/oras-project/oras-go/v3/registry/remote/errcode" + "github.com/oras-project/oras-go/v3/registry/remote/properties" oerrors "oras.land/oras/cmd/oras/internal/errors" "oras.land/oras/cmd/oras/internal/fileref" ) @@ -114,7 +114,7 @@ func (target *Target) Parse(cmd *cobra.Command) error { return nil default: target.Type = TargetTypeRemote - ref, err := registry.ParseReference(target.RawReference) + ref, err := properties.NewReference(target.RawReference) if err != nil { return &oerrors.Error{ OperationType: oerrors.OperationTypeParseArtifactReference, @@ -122,8 +122,9 @@ func (target *Target) Parse(cmd *cobra.Command) error { Recommendation: "Please make sure the provided reference is in the form of /[:tag|@digest]", } } - target.Reference = ref.Reference - ref.Reference = "" + target.Reference = ref.GetReference() + ref.Tag = "" + ref.Digest = "" target.Path = ref.String() return target.Remote.Parse(cmd) } @@ -260,11 +261,11 @@ func (target *Target) ModifyError(cmd *cobra.Command, err error) (bool, error) { return false, err } - ref := registry.Reference{Registry: target.RawReference} + ref := properties.Reference{Registry: target.RawReference} if errResp.URL.Host != ref.Host() { // raw reference is not registry host var parseErr error - ref, parseErr = registry.ParseReference(target.RawReference) + ref, parseErr = properties.NewReference(target.RawReference) if parseErr != nil { // this should not happen return false, err diff --git a/cmd/oras/internal/option/target_test.go b/cmd/oras/internal/option/target_test.go index e24dba07c..13c3c1a4b 100644 --- a/cmd/oras/internal/option/target_test.go +++ b/cmd/oras/internal/option/target_test.go @@ -23,9 +23,9 @@ import ( "strings" "testing" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry/remote/errcode" "github.com/spf13/cobra" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry/remote/errcode" oerrors "oras.land/oras/cmd/oras/internal/errors" ) diff --git a/cmd/oras/root/attach.go b/cmd/oras/root/attach.go index acd49f1a9..b6fac1671 100644 --- a/cmd/oras/root/attach.go +++ b/cmd/oras/root/attach.go @@ -21,11 +21,11 @@ import ( "fmt" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/file" + "github.com/oras-project/oras-go/v3/registry/remote/auth" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/file" - "oras.land/oras-go/v2/registry/remote/auth" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/backup.go b/cmd/oras/root/backup.go index a5d3b9d9a..dc2a08309 100644 --- a/cmd/oras/root/backup.go +++ b/cmd/oras/root/backup.go @@ -27,12 +27,13 @@ import ( "time" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/oci" + "github.com/oras-project/oras-go/v3/registry" + "github.com/oras-project/oras-go/v3/registry/remote/properties" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/oci" - "oras.land/oras-go/v2/registry" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" @@ -413,12 +414,12 @@ func parseArtifactReferences(artifactRefs string) (string, []string, error) { extraTags := refParts[1:] // validate repository - parsedRepo, err := registry.ParseReference(mainRef) + parsedRepo, err := properties.NewReference(mainRef) if err != nil { return "", nil, fmt.Errorf("invalid reference %q: %w", mainRef, err) } - mainTag := parsedRepo.Reference - parsedRepo.Reference = "" // clear the tag + mainTag := parsedRepo.Tag + parsedRepo.Tag = "" // clear the tag repository := parsedRepo.String() if mainTag == "" && len(extraTags) == 0 { // no tags @@ -431,10 +432,11 @@ func parseArtifactReferences(artifactRefs string) (string, []string, error) { if tag == "" { return "", nil, fmt.Errorf("empty tag in reference %q", artifactRefs) } - parsedRepo.Reference = tag - if err := parsedRepo.ValidateReferenceAsTag(); err != nil { + parsedRepo.Tag = tag + if err := parsedRepo.ValidateTag(); err != nil { return "", nil, fmt.Errorf("invalid tag %q in reference %q: %w", tag, artifactRefs, err) } + parsedRepo.Tag = "" } return repository, tags, nil } diff --git a/cmd/oras/root/backup_test.go b/cmd/oras/root/backup_test.go index f09a9fda7..404ef1f8b 100644 --- a/cmd/oras/root/backup_test.go +++ b/cmd/oras/root/backup_test.go @@ -31,12 +31,12 @@ import ( "github.com/opencontainers/image-spec/specs-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/memory" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry/remote" "github.com/sirupsen/logrus" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/memory" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry/remote" ) func TestParseArtifactReferences(t *testing.T) { @@ -403,7 +403,7 @@ func Test_resolveTags(t *testing.T) { if err != nil { t.Fatalf("failed to create remote repository: %v", err) } - repo.PlainHTTP = true + repo.Registry.PlainHTTP = true tags, descs, err := resolveTags(ctx, repo, []string{"v1", "v2"}) if err != nil { @@ -435,7 +435,7 @@ func Test_resolveTags(t *testing.T) { if err != nil { t.Fatalf("failed to create remote repository: %v", err) } - repo.PlainHTTP = true + repo.Registry.PlainHTTP = true _, _, err = resolveTags(ctx, repo, []string{"non-existent"}) if wantErr := errdef.ErrNotFound; !errors.Is(err, wantErr) { @@ -458,7 +458,7 @@ func Test_resolveTags(t *testing.T) { if err != nil { t.Fatalf("failed to create remote repository: %v", err) } - repo.PlainHTTP = true + repo.Registry.PlainHTTP = true tags, descs, err := resolveTags(ctx, repo, nil) if err != nil { @@ -491,7 +491,7 @@ func Test_resolveTags(t *testing.T) { if err != nil { t.Fatalf("failed to create remote repository: %v", err) } - repo.PlainHTTP = true + repo.Registry.PlainHTTP = true _, _, err = resolveTags(ctx, repo, nil) if err == nil { @@ -516,7 +516,7 @@ func Test_resolveTags(t *testing.T) { if err != nil { t.Fatalf("failed to create remote repository: %v", err) } - repo.PlainHTTP = true + repo.Registry.PlainHTTP = true _, _, err = resolveTags(ctx, repo, nil) if wantErr := errdef.ErrNotFound; !errors.Is(err, wantErr) { @@ -537,7 +537,7 @@ func Test_resolveTags(t *testing.T) { if err != nil { t.Fatalf("failed to create remote repository: %v", err) } - repo.PlainHTTP = true + repo.Registry.PlainHTTP = true tags, descs, err := resolveTags(ctx, repo, nil) if err != nil { diff --git a/cmd/oras/root/blob/delete.go b/cmd/oras/root/blob/delete.go index f166037f7..500ae22a9 100644 --- a/cmd/oras/root/blob/delete.go +++ b/cmd/oras/root/blob/delete.go @@ -20,9 +20,9 @@ import ( "fmt" "os" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry/remote/auth" "github.com/spf13/cobra" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry/remote/auth" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/blob/fetch.go b/cmd/oras/root/blob/fetch.go index 61ad1dbd4..031e3bc40 100644 --- a/cmd/oras/root/blob/fetch.go +++ b/cmd/oras/root/blob/fetch.go @@ -22,10 +22,10 @@ import ( "os" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/registry/remote" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/registry/remote" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display/status/track" diff --git a/cmd/oras/root/blob/fetch_test.go b/cmd/oras/root/blob/fetch_test.go index e2dc2d5d6..ab524144a 100644 --- a/cmd/oras/root/blob/fetch_test.go +++ b/cmd/oras/root/blob/fetch_test.go @@ -24,7 +24,7 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content/memory" + "github.com/oras-project/oras-go/v3/content/memory" "oras.land/oras/internal/testutils" ) diff --git a/cmd/oras/root/blob/push.go b/cmd/oras/root/blob/push.go index 4317cfec5..c686a1624 100644 --- a/cmd/oras/root/blob/push.go +++ b/cmd/oras/root/blob/push.go @@ -22,8 +22,8 @@ import ( "os" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" "github.com/spf13/cobra" - "oras.land/oras-go/v2" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/blob/push_test.go b/cmd/oras/root/blob/push_test.go index 4c3396a91..079853fdf 100644 --- a/cmd/oras/root/blob/push_test.go +++ b/cmd/oras/root/blob/push_test.go @@ -26,7 +26,7 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content/memory" + "github.com/oras-project/oras-go/v3/content/memory" "oras.land/oras/internal/testutils" ) diff --git a/cmd/oras/root/cp.go b/cmd/oras/root/cp.go index 13f0869f7..8c32194e2 100644 --- a/cmd/oras/root/cp.go +++ b/cmd/oras/root/cp.go @@ -24,12 +24,12 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/registry" + "github.com/oras-project/oras-go/v3/registry/remote" + "github.com/oras-project/oras-go/v3/registry/remote/auth" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/registry" - "oras.land/oras-go/v2/registry/remote" - "oras.land/oras-go/v2/registry/remote/auth" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" @@ -321,7 +321,7 @@ func getMountPoint(src oras.ReadOnlyGraphTarget, dst oras.GraphTarget, opts *cop if !srcIsRemote || !dstIsRemote { return "", false } - if srcRepo.Reference.Registry != dstRepo.Reference.Registry { + if srcRepo.Registry.Reference.Registry != dstRepo.Registry.Reference.Registry { return "", false } srcCred := opts.From.Credential() @@ -329,5 +329,5 @@ func getMountPoint(src oras.ReadOnlyGraphTarget, dst oras.GraphTarget, opts *cop if srcCred != dstCred { return "", false } - return srcRepo.Reference.Repository, true + return srcRepo.RepositoryName, true } diff --git a/cmd/oras/root/cp_test.go b/cmd/oras/root/cp_test.go index e3aa27317..8eeab8680 100644 --- a/cmd/oras/root/cp_test.go +++ b/cmd/oras/root/cp_test.go @@ -33,10 +33,10 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/memory" - "oras.land/oras-go/v2/registry/remote" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/memory" + "github.com/oras-project/oras-go/v3/registry/remote" "oras.land/oras/cmd/oras/internal/display/status" "oras.land/oras/internal/testutils" ) @@ -185,12 +185,12 @@ func Test_doCopy_mounted(t *testing.T) { if err != nil { t.Fatal(err) } - from.PlainHTTP = true + from.Registry.PlainHTTP = true to, err := remote.NewRepository(fmt.Sprintf("%s/%s", host, repoTo)) if err != nil { t.Fatal(err) } - to.PlainHTTP = true + to.Registry.PlainHTTP = true handler := status.NewTTYCopyHandler(opts.TTY) // test @@ -367,17 +367,9 @@ func Test_prepareCopyOption_noReferrers(t *testing.T) { } func Test_getMountPoint(t *testing.T) { - registry1Repo1 := &remote.Repository{} - registry1Repo1.Reference.Registry = "localhost:5000" - registry1Repo1.Reference.Repository = "repo1" - - registry1Repo2 := &remote.Repository{} - registry1Repo2.Reference.Registry = "localhost:5000" - registry1Repo2.Reference.Repository = "repo2" - - registry2Repo1 := &remote.Repository{} - registry2Repo1.Reference.Registry = "localhost:6000" - registry2Repo1.Reference.Repository = "repo1" + registry1Repo1, _ := remote.NewRepository("localhost:5000/repo1") + registry1Repo2, _ := remote.NewRepository("localhost:5000/repo2") + registry2Repo1, _ := remote.NewRepository("localhost:6000/repo1") tests := []struct { name string diff --git a/cmd/oras/root/discover.go b/cmd/oras/root/discover.go index d42f5f650..a4a8ff0e9 100644 --- a/cmd/oras/root/discover.go +++ b/cmd/oras/root/discover.go @@ -23,8 +23,8 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/registry" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/registry" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/file.go b/cmd/oras/root/file.go index 950e51541..cd7cb13f9 100644 --- a/cmd/oras/root/file.go +++ b/cmd/oras/root/file.go @@ -23,7 +23,7 @@ import ( "path/filepath" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content/file" + "github.com/oras-project/oras-go/v3/content/file" "oras.land/oras/cmd/oras/internal/display/status" "oras.land/oras/cmd/oras/internal/fileref" ) diff --git a/cmd/oras/root/login.go b/cmd/oras/root/login.go index 1f572f33a..36e4f2e92 100644 --- a/cmd/oras/root/login.go +++ b/cmd/oras/root/login.go @@ -22,9 +22,9 @@ import ( "os" "strings" + "github.com/oras-project/oras-go/v3/registry/remote" "github.com/spf13/cobra" "golang.org/x/term" - "oras.land/oras-go/v2/registry/remote/credentials" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" oerrors "oras.land/oras/cmd/oras/internal/errors" @@ -112,11 +112,11 @@ func runLogin(cmd *cobra.Command, opts loginOptions) (err error) { if err != nil { return err } - remote, err := opts.NewRegistry(opts.Hostname, opts.Common, logger) + reg, err := opts.NewRegistry(opts.Hostname, opts.Common, logger) if err != nil { return err } - if err = credentials.Login(ctx, store, remote, opts.Credential()); err != nil { + if err = remote.Login(ctx, store, reg, opts.Credential()); err != nil { return err } _ = opts.Printer.Println("Login Succeeded") diff --git a/cmd/oras/root/logout.go b/cmd/oras/root/logout.go index 3e803ca65..04d48ef85 100644 --- a/cmd/oras/root/logout.go +++ b/cmd/oras/root/logout.go @@ -16,9 +16,9 @@ limitations under the License. package root import ( + "github.com/oras-project/oras-go/v3/registry/remote" "github.com/sirupsen/logrus" "github.com/spf13/cobra" - "oras.land/oras-go/v2/registry/remote/credentials" "oras.land/oras/cmd/oras/internal/argument" oerrors "oras.land/oras/cmd/oras/internal/errors" "oras.land/oras/internal/credential" @@ -63,5 +63,5 @@ func runLogout(cmd *cobra.Command, opts logoutOptions) error { if err != nil { return err } - return credentials.Logout(ctx, store, opts.hostname) + return remote.Logout(ctx, store, opts.hostname) } diff --git a/cmd/oras/root/manifest/delete.go b/cmd/oras/root/manifest/delete.go index 7bb777c10..20b3c0faf 100644 --- a/cmd/oras/root/manifest/delete.go +++ b/cmd/oras/root/manifest/delete.go @@ -20,9 +20,9 @@ import ( "fmt" "os" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry/remote/auth" "github.com/spf13/cobra" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry/remote/auth" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/manifest/fetch.go b/cmd/oras/root/manifest/fetch.go index 8e5d70e18..48526c5b7 100644 --- a/cmd/oras/root/manifest/fetch.go +++ b/cmd/oras/root/manifest/fetch.go @@ -19,9 +19,9 @@ import ( "fmt" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/registry/remote" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/registry/remote" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/manifest/fetch_config.go b/cmd/oras/root/manifest/fetch_config.go index 875c91439..23cfdd321 100644 --- a/cmd/oras/root/manifest/fetch_config.go +++ b/cmd/oras/root/manifest/fetch_config.go @@ -23,9 +23,9 @@ import ( "os" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" oerrors "oras.land/oras/cmd/oras/internal/errors" diff --git a/cmd/oras/root/manifest/index/create.go b/cmd/oras/root/manifest/index/create.go index e1368f3bd..f66571ce8 100644 --- a/cmd/oras/root/manifest/index/create.go +++ b/cmd/oras/root/manifest/index/create.go @@ -25,10 +25,10 @@ import ( "github.com/opencontainers/image-spec/specs-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/errdef" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/errdef" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/manifest/index/create_test.go b/cmd/oras/root/manifest/index/create_test.go index de57f36ff..6006b9099 100644 --- a/cmd/oras/root/manifest/index/create_test.go +++ b/cmd/oras/root/manifest/index/create_test.go @@ -25,7 +25,7 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" + "github.com/oras-project/oras-go/v3" "oras.land/oras/cmd/oras/internal/display/status" ) diff --git a/cmd/oras/root/manifest/index/update.go b/cmd/oras/root/manifest/index/update.go index eac4d9468..ef5a16312 100644 --- a/cmd/oras/root/manifest/index/update.go +++ b/cmd/oras/root/manifest/index/update.go @@ -22,10 +22,10 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" "github.com/spf13/cobra" "github.com/spf13/pflag" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/manifest/index/update_test.go b/cmd/oras/root/manifest/index/update_test.go index 29546db83..235c9f013 100644 --- a/cmd/oras/root/manifest/index/update_test.go +++ b/cmd/oras/root/manifest/index/update_test.go @@ -23,7 +23,7 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" + "github.com/oras-project/oras-go/v3" "oras.land/oras/cmd/oras/internal/display/status" ) diff --git a/cmd/oras/root/manifest/push.go b/cmd/oras/root/manifest/push.go index 4b496baf7..2760a730e 100644 --- a/cmd/oras/root/manifest/push.go +++ b/cmd/oras/root/manifest/push.go @@ -23,11 +23,11 @@ import ( "strings" digest "github.com/opencontainers/go-digest" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry/remote" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry/remote" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/pull.go b/cmd/oras/root/pull.go index f8f3b06af..2c847abdd 100644 --- a/cmd/oras/root/pull.go +++ b/cmd/oras/root/pull.go @@ -22,10 +22,10 @@ import ( "sync" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/file" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/file" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/push.go b/cmd/oras/root/push.go index 46cba38c8..4cd3cfb1f 100644 --- a/cmd/oras/root/push.go +++ b/cmd/oras/root/push.go @@ -22,12 +22,12 @@ import ( "strings" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/file" + "github.com/oras-project/oras-go/v3/content/memory" + "github.com/oras-project/oras-go/v3/registry/remote/auth" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/file" - "oras.land/oras-go/v2/content/memory" - "oras.land/oras-go/v2/registry/remote/auth" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/repo/tags.go b/cmd/oras/root/repo/tags.go index 61214339d..de86f723b 100644 --- a/cmd/oras/root/repo/tags.go +++ b/cmd/oras/root/repo/tags.go @@ -20,8 +20,8 @@ import ( "strings" "github.com/opencontainers/go-digest" + "github.com/oras-project/oras-go/v3/registry/remote/properties" "github.com/spf13/cobra" - "oras.land/oras-go/v2/registry" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" @@ -104,8 +104,8 @@ func showTags(cmd *cobra.Command, opts *showTagsOptions) error { // if a repository path is given, filter the tags under the repository var targetPrefix string if opts.Target.Type == option.TargetTypeOCILayout { - ref, err := registry.ParseReference(opts.Reference) - if err == nil && ref.Reference == "" { + ref, err := properties.NewReference(opts.Reference) + if err == nil && ref.GetReference() == "" { targetPrefix = fmt.Sprintf("%s/%s:", ref.Registry, ref.Repository) } } diff --git a/cmd/oras/root/resolve.go b/cmd/oras/root/resolve.go index 81d30ad18..7238a7b9b 100644 --- a/cmd/oras/root/resolve.go +++ b/cmd/oras/root/resolve.go @@ -18,8 +18,8 @@ package root import ( "fmt" + "github.com/oras-project/oras-go/v3" "github.com/spf13/cobra" - "oras.land/oras-go/v2" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/restore.go b/cmd/oras/root/restore.go index 25b1bad41..a8901098c 100644 --- a/cmd/oras/root/restore.go +++ b/cmd/oras/root/restore.go @@ -23,11 +23,11 @@ import ( "time" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/oci" + "github.com/oras-project/oras-go/v3/registry" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/oci" - "oras.land/oras-go/v2/registry" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" "oras.land/oras/cmd/oras/internal/display" diff --git a/cmd/oras/root/tag.go b/cmd/oras/root/tag.go index cb92dd85f..59fdd41e5 100644 --- a/cmd/oras/root/tag.go +++ b/cmd/oras/root/tag.go @@ -22,10 +22,10 @@ import ( "oras.land/oras/cmd/oras/internal/display" "oras.land/oras/internal/listener" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/errdef" + "github.com/oras-project/oras-go/v3/registry/remote" "github.com/spf13/cobra" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/errdef" - "oras.land/oras-go/v2/registry/remote" "oras.land/oras/cmd/oras/internal/argument" "oras.land/oras/cmd/oras/internal/command" oerrors "oras.land/oras/cmd/oras/internal/errors" @@ -108,9 +108,7 @@ func tagManifest(cmd *cobra.Command, opts *tagOptions) error { return err } if targetRepo, ok := target.(*remote.Repository); ok { - // Since referrer capability has not been set or detected yet, - // nil is the only returned value and thus can be ignored - _ = targetRepo.SetReferrersCapability(true) + targetRepo.SetReferrersCapability(true) } if err := opts.EnsureReferenceNotEmpty(cmd, true); err != nil { return err diff --git a/docs/proposals/oras-go-v3-migration.md b/docs/proposals/oras-go-v3-migration.md new file mode 100644 index 000000000..27cb10958 --- /dev/null +++ b/docs/proposals/oras-go-v3-migration.md @@ -0,0 +1,391 @@ +# oras-go v3 Migration: Deprecation Fixes & New Feature Adoption + +## Overview + +This document tracks the full migration from oras-go v2 to v3, covering both the mechanical breaking-change fixes and the new v3 features worth adopting in the ORAS CLI. The basic import-path and API-rename migration is handled in PR #2002; this document plans the remaining work. + +## Problem Statement & Motivation + +oras-go v3 introduces a new module path (`github.com/oras-project/oras-go/v3`), several breaking API renames, and a set of new packages that provide capabilities the ORAS CLI currently either lacks entirely or implements through duplicated custom code. Fully adopting v3 means: + +- Removing duplicated implementations (`internal/cache`, `internal/trace`) that are now first-class in the library. +- Fixing a process-safety bug in the cache (`oci.New` vs `oci.NewStorage`). +- Unlocking new user-facing capabilities: Podman auth.json credentials, per-registry TLS from `certs.d`, and automatic registry mirrors via `registries.conf`. + +Reference: [`oras-go/docs/SCENARIOS.md`](https://github.com/oras-project/oras-go/blob/main/docs/SCENARIOS.md) and [`oras-go/docs/migration-v3/`](https://github.com/oras-project/oras-go/blob/main/docs/migration-v3/). + +## Background & Context + +### What PR #2002 Already Covers + +The branch `feat/migrate-to-oras-go-v3` completes the mechanical migration: + +| Status | Change | +|--------|--------| +| ✅ Done | Import path `oras.land/oras-go/v2` → `github.com/oras-project/oras-go/v3` | +| ✅ Done | `auth.Credential{}` → `credentials.Credential{}` | +| ✅ Done | `client.Credential =` → `client.CredentialFunc =` | +| ✅ Done | `credentials.Login/Logout` → `remote.Login/Logout` | +| ✅ Done | `repo.Client/PlainHTTP/HandleWarning` → `repo.Registry.*` | +| ✅ Done | `repo.Reference.Repository` → `repo.RepositoryName` | +| ✅ Done | `ref.Reference` (field) → `ref.GetReference()` | +| ✅ Done | `SetReferrersCapability()` — void, no longer returns error | + +### New Packages in oras-go v3 + +| Package | Description | +|---------|-------------| +| `registry/remote/config` | Unified loader for Docker config.json, containers auth.json, registries.conf, policy.json, certs.d | +| `registry/remote/properties` | Typed registry configuration (`Registry`, `Transport`, `Mirror`) | +| `registry/remote/builder.go` | `ClientBuilder` factory: TLS, retry, credentials, user-agent, debug logging in one place | +| `registry/remote/middleware.go` | `RepositoryMiddleware`, `WithPolicyEnforcement`, `Compose` | +| `registry/remote/mirror.go` | Mirror fallback with pull policies | +| `registry/remote/policy` | `containers-policy.json` enforcement | +| `registry/remote/signature` | Atomic container signature signing/verification (OpenPGP, lookaside) | +| `content/cache` | Process-safe caching wrapper (`CacheReadOnlyTarget`, `Cache`, `NewFromEnv`) | +| `objects` | ORM-like API for OCI images, artifacts, and image indexes | + +## Scenarios + +**Enterprise/air-gapped users** rely on `registries.conf` to configure mirrors and blocked registries. Currently ORAS ignores this file; after adopting `config.LoadConfigs()`, mirrors are tried automatically on every pull operation. + +**Podman users** store credentials in `containers/auth.json`, not Docker's `config.json`. Currently ORAS only reads Docker's format; `config.LoadConfigs()` reads both. + +**Operators** in regulated environments may have per-registry CA certificates in `certs.d`. Currently these require a `--ca-file` flag on every command; after adopting the full config stack this happens automatically. + +**Developers running parallel pulls** in CI share an `ORAS_CACHE` directory across processes. The current `oci.New()` based cache is not safe for concurrent writes; `oci.NewStorage()` fixes this silently. + +## Proposal + +### Part 1 — Remaining Deprecations (Bugs / Code Duplication) + +#### 1.1 Fix Cache Process-Safety: `oci.New()` → `oci.NewStorage()` + +**File:** `cmd/oras/internal/option/cache.go:34` + +`oci.New()` maintains an `index.json` file that is not safe for concurrent process access. `oci.NewStorage()` omits `index.json` writes and is designed for shared cache use. (SCENARIOS.md §8.) + +```go +// Before +ociStore, err := oci.New(opts.Root) + +// After — process-safe for shared ORAS_CACHE directories +ociStore, err := oci.NewStorage(opts.Root) +``` + +Also update `option/cache_test.go` which uses `oci.New()` directly. + +#### 1.2 Delete `internal/cache/` — Use `oras-go/content/cache` + +**Files:** `internal/cache/target.go`, `internal/cache/target_test.go`, `cmd/oras/internal/option/cache.go` + +`internal/cache/target.go` reimplements `CacheReadOnlyTarget`, `Fetch`, `FetchReference`, and `Exists` caching logic. This is now first-class in `github.com/oras-project/oras-go/v3/content/cache`. The library version also correctly uses `oci.NewStorage()` internally. + +```go +// option/cache.go — After +import "github.com/oras-project/oras-go/v3/content/cache" + +func (opts *Cache) CachedTarget(src oras.ReadOnlyTarget) (oras.ReadOnlyTarget, error) { + opts.Root = os.Getenv("ORAS_CACHE") + if opts.Root != "" { + c := &cache.Cache{Root: opts.Root} + return c.ReadOnlyTarget(src) // uses oci.NewStorage internally + } + return src, nil +} +``` + +Net reduction: ~100 lines of duplicated implementation removed. + +#### 1.3 Replace Custom `handleWarning()` with `remote.NewWarningLogger()` + +**File:** `cmd/oras/internal/option/remote.go:327-342` + +The custom `handleWarning()` function with its `sync.Map` de-duplication tracks exactly what `remote.NewWarningLogger(registry, *slog.Logger)` provides in v3. (SCENARIOS.md §11.) + +The complication is that ORAS uses `logrus` while `NewWarningLogger` takes `*slog.Logger`. The fix requires a small slog→logrus bridge handler: + +```go +// internal/logutil/slog_bridge.go +type logrusHandler struct { + logger logrus.FieldLogger + attrs []slog.Attr +} + +func (h *logrusHandler) Handle(_ context.Context, r slog.Record) error { + entry := h.logger + r.Attrs(func(a slog.Attr) bool { + entry = entry.WithField(a.Key, a.Value.Any()) + return true + }) + entry.Warn(r.Message) + return nil +} +// + Enabled, WithAttrs, WithGroup stubs +``` + +Then replace `handleWarning()`: + +```go +// option/remote.go — After +import ( + "log/slog" + "oras.land/oras/internal/logutil" +) + +// In NewRepository() and NewRegistry(): +slogLogger := slog.New(logutil.NewLogrusHandler(logger)) +repo.Registry.HandleWarning = remote.NewWarningLogger(registry, slogLogger) +``` + +This removes `warned map[string]*sync.Map` from the `Remote` struct, removes the init code in `binary_target.go:63-64`, and eliminates the per-registry state tracking (~25 lines). + +#### 1.4 Replace Custom Trace Transport with `remote.NewLoggingTransport()` + +**File:** `internal/trace/transport.go` + +`internal/trace/transport.go` (~160 lines) implements HTTP debug logging with auth header scrubbing and token body redaction. `remote.NewLoggingTransport(inner, *slog.Logger)` in v3 provides identical behavior with the same 16 KiB body cap, same header scrubbing (`Authorization`, `Set-Cookie`), same token field redaction, and adds sequential request IDs for correlating concurrent requests. + +With `ClientBuilder` adoption (Part 2 below), debug logging is wired via `builder.Logger`: + +```go +// option/remote.go — in newClientBuilder() +if debug { + builder.Logger = slog.New(logutil.NewLogrusHandler(logger)) + // ClientBuilder internally wraps transport as: + // LoggingTransport → retry.Transport → http.Transport (TLS) +} +``` + +Once `ClientBuilder` is adopted, `internal/trace/transport.go` and its call site can be deleted (~160 lines removed). + +### Part 2 — New v3 Features to Implement + +#### 2.1 `ClientBuilder` + `properties.Registry` in `NewRepository()`/`NewRegistry()` + +**File:** `cmd/oras/internal/option/remote.go` + +**Current approach:** `authClient()` manually assembles `tls.Config` → `http.Transport` → `retry.Transport` → `auth.Client`, then `NewRepository()` sets `repo.Registry.*` fields individually. This is 40+ lines of plumbing that `ClientBuilder` handles in one place. + +**New approach:** + +```go +func (remo *Remote) newClientBuilder(debug bool) (*remote.ClientBuilder, error) { + builder := remote.NewClientBuilder() + builder.UserAgent = "oras/" + version.GetVersion() + + // DNS resolve: set on BaseTransport + baseTransport := http.DefaultTransport.(*http.Transport).Clone() + dialContext, err := remo.parseResolve(baseTransport.DialContext) + if err != nil { + return nil, err + } + baseTransport.DialContext = dialContext + builder.BaseTransport = baseTransport + + if debug { + builder.Logger = slog.New(logutil.NewLogrusHandler(...)) + } + + cred := remo.Credential() + if !cred.IsEmpty() { + // Wrap inline credential as a single-entry store + builder.CredentialStore = credentials.NewMemoryStore() + // or set props.Credential directly (see 2.2) + } else { + store, err := credential.NewStore(remo.Configs...) + if err != nil { + return nil, err + } + builder.CredentialStore = store + } + return builder, nil +} + +func (remo *Remote) NewRepository(reference string, common Common, logger logrus.FieldLogger) (*remote.Repository, error) { + props, err := properties.NewReference(reference) + if err != nil { + return nil, err + } + + // Override from CLI flags + registry := props.Reference.Registry + props.Transport.PlainHTTP = remo.isPlainHTTP(registry) + props.Transport.Insecure = remo.Insecure + if remo.CACertFilePath != "" { + props.Transport.CACerts = []string{remo.CACertFilePath} + } + if remo.CertFilePath != "" && remo.KeyFilePath != "" { + props.Transport.ClientCerts = []properties.ClientCert{ + {CertFile: remo.CertFilePath, KeyFile: remo.KeyFilePath}, + } + } + cred := remo.Credential() + if !cred.IsEmpty() { + props.Credential = cred + } + + builder, err := remo.newClientBuilder(common.Debug) + if err != nil { + return nil, err + } + + repo, err := remote.NewRepositoryWithProperties(props, builder) + if err != nil { + return nil, err + } + repo.SkipReferrersGC = true + if remo.ReferrersAPI != ReferrersStateUnknown { + repo.SetReferrersCapability(remo.ReferrersAPI == ReferrersStateSupported) + } + return repo, nil +} +``` + +`NewRepositoryWithProperties` also calls `NewWarningLogger` automatically, eliminating the need to set `HandleWarning` manually. + +#### 2.2 `config.LoadConfigs()` for Full Ecosystem Config Stack + +**File:** `cmd/oras/internal/option/remote.go` + +**Current:** Only reads Docker `config.json` via `credential.NewStore()`. Ignores containers `auth.json`, per-registry TLS from `certs.d`, and registry mirrors from `registries.conf`. + +**New:** Use `config.LoadConfigs()` as the baseline, then override with CLI flags. This follows Scenario 2 (CLI Tool with Flag Overrides) from SCENARIOS.md exactly. + +```go +import "github.com/oras-project/oras-go/v3/registry/remote/config" + +func (remo *Remote) registryProperties(reference string) (*properties.Registry, credentials.Store, error) { + // Load full ecosystem config: Docker config.json, containers auth.json, + // registries.conf (mirrors, blocked registries), certs.d (per-registry TLS). + // Files that do not exist are silently skipped. + opts := config.LoadConfigsOptions{} + if len(remo.Configs) > 0 { + opts.DockerConfigPath = remo.Configs[0] // --registry-config flag + } + configs, err := config.LoadConfigsWithOptions(opts) + if err != nil { + return nil, nil, err + } + + // Config-driven properties (resolves mirrors, alias rewrites, certs.d TLS). + props, err := configs.RegistryProperties(reference) + if err != nil { + return nil, nil, err + } + + // CLI flags override config-file values (highest priority per Scenario 2). + if remo.Insecure { + props.Transport.Insecure = true + } + if remo.CACertFilePath != "" { + props.Transport.CACerts = []string{remo.CACertFilePath} + } + if remo.CertFilePath != "" && remo.KeyFilePath != "" { + props.Transport.ClientCerts = []properties.ClientCert{ + {CertFile: remo.CertFilePath, KeyFile: remo.KeyFilePath}, + } + } + plainHTTP, enforced := remo.plainHTTP() + if enforced { + props.Transport.PlainHTTP = plainHTTP + } else if isLocalhost(props.Reference.Registry) { + props.Transport.PlainHTTP = true + } + cred := remo.Credential() + if !cred.IsEmpty() { + props.Credential = cred // explicit credential wins over store + } + + store, err := configs.CredentialStore(credentials.StoreOptions{}) + if err != nil { + return nil, nil, err + } + return props, store, nil +} +``` + +**Capabilities unlocked at zero additional CLI surface:** +- **Registry mirrors**: When `registries.conf` exists (standard on RHEL/Fedora/CentOS/WSL), mirrors are tried automatically on every read operation before falling back to the primary registry. +- **Podman/containers auth.json**: Credentials saved by Podman (`podman login`) are read alongside Docker credentials. +- **certs.d TLS**: Per-registry CA certificates in `~/.config/containers/certs.d/` or `/etc/containers/certs.d/` are loaded without any CLI flags. + +**Future flags to add (separate PRs):** +- `--registries-config` — override path to `registries.conf` +- `--policy-file` — override path to `policy.json` (prerequisite for policy enforcement, Part 3) + +#### 2.3 `oras.CopyError` Structured Error Handling + +**Files:** `cmd/oras/root/cp.go`, `cmd/oras/root/push.go`, `cmd/oras/root/pull.go`, `cmd/oras/root/attach.go` + +v3 wraps copy failures in `*oras.CopyError` which identifies whether the failure originated at the source or destination and which descriptor failed. (SCENARIOS.md §15.) + +```go +// In runCopy(), runPush(), runPull(), runAttach() after oras.Copy() calls: +_, err = oras.Copy(ctx, src, srcRef, dst, dstRef, opts) +if err != nil { + var copyErr *oras.CopyError + if errors.As(err, ©Err) { + switch copyErr.Origin { + case oras.CopyErrorOriginSource: + return fmt.Errorf("failed to read %s from source: %w", + copyErr.Descriptor.Digest, copyErr.Err) + case oras.CopyErrorOriginDestination: + return fmt.Errorf("failed to write %s to destination: %w", + copyErr.Descriptor.Digest, copyErr.Err) + } + } + return err +} +``` + +This improves the user experience for `oras cp` failures, which often happen due to auth or network issues on one side of a registry-to-registry copy, making the error message clearly actionable. + +#### 2.4 `remote.NewCredentialFunc()` Instead of `store.Get` Directly + +**File:** `cmd/oras/internal/option/remote.go:289` + +Minor hardening: `remote.NewCredentialFunc(store)` gracefully handles a nil store (returns empty credentials), whereas `store.Get` would panic. With `ClientBuilder` adoption this is handled internally, but as a standalone fix: + +```go +// Before +client.CredentialFunc = remo.store.Get + +// After +client.CredentialFunc = remote.NewCredentialFunc(remo.store) +``` + +### Part 3 — Future Work (Separate PRs) + +The following new v3 capabilities require new CLI flags and more substantial user-facing design. They are not part of the oras-go v3 migration PR but are enabled by it. + +| Capability | oras-go Package | SCENARIOS.md | Notes | +|------------|----------------|--------------|-------| +| Policy enforcement (`--policy-file`) | `registry/remote/policy` | §3 | Requires UX design for `insecureAcceptAnything` / `reject` / `signedBy` rules | +| OpenPGP signature verification | `registry/remote/signature` | §10 | Depends on `registries.d` config support and lookaside store URLs | +| `objects` package for push/pack | `objects` | §5 | Higher-level alternative to `PackManifest`; consider for `oras push` simplification | +| `ParseReferenceList` for multi-tag | `registry` | §4 | Convenience for `oras tag` with comma-separated tags | + +### Implementation Order + +| # | Task | Primary Files | Net LOC | Unblocked By | +|---|------|--------------|---------|-------------| +| 1 | `oci.New()` → `oci.NewStorage()` in cache | `option/cache.go` | −2 | — | +| 2 | Delete `internal/cache/`; use `oras-go/content/cache` | `internal/cache/`, `option/cache.go` | −100 | 1 | +| 3 | `logutil.NewLogrusHandler` slog bridge | new `internal/logutil/bridge.go` | +15 | — | +| 4 | `remote.NewWarningLogger()` via bridge | `option/remote.go`, `option/binary_target.go` | −25 | 3 | +| 5 | `ClientBuilder` in `NewRepository()`/`NewRegistry()` | `option/remote.go` | −40+30 | 3,4 | +| 6 | `config.LoadConfigs()` full config stack | `option/remote.go` | +30 | 5 | +| 7 | `remote.NewLoggingTransport()` via `builder.Logger` | `option/remote.go`, `internal/trace/` | −160 | 5 | +| 8 | `oras.CopyError` structured errors | `root/cp.go`, `root/push.go`, etc. | +20 | — | +| 9 | `remote.NewCredentialFunc()` | `option/remote.go` | −2 | — (or covered by 5) | + +Steps 1–2 are self-contained bug fixes. Steps 3–7 form a coherent refactor of the remote client construction path. Steps 8–9 are independent improvements. + +## Impact to Users and Ecosystem + +- **Podman/containers-tools users** get automatic credential discovery without `--registry-config` pointing at `auth.json`. +- **Enterprise/air-gapped users** get automatic mirror fallback from `registries.conf` with no CLI changes. +- **CI operators** sharing a cache directory (`ORAS_CACHE`) across parallel jobs no longer risk cache corruption from `oci.New()` concurrent writes. +- **All users** get clearer `oras cp` error messages distinguishing source failures from destination failures. +- **Codebase**: net reduction of ~300 lines of duplicated code once all steps are complete. diff --git a/go.mod b/go.mod index 341bc9a79..6698ef9e7 100644 --- a/go.mod +++ b/go.mod @@ -8,17 +8,18 @@ require ( github.com/morikuni/aec v1.1.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.1 + github.com/oras-project/oras-go/v3 v3.0.0-dev github.com/sirupsen/logrus v1.9.4 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 go.yaml.in/yaml/v4 v4.0.0-rc.4 golang.org/x/sync v0.20.0 golang.org/x/term v0.42.0 - oras.land/oras-go/v2 v2.6.0 ) require ( dario.cat/mergo v1.0.2 // indirect + github.com/BurntSushi/toml v1.4.0 // indirect github.com/Masterminds/goutils v1.1.1 // indirect github.com/Masterminds/semver/v3 v3.4.0 // indirect github.com/google/uuid v1.6.0 // indirect @@ -30,4 +31,5 @@ require ( github.com/spf13/cast v1.9.2 // indirect golang.org/x/crypto v0.45.0 // indirect golang.org/x/sys v0.43.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index ed9437350..4ec0ec605 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI= github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0= @@ -35,6 +37,8 @@ github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= +github.com/oras-project/oras-go/v3 v3.0.0-dev h1:y05Hp3FZY/N1HZwLA3lGtZeioDCGjKRgMmL5dSwusSU= +github.com/oras-project/oras-go/v3 v3.0.0-dev/go.mod h1:K6YuAuFiQDoNV5ARQSRxqJpTs9wJBbI2VP4D4q8rBSc= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= @@ -65,8 +69,7 @@ golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI= golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.42.0 h1:UiKe+zDFmJobeJ5ggPwOshJIVt6/Ft0rcfrXZDLWAWY= golang.org/x/term v0.42.0/go.mod h1:Dq/D+snpsbazcBG5+F9Q1n2rXV8Ma+71xEjTRufARgY= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -oras.land/oras-go/v2 v2.6.0 h1:X4ELRsiGkrbeox69+9tzTu492FMUu7zJQW6eJU+I2oc= -oras.land/oras-go/v2 v2.6.0/go.mod h1:magiQDfG6H1O9APp+rOsvCPcW1GD2MM7vgnKY0Y+u1o= diff --git a/internal/cache/target.go b/internal/cache/target.go index e9f775896..1b2f6a694 100644 --- a/internal/cache/target.go +++ b/internal/cache/target.go @@ -21,9 +21,9 @@ import ( "sync" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/registry" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/registry" ) type closer func() error diff --git a/internal/cache/target_test.go b/internal/cache/target_test.go index 469fb5c1d..96ba1223a 100644 --- a/internal/cache/target_test.go +++ b/internal/cache/target_test.go @@ -31,11 +31,11 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/memory" - "oras.land/oras-go/v2/registry" - "oras.land/oras-go/v2/registry/remote" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/memory" + "github.com/oras-project/oras-go/v3/registry" + "github.com/oras-project/oras-go/v3/registry/remote" ) func TestProxy_fetchCache(t *testing.T) { @@ -196,12 +196,12 @@ func TestProxy_fetchReference(t *testing.T) { if err != nil { t.Fatalf("NewRepository() error = %v", err) } - repo.PlainHTTP = true + repo.Registry.PlainHTTP = true p := New(repo, memory.New()) ctx := context.Background() // first fetch reference - gotDesc, rc, err := p.(registry.ReferenceFetcher).FetchReference(ctx, repo.Reference.Reference) + gotDesc, rc, err := p.(registry.ReferenceFetcher).FetchReference(ctx, tagName) if err != nil { t.Fatal("ReferenceTarget.FetchReference() error =", err) } @@ -228,7 +228,7 @@ func TestProxy_fetchReference(t *testing.T) { } // second fetch reference, should get the rc from the cache - gotDesc, rc, err = p.(registry.ReferenceFetcher).FetchReference(ctx, repo.Reference.Reference) + gotDesc, rc, err = p.(registry.ReferenceFetcher).FetchReference(ctx, tagName) if err != nil { t.Fatal("ReferenceTarget.FetchReference() error =", err) } diff --git a/internal/contentutil/target.go b/internal/contentutil/target.go index d55734dd8..c2ce42dca 100644 --- a/internal/contentutil/target.go +++ b/internal/contentutil/target.go @@ -21,8 +21,8 @@ import ( "io" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/errdef" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/errdef" ) type multiReadOnlyTarget struct { diff --git a/internal/credential/credential.go b/internal/credential/credential.go index e314d032a..8fa9843ca 100644 --- a/internal/credential/credential.go +++ b/internal/credential/credential.go @@ -15,16 +15,16 @@ limitations under the License. package credential -import "oras.land/oras-go/v2/registry/remote/auth" +import "github.com/oras-project/oras-go/v3/registry/remote/credentials" // Credential converts user input username and password to a credential. -func Credential(username, password string) auth.Credential { +func Credential(username, password string) credentials.Credential { if username == "" { - return auth.Credential{ + return credentials.Credential{ RefreshToken: password, } } - return auth.Credential{ + return credentials.Credential{ Username: username, Password: password, } diff --git a/internal/credential/credential_test.go b/internal/credential/credential_test.go index f5053c529..04bbceb28 100644 --- a/internal/credential/credential_test.go +++ b/internal/credential/credential_test.go @@ -18,19 +18,19 @@ package credential_test import ( "testing" - "oras.land/oras-go/v2/registry/remote/auth" + "github.com/oras-project/oras-go/v3/registry/remote/credentials" "oras.land/oras/internal/credential" ) func Test_Credential_emptyCredential(t *testing.T) { cred := credential.Credential("", "") - if cred != auth.EmptyCredential { + if cred != credentials.EmptyCredential { t.Fatalf("Expect empty credential but got %v", cred) } } func Test_Credential_usernamePassword(t *testing.T) { - expected := auth.Credential{ + expected := credentials.Credential{ Username: "username", Password: "password", } @@ -41,7 +41,7 @@ func Test_Credential_usernamePassword(t *testing.T) { } func Test_Credential_refreshToken(t *testing.T) { - expected := auth.Credential{ + expected := credentials.Credential{ RefreshToken: "mocked", } cred := credential.Credential("", expected.RefreshToken) diff --git a/internal/credential/store.go b/internal/credential/store.go index 798eb367d..44adc2534 100644 --- a/internal/credential/store.go +++ b/internal/credential/store.go @@ -16,7 +16,8 @@ limitations under the License. package credential import ( - "oras.land/oras-go/v2/registry/remote/credentials" + _ "github.com/oras-project/oras-go/v3/registry/remote/config" // registers config loader + "github.com/oras-project/oras-go/v3/registry/remote/credentials" ) // NewStore generates a store based on the passed-in config file paths. diff --git a/internal/graph/graph.go b/internal/graph/graph.go index 5dc298b99..49e688e1f 100644 --- a/internal/graph/graph.go +++ b/internal/graph/graph.go @@ -21,10 +21,10 @@ import ( "sync" ocispec "github.com/opencontainers/image-spec/specs-go/v1" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/registry" "golang.org/x/sync/errgroup" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/registry" "oras.land/oras/internal/docker" ) diff --git a/internal/graph/graph_test.go b/internal/graph/graph_test.go index 9807fd020..ec9e562e8 100644 --- a/internal/graph/graph_test.go +++ b/internal/graph/graph_test.go @@ -26,9 +26,9 @@ import ( "github.com/opencontainers/go-digest" "github.com/opencontainers/image-spec/specs-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/memory" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/memory" "oras.land/oras/internal/docker" "oras.land/oras/internal/testutils" ) diff --git a/internal/listener/tag.go b/internal/listener/tag.go index e7a17f658..e9ef9f20f 100644 --- a/internal/listener/tag.go +++ b/internal/listener/tag.go @@ -20,8 +20,8 @@ import ( "io" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" - "oras.land/oras-go/v2/registry" + "github.com/oras-project/oras-go/v3" + "github.com/oras-project/oras-go/v3/registry" ) // NewTagListener creates a wrapper type for printing a tag status and hint. diff --git a/internal/listener/tag_test.go b/internal/listener/tag_test.go index 3039d2a47..569ea124b 100644 --- a/internal/listener/tag_test.go +++ b/internal/listener/tag_test.go @@ -21,8 +21,8 @@ import ( "testing" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content/memory" - "oras.land/oras-go/v2/registry/remote" + "github.com/oras-project/oras-go/v3/content/memory" + "github.com/oras-project/oras-go/v3/registry/remote" ) func TestNewTagListener(t *testing.T) { diff --git a/internal/mock/repository.go b/internal/mock/repository.go index a5abc5d5a..92423a9a3 100644 --- a/internal/mock/repository.go +++ b/internal/mock/repository.go @@ -25,7 +25,7 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/registry/remote" + "github.com/oras-project/oras-go/v3/registry/remote" ) type content struct { diff --git a/internal/registryutil/auth.go b/internal/registryutil/auth.go index 0805e60eb..7ab5bdc94 100644 --- a/internal/registryutil/auth.go +++ b/internal/registryutil/auth.go @@ -18,14 +18,15 @@ package registryutil import ( "context" - "oras.land/oras-go/v2/registry/remote" - "oras.land/oras-go/v2/registry/remote/auth" + "github.com/oras-project/oras-go/v3/registry/remote" + "github.com/oras-project/oras-go/v3/registry/remote/auth" ) // WithScopeHint adds a hinted scope to the context. func WithScopeHint(ctx context.Context, target any, actions ...string) context.Context { if repo, ok := target.(*remote.Repository); ok { - return auth.AppendRepositoryScope(ctx, repo.Reference, actions...) + scope := auth.ScopeRepository(repo.RepositoryName, actions...) + return auth.AppendScopesForHost(ctx, repo.Registry.Reference.Registry, scope) } return ctx } diff --git a/internal/repository/repository.go b/internal/repository/repository.go index c28502cc6..cf33db0c1 100644 --- a/internal/repository/repository.go +++ b/internal/repository/repository.go @@ -19,19 +19,19 @@ import ( "fmt" "strings" - "oras.land/oras-go/v2/registry" + "github.com/oras-project/oras-go/v3/registry/remote/properties" ) // ParseRemoteRepository extracts hostname and namespace from rawReference. func ParseRemoteRepository(rawReference string) (hostname, namespace string, err error) { rawReference = strings.TrimSuffix(rawReference, "/") if strings.Contains(rawReference, "/") { - var ref registry.Reference - ref, err = registry.ParseReference(rawReference) + var ref properties.Reference + ref, err = properties.NewReference(rawReference) if err != nil { return } - if ref.Reference != "" { + if ref.GetReference() != "" { err = fmt.Errorf("tags or digests should not be provided") return } diff --git a/internal/testutils/fetcher.go b/internal/testutils/fetcher.go index 19cda6f77..33712fb1f 100644 --- a/internal/testutils/fetcher.go +++ b/internal/testutils/fetcher.go @@ -22,8 +22,8 @@ import ( "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2/content" - "oras.land/oras-go/v2/content/memory" + "github.com/oras-project/oras-go/v3/content" + "github.com/oras-project/oras-go/v3/content/memory" "oras.land/oras/internal/docker" ) diff --git a/internal/testutils/prompt.go b/internal/testutils/prompt.go index 797d5d40b..3da782b64 100644 --- a/internal/testutils/prompt.go +++ b/internal/testutils/prompt.go @@ -19,7 +19,7 @@ import ( "io" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" + "github.com/oras-project/oras-go/v3" "oras.land/oras/internal/progress" ) diff --git a/scripts/release.sh b/scripts/release.sh new file mode 100755 index 000000000..bee7df2a4 --- /dev/null +++ b/scripts/release.sh @@ -0,0 +1,582 @@ +#!/usr/bin/env bash +# Copyright The ORAS Authors. +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +set -euo pipefail + +# ORAS Release Helper Script +# Usage: scripts/release.sh [args...] +# Phases: prep, tag, validate, publish + +REPO="oras-project/oras" +VERSION_FILE="internal/version/version.go" +REMOTE="${ORAS_REMOTE:-upstream}" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +CYAN='\033[0;36m' +NC='\033[0m' # No Color + +info() { echo -e "${CYAN}[INFO]${NC} $*"; } +success() { echo -e "${GREEN}[OK]${NC} $*"; } +warn() { echo -e "${YELLOW}[MANUAL]${NC} $*"; } +error() { echo -e "${RED}[ERROR]${NC} $*" >&2; } + +DRY_RUN=false + +# Parse global flags +parse_global_flags() { + local args=() + for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=true ;; + *) args+=("$arg") ;; + esac + done + echo "${args[@]:-}" +} + +run() { + if [ "$DRY_RUN" = true ]; then + info "[DRY-RUN] $*" + return 0 + fi + "$@" +} + +confirm() { + if [ "$DRY_RUN" = true ]; then + info "[DRY-RUN] Would confirm: $1" + return 0 + fi + echo -en "${YELLOW}$1 [y/N]: ${NC}" + read -r response + case "$response" in + [yY][eE][sS]|[yY]) return 0 ;; + *) error "Aborted."; exit 1 ;; + esac +} + +# Validate semver format +validate_version() { + local version="$1" + if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then + error "Invalid version format: $version (expected semver like 1.2.3 or 1.2.3-rc.1)" + exit 1 + fi +} + +# Check if this is a new minor version (patch == 0, no pre-release) +is_new_minor() { + local version="$1" + local patch + patch=$(echo "$version" | cut -d. -f3 | cut -d- -f1) + if [[ "$patch" == "0" && ! "$version" =~ - ]]; then + return 0 + fi + return 1 +} + +# Get major.minor from version +get_major_minor() { + local version="$1" + echo "$version" | cut -d. -f1-2 +} + +############################################################################### +# Check prerequisites (gh, gpg, remote) +############################################################################### +check_prerequisites() { + info "Checking prerequisites..." + if ! command -v gh &>/dev/null; then + error "'gh' CLI not found. Install: https://cli.github.com" + exit 1 + fi + if ! gh auth status &>/dev/null; then + error "'gh' CLI not authenticated. Run: gh auth login" + exit 1 + fi + if ! command -v gpg &>/dev/null; then + error "'gpg' not found. Install GPG." + exit 1 + fi + if ! gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep -q sec; then + error "No GPG secret keys found. Import or generate a key." + exit 1 + fi + if ! git remote get-url "$REMOTE" &>/dev/null; then + error "Git remote '${REMOTE}' not found. Set ORAS_REMOTE or add the remote." + exit 1 + fi +} + +############################################################################### +# Phase 1: Prep +############################################################################### +do_prep() { + local version="$1" + validate_version "$version" + info "Preparing release v${version}" + + check_prerequisites + success "Prerequisites OK" + + # Check we're on main and up to date + local current_branch + current_branch=$(git branch --show-current) + if [ "$current_branch" != "main" ]; then + warn "Currently on branch '$current_branch', not 'main'." + confirm "Continue anyway?" + fi + + # Ensure working tree is clean + if ! git diff --quiet || ! git diff --cached --quiet; then + error "Working tree is not clean. Commit or stash changes before running prep." + exit 1 + fi + + # Update version file + info "Updating ${VERSION_FILE}..." + sed -i.bak -E "s/Version = \"[^\"]+\"/Version = \"${version}\"/" "$VERSION_FILE" + sed -i.bak -E "s/BuildMetadata = \"[^\"]*\"/BuildMetadata = \"\"/" "$VERSION_FILE" + rm -f "${VERSION_FILE}.bak" + success "Version set to ${version}" + + # Show the diff + git diff "$VERSION_FILE" + + # Create branch, commit, push, PR + local branch="chore/release-v${version}" + info "Creating branch ${branch}..." + run git checkout -b "$branch" + run git add "$VERSION_FILE" + run git commit -m "bump: tag and release ORAS CLI v${version}" + run git push "${REMOTE}" "$branch" + + info "Creating pull request..." + local pr_url + if [ "$DRY_RUN" = true ]; then + pr_url="https://github.com/${REPO}/pull/DRY-RUN" + info "[DRY-RUN] Would create PR" + else + pr_url=$(gh pr create \ + --repo "$REPO" \ + --title "bump: tag and release ORAS CLI v${version}" \ + --body "$(cat <" +} + +############################################################################### +# Phase 2: Tag +############################################################################### +do_tag() { + local version="$1" + local sha="${2:-}" + validate_version "$version" + + if [ -z "$sha" ]; then + error "Usage: scripts/release.sh tag " + exit 1 + fi + + info "Tagging v${version} at ${sha}" + + check_prerequisites + success "Prerequisites OK" + + # Verify the commit exists and is on main + if ! git cat-file -t "$sha" &>/dev/null; then + error "Commit ${sha} not found. Did you fetch latest?" + exit 1 + fi + + # Check that the version file at that commit has the right version + local file_version + file_version=$(git show "${sha}:${VERSION_FILE}" | grep 'Version = ' | sed -E 's/.*"([^"]+)".*/\1/') + if [ "$file_version" != "$version" ]; then + error "Version in ${VERSION_FILE} at ${sha} is '${file_version}', expected '${version}'" + exit 1 + fi + + # Create signed tag + confirm "Create signed tag v${version} at ${sha}?" + run git tag -s "v${version}" "$sha" -m "Release v${version}" + success "Tag v${version} created" + + # Push tag + confirm "Push tag v${version} to ${REMOTE}?" + run git push "${REMOTE}" "v${version}" + success "Tag pushed" + + # Create release branch for new minor versions + if is_new_minor "$version"; then + local release_branch="release-$(get_major_minor "$version")" + info "New minor version detected. Creating release branch ${release_branch}..." + run git branch "$release_branch" "$sha" + confirm "Push release branch ${release_branch} to ${REMOTE}?" + run git push "${REMOTE}" "$release_branch" + success "Release branch ${release_branch} pushed" + fi + + echo "" + info "CI workflows triggered. Monitor at:" + echo " https://github.com/${REPO}/actions?query=event%3Apush+branch%3Av${version}" + echo "" + warn "Once CI completes, run:" + echo " scripts/release.sh validate ${version}" +} + +############################################################################### +# Phase 3: Validate +############################################################################### +do_validate() { + local version="$1" + validate_version "$version" + info "Validating release v${version}" + + # Wait for CI workflows + info "Checking CI workflow status..." + local workflows=("release-ghcr" "release-github") + local all_done=false + local max_attempts=60 # 30 minutes at 30s intervals + local attempt=0 + + while [ "$all_done" != "true" ] && [ "$attempt" -lt "$max_attempts" ]; do + all_done=true + for wf in "${workflows[@]}"; do + local status + status=$(gh run list \ + --repo "$REPO" \ + --workflow "$wf" \ + --branch "v${version}" \ + --limit 1 \ + --json status,conclusion \ + --jq '.[0] | "\(.status) \(.conclusion)"' 2>/dev/null || echo "not_found") + + if [[ "$status" == *"completed success"* ]]; then + success "Workflow ${wf}: completed successfully" + elif [[ "$status" == *"completed"* ]]; then + error "Workflow ${wf}: ${status}" + exit 1 + elif [[ "$status" == "not_found" ]]; then + warn "Workflow ${wf}: not found yet" + all_done=false + else + info "Workflow ${wf}: ${status} (waiting...)" + all_done=false + fi + done + + if [ "$all_done" != "true" ]; then + ((attempt++)) + if [ "$attempt" -lt "$max_attempts" ]; then + info "Waiting 30s for workflows... (attempt ${attempt}/${max_attempts})" + sleep 30 + fi + fi + done + + if [ "$all_done" != "true" ]; then + error "Timed out waiting for workflows" + exit 1 + fi + success "All CI workflows completed" + + # Fetch distribution artifacts + info "Fetching distribution artifacts..." + run make fetch-dist VERSION="$version" + success "Artifacts downloaded to _dist/" + + # Verify checksums + info "Verifying checksums..." + if command -v sha256sum >/dev/null 2>&1; then + (cd _dist && sha256sum -c "oras_${version}_checksums.txt" --ignore-missing) + elif command -v shasum >/dev/null 2>&1; then + (cd _dist && shasum -a 256 -c "oras_${version}_checksums.txt" --ignore-missing) + else + error "Neither sha256sum nor shasum is available; cannot verify checksums." + exit 1 + fi + success "Checksums verified" + + # Test binary + info "Testing linux/amd64 binary..." + local tmpdir + tmpdir=$(mktemp -d) + tar -xzf "_dist/oras_${version}_linux_amd64.tar.gz" -C "$tmpdir" + local bin_version + bin_version=$("$tmpdir/oras" version 2>/dev/null | head -1 || echo "unknown") + rm -rf "$tmpdir" + + if echo "$bin_version" | grep -q "$version"; then + success "Binary version matches: ${bin_version}" + else + error "Binary version mismatch. Expected '${version}', got: ${bin_version}" + exit 1 + fi + + # Check git commit in binary + local tag_sha + tag_sha=$(git rev-list -n 1 "v${version}" 2>/dev/null || echo "unknown") + if echo "$bin_version" | grep -q "${tag_sha:0:7}"; then + success "Binary git commit matches tag SHA" + else + warn "Could not verify git commit in binary output (non-fatal)" + fi + + echo "" + success "All validation checks passed!" + echo "" + warn "Review the release notes at:" + echo " https://github.com/${REPO}/releases/tag/v${version}" + echo "" + warn "When ready, run:" + echo " scripts/release.sh publish ${version}" +} + +############################################################################### +# Phase 4: Sign & Publish +############################################################################### +do_publish() { + local version="$1" + validate_version "$version" + info "Publishing release v${version}" + + # Check artifacts exist + if [ ! -d "_dist" ]; then + error "_dist/ directory not found. Run 'scripts/release.sh validate ${version}' first." + exit 1 + fi + + # Sign artifacts + info "Signing artifacts with GPG..." + run make SHELL=/bin/bash sign + success "Artifacts signed" + + # Verify signatures + info "Verifying GPG signatures..." + local sig_count=0 + for asc in _dist/*.asc; do + [ -f "$asc" ] || continue + local orig="${asc%.asc}" + if gpg --verify "$asc" "$orig" 2>/dev/null; then + success "Verified: $(basename "$asc")" + ((sig_count++)) + else + error "Signature verification failed: $(basename "$asc")" + exit 1 + fi + done + if [ "$sig_count" -eq 0 ]; then + error "No .asc signature files found in _dist/" + exit 1 + fi + success "All ${sig_count} signatures verified" + + # Upload signatures to GitHub release + info "Uploading signatures to GitHub release..." + confirm "Upload ${sig_count} .asc files to release v${version}?" + if [[ "$DRY_RUN" == "true" ]]; then + info "[DRY-RUN] Would upload ${sig_count} .asc files to release v${version}" + else + gh release upload "v${version}" _dist/*.asc --repo "$REPO" + fi + success "Signatures uploaded" + + # Get GPG key fingerprint for release notes + local fingerprint + fingerprint=$(gpg --list-secret-keys --keyid-format LONG 2>/dev/null | grep sec | head -1 | awk '{print $2}' | cut -d/ -f2) + if [ -n "$fingerprint" ]; then + info "Adding signing key info to release notes..." + local note="## Verification\n\nAll release artifacts are signed with GPG key \`${fingerprint}\`. Signatures (\`.asc\` files) are attached to this release.\n\nPublic keys are available in the [KEYS](https://github.com/${REPO}/blob/main/KEYS) file." + if [ "$DRY_RUN" = true ]; then + info "[DRY-RUN] Would append signing info to release notes" + else + local existing_notes + existing_notes=$(gh release view "v${version}" --repo "$REPO" --json body --jq '.body') + gh release edit "v${version}" --repo "$REPO" --notes "$(printf '%s\n\n%b' "$existing_notes" "$note")" + fi + success "Release notes updated with signing key info" + fi + + # Publish release + confirm "Publish release v${version} (remove draft status)?" + run gh release edit "v${version}" --repo "$REPO" --draft=false + success "Release v${version} published!" + + # Trigger snap workflow + info "Triggering snap workflow..." + local is_stable="true" + if [[ "$version" == *"-"* ]]; then + is_stable="false" + fi + if [ "$DRY_RUN" = true ]; then + info "[DRY-RUN] Would trigger release-snap.yml with version=v${version} isStable=${is_stable}" + else + gh workflow run release-snap.yml \ + --repo "$REPO" \ + --ref "v${version}" \ + --field version="v${version}" \ + --field isStable="${is_stable}" 2>/dev/null \ + && success "Snap workflow triggered" \ + || warn "Could not trigger snap workflow. You may need to trigger it manually." + fi + + # Clean up + confirm "Remove _dist/ directory?" + run rm -rf _dist + success "Cleaned up _dist/" + + echo "" + success "Release v${version} is live!" + echo " https://github.com/${REPO}/releases/tag/v${version}" + echo "" + warn "Post-release steps (manual):" + echo " 1. Update oras-www docs if needed" + echo " 2. Announce in Slack #oras:" + echo "" + echo -e "${CYAN}---${NC}" + cat < [args...] + +Phases: + prep Bump version, create PR, print vote template + tag Create and push signed tag + validate Wait for CI, download and verify artifacts + publish Sign, upload signatures, publish release + +Flags: + --dry-run Print actions without executing them + +Environment: + ORAS_REMOTE Git remote name (default: upstream) + +Examples: + scripts/release.sh prep 1.3.0 + scripts/release.sh tag 1.3.0 abc1234 + scripts/release.sh validate 1.3.0 + scripts/release.sh publish 1.3.0 + scripts/release.sh --dry-run prep 1.3.0-rc.1 +EOF +} + +main() { + local args + args=$(parse_global_flags "$@") + # Re-split args + set -- $args + + local phase="${1:-}" + local version="${2:-}" + + if [ -z "$phase" ]; then + usage + exit 1 + fi + + # Ensure we're in the repo root + cd "$(git rev-parse --show-toplevel)" + + case "$phase" in + prep) + [ -z "$version" ] && { error "Usage: scripts/release.sh prep "; exit 1; } + do_prep "$version" + ;; + tag) + [ -z "$version" ] && { error "Usage: scripts/release.sh tag "; exit 1; } + do_tag "$version" "${3:-}" + ;; + validate) + [ -z "$version" ] && { error "Usage: scripts/release.sh validate "; exit 1; } + do_validate "$version" + ;; + publish) + [ -z "$version" ] && { error "Usage: scripts/release.sh publish "; exit 1; } + do_publish "$version" + ;; + help|--help|-h) + usage + ;; + *) + error "Unknown phase: ${phase}" + usage + exit 1 + ;; + esac +} + +main "$@" diff --git a/test/e2e/internal/utils/init.go b/test/e2e/internal/utils/init.go index 5218aa367..a9b571496 100644 --- a/test/e2e/internal/utils/init.go +++ b/test/e2e/internal/utils/init.go @@ -24,7 +24,7 @@ import ( . "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" "github.com/onsi/gomega/gexec" - "oras.land/oras-go/v2/registry" + "github.com/oras-project/oras-go/v3/registry" ) // ORASPath points to the to-be-tested oras binary. diff --git a/test/e2e/internal/utils/reference.go b/test/e2e/internal/utils/reference.go index 7c02e6c1a..6ba8cf34f 100644 --- a/test/e2e/internal/utils/reference.go +++ b/test/e2e/internal/utils/reference.go @@ -21,7 +21,7 @@ import ( "github.com/onsi/gomega" "github.com/opencontainers/go-digest" - "oras.land/oras-go/v2/registry" + "github.com/oras-project/oras-go/v3/registry" ) // RegistryRef generates the reference string from given parameters. diff --git a/test/e2e/suite/auth/auth.go b/test/e2e/suite/auth/auth.go index 00a89a2ff..18f46e739 100644 --- a/test/e2e/suite/auth/auth.go +++ b/test/e2e/suite/auth/auth.go @@ -24,7 +24,7 @@ import ( . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" - "oras.land/oras-go/v2" + "github.com/oras-project/oras-go/v3" "oras.land/oras/test/e2e/internal/testdata/feature" "oras.land/oras/test/e2e/internal/testdata/foobar" . "oras.land/oras/test/e2e/internal/utils" diff --git a/test/e2e/suite/command/backup.go b/test/e2e/suite/command/backup.go index 02c73f79a..e4f3d1fd0 100644 --- a/test/e2e/suite/command/backup.go +++ b/test/e2e/suite/command/backup.go @@ -28,7 +28,7 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" - "oras.land/oras-go/v2" + "github.com/oras-project/oras-go/v3" "oras.land/oras/test/e2e/internal/testdata/feature" "oras.land/oras/test/e2e/internal/testdata/foobar" ma "oras.land/oras/test/e2e/internal/testdata/multi_arch" diff --git a/test/e2e/suite/command/cp.go b/test/e2e/suite/command/cp.go index 2892954a7..2ec12877d 100644 --- a/test/e2e/suite/command/cp.go +++ b/test/e2e/suite/command/cp.go @@ -26,7 +26,7 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" ocispec "github.com/opencontainers/image-spec/specs-go/v1" - "oras.land/oras-go/v2" + "github.com/oras-project/oras-go/v3" "oras.land/oras/test/e2e/internal/testdata/artifact/blob" "oras.land/oras/test/e2e/internal/testdata/artifact/config" "oras.land/oras/test/e2e/internal/testdata/artifact/index" diff --git a/test/e2e/suite/command/restore.go b/test/e2e/suite/command/restore.go index 54653c376..40169d487 100644 --- a/test/e2e/suite/command/restore.go +++ b/test/e2e/suite/command/restore.go @@ -28,7 +28,7 @@ import ( . "github.com/onsi/gomega" "github.com/onsi/gomega/gbytes" - "oras.land/oras-go/v2" + "github.com/oras-project/oras-go/v3" "oras.land/oras/test/e2e/internal/testdata/feature" "oras.land/oras/test/e2e/internal/testdata/foobar" ma "oras.land/oras/test/e2e/internal/testdata/multi_arch"