From 585e50f1978b6e0e7372b4cef25b5b4f312fa2c4 Mon Sep 17 00:00:00 2001 From: zongz Date: Mon, 13 Nov 2023 17:38:47 +0800 Subject: [PATCH] feat: add 'kpm update' to update the dependencies Signed-off-by: zongz --- kpm.go | 1 + pkg/client/client.go | 68 ++++++++++++++++++ pkg/client/client_test.go | 62 +++++++++++++++++ .../test_update/test_update_kcl_mod/expected | 9 +++ .../test_update/test_update_kcl_mod/kcl.mod | 7 ++ .../test_update_kcl_mod/kcl.mod.lock | 0 .../test_update/test_update_kcl_mod/main.k | 1 + .../test_update_kcl_mod_lock/expected | 0 .../test_update_kcl_mod_lock/kcl.mod | 4 ++ .../test_update_kcl_mod_lock/kcl.mod.lock | 9 +++ .../test_update_kcl_mod_lock/main.k | 1 + pkg/cmd/cmd_push.go | 6 +- pkg/cmd/cmd_update.go | 69 +++++++++++++++++++ pkg/constants/constants.go | 1 + pkg/oci/oci.go | 10 ++- pkg/package/package.go | 5 ++ pkg/reporter/reporter.go | 2 + pkg/utils/utils.go | 6 +- test/e2e/kpm_test.go | 7 +- .../help_msg/test_suite.stdout | 1 + .../test_suite.stdout | 2 +- .../expected_oci_manifest.json | 2 +- 22 files changed, 264 insertions(+), 9 deletions(-) create mode 100644 pkg/client/test_data/test_update/test_update_kcl_mod/expected create mode 100644 pkg/client/test_data/test_update/test_update_kcl_mod/kcl.mod create mode 100644 pkg/client/test_data/test_update/test_update_kcl_mod/kcl.mod.lock create mode 100644 pkg/client/test_data/test_update/test_update_kcl_mod/main.k create mode 100644 pkg/client/test_data/test_update/test_update_kcl_mod_lock/expected create mode 100644 pkg/client/test_data/test_update/test_update_kcl_mod_lock/kcl.mod create mode 100644 pkg/client/test_data/test_update/test_update_kcl_mod_lock/kcl.mod.lock create mode 100644 pkg/client/test_data/test_update/test_update_kcl_mod_lock/main.k create mode 100644 pkg/cmd/cmd_update.go rename test/e2e/test_suites/test_data/{test_push_with_oci_manifest => }/expected_oci_manifest.json (81%) diff --git a/kpm.go b/kpm.go index f6958d23..65ae09d2 100644 --- a/kpm.go +++ b/kpm.go @@ -37,6 +37,7 @@ func main() { cmd.NewLogoutCmd(kpmcli), cmd.NewPushCmd(kpmcli), cmd.NewPullCmd(kpmcli), + cmd.NewUpdateCmd(kpmcli), } app.Flags = []cli.Flag{ &cli.BoolFlag{ diff --git a/pkg/client/client.go b/pkg/client/client.go index ae15f965..e0a04bcb 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -9,6 +9,7 @@ import ( "reflect" "strings" + ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/otiai10/copy" "kcl-lang.io/kcl-go/pkg/kcl" "kcl-lang.io/kpm/pkg/constants" @@ -22,6 +23,7 @@ import ( "kcl-lang.io/kpm/pkg/runner" "kcl-lang.io/kpm/pkg/settings" "kcl-lang.io/kpm/pkg/utils" + "oras.land/oras-go/v2" ) // KpmClient is the client of kpm. @@ -97,6 +99,33 @@ func (c *KpmClient) ResolveDepsIntoMap(kclPkg *pkg.KclPkg) (map[string]string, e return pkgMap, nil } +// / fillPkgInfoFromOciMenifast will fill the package information from the oci manifest. +func (c *KpmClient) fillPkgInfoFromOciMenifast(name, tag string, dep pkg.Dependency) (pkg.Dependency, error) { + manifest := ocispec.Manifest{} + jsonDesc, err := c.FetchOciManifestIntoJsonStr(opt.OciFetchOptions{ + FetchBytesOptions: oras.DefaultFetchBytesOptions, + OciOptions: opt.OciOptions{ + Reg: c.GetSettings().DefaultOciRegistry(), + Repo: fmt.Sprintf("%s/%s", c.GetSettings().DefaultOciRepo(), name), + Tag: tag, + }, + }) + + if err != nil { + return dep, err + } + + err = json.Unmarshal([]byte(jsonDesc), &manifest) + if err != nil { + return dep, err + } + + if value, ok := manifest.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_SUM]; ok { + dep.Sum = value + } + return dep, nil +} + // ResolveDepsMetadata will calculate the local storage path of the external package, // and check whether the package exists locally. // If the package does not exist, it will re-download to the local. @@ -115,8 +144,33 @@ func (c *KpmClient) ResolvePkgDepsMetadata(kclPkg *pkg.KclPkg, update bool) erro } // alian the dependencies between kcl.mod and kcl.mod.lock + // clean the dependencies in kcl.mod.lock which not in kcl.mod + for name := range kclPkg.Dependencies.Deps { + if _, ok := kclPkg.ModFile.Dependencies.Deps[name]; !ok { + reporter.ReportEventTo( + reporter.NewEvent( + reporter.RemoveDep, + fmt.Sprintf("removing '%s'", name), + ), + c.logWriter, + ) + delete(kclPkg.Dependencies.Deps, name) + } + } + // add the dependencies in kcl.mod which not in kcl.mod.lock for name, d := range kclPkg.ModFile.Dependencies.Deps { if _, ok := kclPkg.Dependencies.Deps[name]; !ok { + reporter.ReportEventTo( + reporter.NewEvent( + reporter.AddDep, + fmt.Sprintf("adding '%s'", name), + ), + c.logWriter, + ) + d, err := c.fillPkgInfoFromOciMenifast(name, d.Version, d) + if err != nil { + return err + } kclPkg.Dependencies.Deps[name] = d } } @@ -176,6 +230,20 @@ func (c *KpmClient) ResolvePkgDepsMetadata(kclPkg *pkg.KclPkg, update bool) erro return nil } +// / UpdateDeps will update the dependencies. +func (c *KpmClient) UpdateDeps(kclPkg *pkg.KclPkg) error { + _, err := c.ResolveDepsMetadataInJsonStr(kclPkg, true) + if err != nil { + return err + } + + err = kclPkg.UpdateModAndLockFile() + if err != nil { + return err + } + return nil +} + // ResolveDepsMetadataInJsonStr will calculate the local storage path of the external package, // and check whether the package exists locally. If the package does not exist, it will re-download to the local. // Finally, the calculated metadata of the dependent packages is serialized into a json string and returned. diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 6f04d29b..c01c24ec 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -10,6 +10,7 @@ import ( "path/filepath" "testing" + "github.com/otiai10/copy" "github.com/stretchr/testify/assert" "kcl-lang.io/kpm/pkg/env" "kcl-lang.io/kpm/pkg/opt" @@ -687,3 +688,64 @@ func TestParseOciOptionFromString(t *testing.T) { assert.Equal(t, ociOption.Repo, "/test_oci_repo") assert.Equal(t, ociOption.Tag, "test_tag") } + +func TestUpdateWithKclMod(t *testing.T) { + kpmcli, err := NewKpmClient() + assert.Equal(t, err, nil) + + testDir := getTestDir("test_update") + src_testDir := filepath.Join(testDir, "test_update_kcl_mod") + dest_testDir := filepath.Join(testDir, "test_update_kcl_mod_tmp") + err = copy.Copy(src_testDir, dest_testDir) + assert.Equal(t, err, nil) + + kclPkg, err := pkg.LoadKclPkg(dest_testDir) + assert.Equal(t, err, nil) + err = kpmcli.UpdateDeps(kclPkg) + assert.Equal(t, err, nil) + got_lock_file := filepath.Join(dest_testDir, "kcl.mod.lock") + got_content, err := os.ReadFile(got_lock_file) + assert.Equal(t, err, nil) + + expected_path := filepath.Join(dest_testDir, "expected") + expected_content, err := os.ReadFile(expected_path) + + assert.Equal(t, err, nil) + assert.Equal(t, string(got_content), string(expected_content)) + + defer func() { + err := os.RemoveAll(dest_testDir) + assert.Equal(t, err, nil) + }() +} + + +func TestUpdateWithKclModlock(t *testing.T) { + kpmcli, err := NewKpmClient() + assert.Equal(t, err, nil) + + testDir := getTestDir("test_update") + src_testDir := filepath.Join(testDir, "test_update_kcl_mod_lock") + dest_testDir := filepath.Join(testDir, "test_update_kcl_mod_lock_tmp") + err = copy.Copy(src_testDir, dest_testDir) + assert.Equal(t, err, nil) + + kclPkg, err := pkg.LoadKclPkg(dest_testDir) + assert.Equal(t, err, nil) + err = kpmcli.UpdateDeps(kclPkg) + assert.Equal(t, err, nil) + got_lock_file := filepath.Join(dest_testDir, "kcl.mod.lock") + got_content, err := os.ReadFile(got_lock_file) + assert.Equal(t, err, nil) + + expected_path := filepath.Join(dest_testDir, "expected") + expected_content, err := os.ReadFile(expected_path) + + assert.Equal(t, err, nil) + assert.Equal(t, string(got_content), string(expected_content)) + + defer func() { + err := os.RemoveAll(dest_testDir) + assert.Equal(t, err, nil) + }() +} \ No newline at end of file diff --git a/pkg/client/test_data/test_update/test_update_kcl_mod/expected b/pkg/client/test_data/test_update/test_update_kcl_mod/expected new file mode 100644 index 00000000..6270d4f4 --- /dev/null +++ b/pkg/client/test_data/test_update/test_update_kcl_mod/expected @@ -0,0 +1,9 @@ +[dependencies] + [dependencies.helloworld] + name = "helloworld" + full_name = "helloworld_0.1.1" + version = "0.1.1" + sum = "7OO4YK2QuRWPq9C7KTzcWcti5yUnueCjptT3OXiPVeQ=" + reg = "ghcr.io" + repo = "kcl-lang/helloworld" + oci_tag = "0.1.1" diff --git a/pkg/client/test_data/test_update/test_update_kcl_mod/kcl.mod b/pkg/client/test_data/test_update/test_update_kcl_mod/kcl.mod new file mode 100644 index 00000000..d3a99616 --- /dev/null +++ b/pkg/client/test_data/test_update/test_update_kcl_mod/kcl.mod @@ -0,0 +1,7 @@ +[package] +name = "test_update" +edition = "0.0.1" +version = "0.0.1" + +[dependencies] +helloworld = "0.1.1" diff --git a/pkg/client/test_data/test_update/test_update_kcl_mod/kcl.mod.lock b/pkg/client/test_data/test_update/test_update_kcl_mod/kcl.mod.lock new file mode 100644 index 00000000..e69de29b diff --git a/pkg/client/test_data/test_update/test_update_kcl_mod/main.k b/pkg/client/test_data/test_update/test_update_kcl_mod/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/pkg/client/test_data/test_update/test_update_kcl_mod/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/pkg/client/test_data/test_update/test_update_kcl_mod_lock/expected b/pkg/client/test_data/test_update/test_update_kcl_mod_lock/expected new file mode 100644 index 00000000..e69de29b diff --git a/pkg/client/test_data/test_update/test_update_kcl_mod_lock/kcl.mod b/pkg/client/test_data/test_update/test_update_kcl_mod_lock/kcl.mod new file mode 100644 index 00000000..f43948ad --- /dev/null +++ b/pkg/client/test_data/test_update/test_update_kcl_mod_lock/kcl.mod @@ -0,0 +1,4 @@ +[package] +name = "test_update" +edition = "0.0.1" +version = "0.0.1" diff --git a/pkg/client/test_data/test_update/test_update_kcl_mod_lock/kcl.mod.lock b/pkg/client/test_data/test_update/test_update_kcl_mod_lock/kcl.mod.lock new file mode 100644 index 00000000..6270d4f4 --- /dev/null +++ b/pkg/client/test_data/test_update/test_update_kcl_mod_lock/kcl.mod.lock @@ -0,0 +1,9 @@ +[dependencies] + [dependencies.helloworld] + name = "helloworld" + full_name = "helloworld_0.1.1" + version = "0.1.1" + sum = "7OO4YK2QuRWPq9C7KTzcWcti5yUnueCjptT3OXiPVeQ=" + reg = "ghcr.io" + repo = "kcl-lang/helloworld" + oci_tag = "0.1.1" diff --git a/pkg/client/test_data/test_update/test_update_kcl_mod_lock/main.k b/pkg/client/test_data/test_update/test_update_kcl_mod_lock/main.k new file mode 100644 index 00000000..fa7048e6 --- /dev/null +++ b/pkg/client/test_data/test_update/test_update_kcl_mod_lock/main.k @@ -0,0 +1 @@ +The_first_kcl_program = 'Hello World!' \ No newline at end of file diff --git a/pkg/cmd/cmd_push.go b/pkg/cmd/cmd_push.go index 05f3c4cc..a7477fe3 100644 --- a/pkg/cmd/cmd_push.go +++ b/pkg/cmd/cmd_push.go @@ -167,7 +167,11 @@ func pushPackage(ociUrl string, kclPkg *pkg.KclPkg, vendorMode bool, kpmcli *cli "only support url scheme 'oci://'.", ) } - ociOpts.Annotations = oci.GenOciManifestFromPkg(kclPkg) + + ociOpts.Annotations, err = oci.GenOciManifestFromPkg(kclPkg) + if err != nil { + return err + } reporter.ReportMsgTo(fmt.Sprintf("kpm: package '%s' will be pushed", kclPkg.GetPkgName()), kpmcli.GetLogWriter()) // 4. Push it. diff --git a/pkg/cmd/cmd_update.go b/pkg/cmd/cmd_update.go new file mode 100644 index 00000000..9e08ee89 --- /dev/null +++ b/pkg/cmd/cmd_update.go @@ -0,0 +1,69 @@ +// Copyright 2023 The KCL Authors. All rights reserved. + +package cmd + +import ( + "os" + + "github.com/urfave/cli/v2" + "kcl-lang.io/kpm/pkg/client" + "kcl-lang.io/kpm/pkg/env" + "kcl-lang.io/kpm/pkg/errors" + pkg "kcl-lang.io/kpm/pkg/package" + "kcl-lang.io/kpm/pkg/reporter" +) + +// NewUpdateCmd new a Command for `kpm update`. +func NewUpdateCmd(kpmcli *client.KpmClient) *cli.Command { + return &cli.Command{ + Hidden: false, + Name: "update", + Usage: "Update dependencies listed in kcl.mod.lock", + Action: func(c *cli.Context) error { + return KpmUpdate(c, kpmcli) + }, + } +} + +func KpmUpdate(c *cli.Context, kpmcli *client.KpmClient) error { + input_paths := c.Args().Slice() + + pkg_paths := []string{} + if len(input_paths) == 0 { + pwd, err := os.Getwd() + if err != nil { + return errors.InternalBug + } + pkg_paths = append(pkg_paths, pwd) + } else { + pkg_paths = input_paths + } + + for _, pkg_path := range pkg_paths { + kclPkg, err := pkg.LoadKclPkg(pkg_path) + if err != nil { + return err + } + + globalPkgPath, err := env.GetAbsPkgPath() + if err != nil { + return err + } + + err = kclPkg.ValidateKpmHome(globalPkgPath) + if err != (*reporter.KpmEvent)(nil) { + return err + } + + _, err = kpmcli.ResolveDepsMetadataInJsonStr(kclPkg, true) + if err != nil { + return err + } + + err = kclPkg.UpdateModAndLockFile() + if err != nil { + return err + } + } + return nil +} diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index cbd41662..c8cd3fcd 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -17,5 +17,6 @@ const ( DEFAULT_KCL_OCI_MANIFEST_NAME = "org.kcllang.package.name" DEFAULT_KCL_OCI_MANIFEST_VERSION = "org.kcllang.package.version" DEFAULT_KCL_OCI_MANIFEST_DESCRIPTION = "org.kcllang.package.description" + DEFAULT_KCL_OCI_MANIFEST_SUM = "org.kcllang.package.sum" DEFAULT_CREATE_OCI_MANIFEST_TIME = "org.opencontainers.image.created" ) diff --git a/pkg/oci/oci.go b/pkg/oci/oci.go index 24e042fa..1618c222 100644 --- a/pkg/oci/oci.go +++ b/pkg/oci/oci.go @@ -338,10 +338,16 @@ func Push(localPath, hostName, repoName, tag string, settings *settings.Settings return ociClient.Push(localPath, tag) } -func GenOciManifestFromPkg(kclPkg *pkg.KclPkg) map[string]string { +// GenOciManifestFromPkg will generate the oci manifest from the kcl package. +func GenOciManifestFromPkg(kclPkg *pkg.KclPkg) (map[string]string, error) { res := make(map[string]string) res[constants.DEFAULT_KCL_OCI_MANIFEST_NAME] = kclPkg.GetPkgName() res[constants.DEFAULT_KCL_OCI_MANIFEST_VERSION] = kclPkg.GetPkgVersion() res[constants.DEFAULT_KCL_OCI_MANIFEST_DESCRIPTION] = kclPkg.GetPkgDescription() - return res + sum, err := kclPkg.GenCheckSum() + if err != nil { + return nil, err + } + res[constants.DEFAULT_KCL_OCI_MANIFEST_SUM] = sum + return res, nil } diff --git a/pkg/package/package.go b/pkg/package/package.go index cc5270c6..de762f08 100644 --- a/pkg/package/package.go +++ b/pkg/package/package.go @@ -194,3 +194,8 @@ func (KclPkg *KclPkg) GetPkgVersion() string { func (KclPkg *KclPkg) GetPkgDescription() string { return KclPkg.ModFile.Pkg.Description } + +// GenCheckSum generates the checksum of the current kcl package. +func (KclPkg *KclPkg) GenCheckSum() (string, error) { + return utils.HashDir(KclPkg.HomePath) +} diff --git a/pkg/reporter/reporter.go b/pkg/reporter/reporter.go index ce8d667e..95b21a36 100644 --- a/pkg/reporter/reporter.go +++ b/pkg/reporter/reporter.go @@ -98,6 +98,8 @@ const ( AddItselfAsDep PkgTagExists DependencyNotFound + RemoveDep + AddDep KclModNotFound CompileFailed FailedParseVersion diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index 6511ad19..49e88bb6 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -38,8 +38,10 @@ func HashDir(dir string) (string, error) { // files in the ".git "directory will cause the same repository, cloned at different times, // has different checksum. - if strings.Contains(path, ".git") { - return nil + for _, ignore := range ignores { + if strings.Contains(path, ignore) { + return nil + } } f, err := os.Open(path) diff --git a/test/e2e/kpm_test.go b/test/e2e/kpm_test.go index ffa0c354..55ecf6f5 100644 --- a/test/e2e/kpm_test.go +++ b/test/e2e/kpm_test.go @@ -176,7 +176,7 @@ var _ = ginkgo.Describe("Kpm CLI Testing", func() { gomega.Expect(stderr).To(gomega.ContainSubstring(expectedStderr)) } - bytes, err := os.ReadFile(filepath.Join(testDataRoot, ts.Name, "expected_oci_manifest.json")) + bytes, err := os.ReadFile(filepath.Join(testDataRoot, "expected_oci_manifest.json")) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) // 2. fetch the metadata in OCI manifest to check if the metadata is correct @@ -209,6 +209,8 @@ var _ = ginkgo.Describe("Kpm CLI Testing", func() { To(gomega.Equal(manifest_got.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_VERSION])) gomega.Expect(manifest_expect.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_DESCRIPTION]). To(gomega.Equal(manifest_got.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_DESCRIPTION])) + gomega.Expect(manifest_expect.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_SUM]). + To(gomega.Equal(manifest_got.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_SUM])) }) ginkgo.It("testing 'fetch api '", func() { @@ -226,10 +228,11 @@ var _ = ginkgo.Describe("Kpm CLI Testing", func() { var manifest_expect v1.Manifest err = json.Unmarshal([]byte(jsonstr), &manifest_expect) gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) - gomega.Expect(len(manifest_expect.Annotations)).To(gomega.Equal(4)) + gomega.Expect(len(manifest_expect.Annotations)).To(gomega.Equal(5)) gomega.Expect(manifest_expect.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_NAME]).To(gomega.Equal("kcl2")) gomega.Expect(manifest_expect.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_VERSION]).To(gomega.Equal("0.0.1")) gomega.Expect(manifest_expect.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_DESCRIPTION]).To(gomega.Equal("This is the kcl package named kcl2")) + gomega.Expect(manifest_expect.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_SUM]).To(gomega.Equal("zQ7PTOcJi4gzXqypCWML6bsjToQU+E9Q2WZw/N3WnNY=")) }) } }) diff --git a/test/e2e/test_suites/kpm/exec_outside_pkg/help_msg/test_suite.stdout b/test/e2e/test_suites/kpm/exec_outside_pkg/help_msg/test_suite.stdout index 5d96e56c..929067af 100644 --- a/test/e2e/test_suites/kpm/exec_outside_pkg/help_msg/test_suite.stdout +++ b/test/e2e/test_suites/kpm/exec_outside_pkg/help_msg/test_suite.stdout @@ -9,4 +9,5 @@ COMMANDS: logout logout from a registry push push kcl package to OCI registry. pull pull kcl package from OCI registry. + update Update dependencies listed in kcl.mod.lock help, h Shows a list of commands or help for one command \ No newline at end of file diff --git a/test/e2e/test_suites/kpm/kpm_run/test_kpm_run_with_only_kcl_mod/test_suite.stdout b/test/e2e/test_suites/kpm/kpm_run/test_kpm_run_with_only_kcl_mod/test_suite.stdout index 52b79fa3..aa279768 100644 --- a/test/e2e/test_suites/kpm/kpm_run/test_kpm_run_with_only_kcl_mod/test_suite.stdout +++ b/test/e2e/test_suites/kpm/kpm_run/test_kpm_run_with_only_kcl_mod/test_suite.stdout @@ -1,4 +1,4 @@ -kpm: downloading 'test/k8s:1.27' from 'localhost:5001/test/k8s:1.27'. +kpm: adding 'k8s' apiVersion: v1 kind: Pod metadata: diff --git a/test/e2e/test_suites/test_data/test_push_with_oci_manifest/expected_oci_manifest.json b/test/e2e/test_suites/test_data/expected_oci_manifest.json similarity index 81% rename from test/e2e/test_suites/test_data/test_push_with_oci_manifest/expected_oci_manifest.json rename to test/e2e/test_suites/test_data/expected_oci_manifest.json index 1c966fc2..719a659f 100644 --- a/test/e2e/test_suites/test_data/test_push_with_oci_manifest/expected_oci_manifest.json +++ b/test/e2e/test_suites/test_data/expected_oci_manifest.json @@ -1 +1 @@ -{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","artifactType":"application/vnd.oci.image.layer.v1.tar","config":{"mediaType":"application/vnd.oci.empty.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2,"data":"e30="},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar","digest":"sha256:1d0b4bf7380ee67c23d48a16ebfbcc0720e9d0c59a1fe0f603e452ee8e99068f","size":4608,"annotations":{"org.opencontainers.image.title":"test_push_with_oci_manifest-0.0.1.tar"}}],"annotations":{"org.kcllang.package.description":"This is the description of the package","org.kcllang.package.name":"test_push_with_oci_manifest","org.kcllang.package.version":"0.0.1","org.opencontainers.image.created":"2023-10-23T06:24:49Z"}} \ No newline at end of file +{"schemaVersion":2,"mediaType":"application/vnd.oci.image.manifest.v1+json","artifactType":"application/vnd.oci.image.layer.v1.tar","config":{"mediaType":"application/vnd.oci.empty.v1+json","digest":"sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a","size":2,"data":"e30="},"layers":[{"mediaType":"application/vnd.oci.image.layer.v1.tar","digest":"sha256:1d0b4bf7380ee67c23d48a16ebfbcc0720e9d0c59a1fe0f603e452ee8e99068f","size":4608,"annotations":{"org.opencontainers.image.title":"test_push_with_oci_manifest-0.0.1.tar"}}],"annotations":{"org.kcllang.package.description":"This is the description of the package","org.kcllang.package.name":"test_push_with_oci_manifest","org.kcllang.package.version":"0.0.1","org.kcllang.package.sum":"ZxaNe8Na988Tnyh8hTInPhPYPWShgJInsgGYpxqxfe4=","org.opencontainers.image.created":"2023-10-23T06:24:49Z"}} \ No newline at end of file