Skip to content

Commit

Permalink
feat: add metadata into oci manifest when 'kpm push' (#205)
Browse files Browse the repository at this point in the history
* feat: add metadata into oci manifest when 'kpm push'

Signed-off-by: zongz <[email protected]>

* fix: fix CR comments

Signed-off-by: zongz <[email protected]>

* fix: fix CR comments

Signed-off-by: zongz <[email protected]>

---------

Signed-off-by: zongz <[email protected]>
  • Loading branch information
zong-zhe authored Oct 23, 2023
1 parent 01c6aa5 commit 0de32be
Show file tree
Hide file tree
Showing 23 changed files with 187 additions and 35 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.19
require (
github.com/BurntSushi/toml v1.2.1
github.com/docker/distribution v2.8.1+incompatible
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b
github.com/opencontainers/image-spec v1.1.0-rc4
github.com/otiai10/copy v1.9.0
github.com/sirupsen/logrus v1.9.0
github.com/urfave/cli/v2 v2.25.0
Expand Down Expand Up @@ -81,7 +81,7 @@ require (
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/mod v0.9.0 // indirect
golang.org/x/net v0.9.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sync v0.3.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/tools v0.7.0 // indirect
Expand All @@ -108,5 +108,5 @@ require (
github.com/thoas/go-funk v0.9.3
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
oras.land/oras-go v1.2.3
oras.land/oras-go/v2 v2.0.2
oras.land/oras-go/v2 v2.3.0
)
12 changes: 6 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -311,8 +311,8 @@ github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b h1:YWuSjZCQAPM8UUBLkYUk1e+rZcvWHJmFb6i6rM44Xs8=
github.com/opencontainers/image-spec v1.1.0-rc2.0.20221005185240-3a7f492d3f1b/go.mod h1:3OVijpioIKYWTqjiG0zfF6wvoJ4fAXGbjdZuI2NgsRQ=
github.com/opencontainers/image-spec v1.1.0-rc4 h1:oOxKUJWnFC4YGHCCMNql1x4YaDfYBTS5Y4x/Cgeo1E0=
github.com/opencontainers/image-spec v1.1.0-rc4/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8=
github.com/otiai10/copy v1.9.0 h1:7KFNiCgZ91Ru4qW4CWPf/7jqtxLagGRmIxWldPP9VY4=
github.com/otiai10/copy v1.9.0/go.mod h1:hsfX19wcn0UWIHUQ3/4fHuehhk2UyArQ9dVFAn3FczI=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
Expand Down Expand Up @@ -522,8 +522,8 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
Expand Down Expand Up @@ -769,8 +769,8 @@ kcl-lang.io/kcl-go v0.6.0-alpha.1 h1:BhMQ2GNRp9AccWxB2QydvZF6g6iVlPkkSSPa+RAdYx0
kcl-lang.io/kcl-go v0.6.0-alpha.1/go.mod h1:tHMTzp0dtah8Hn6h6UfnwbrEv737+TKf0xjIJkUkuaU=
oras.land/oras-go v1.2.3 h1:v8PJl+gEAntI1pJ/LCrDgsuk+1PKVavVEPsYIHFE5uY=
oras.land/oras-go v1.2.3/go.mod h1:M/uaPdYklze0Vf3AakfarnpoEckvw0ESbRdN8Z1vdJg=
oras.land/oras-go/v2 v2.0.2 h1:3aSQdJ7EUC0ft2e9PjJB9Jzastz5ojPA4LzZ3Q4YbUc=
oras.land/oras-go/v2 v2.0.2/go.mod h1:PWnWc/Kyyg7wUTUsDHshrsJkzuxXzreeMd6NrfdnFSo=
oras.land/oras-go/v2 v2.3.0 h1:lqX1aXdN+DAmDTKjiDyvq85cIaI4RkIKp/PghWlAGIU=
oras.land/oras-go/v2 v2.3.0/go.mod h1:GeAwLuC4G/JpNwkd+bSZ6SkDMGaaYglt6YK2WvZP7uQ=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
Expand Down
4 changes: 3 additions & 1 deletion pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -832,7 +832,9 @@ func (c *KpmClient) PushToOci(localPath string, ociOpts *opt.OciOptions) error {
)
}

return ociCli.Push(localPath, ociOpts.Tag)
return ociCli.PushWithOciManifest(localPath, ociOpts.Tag, &opt.OciManifestOptions{
Annotations: ociOpts.Annotations,
})
}

// LoginOci will login to the oci registry.
Expand Down
2 changes: 1 addition & 1 deletion pkg/cmd/cmd_push.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,13 @@ func pushPackage(ociUrl string, kclPkg *pkg.KclPkg, vendorMode bool, kpmcli *cli
"only support url scheme 'oci://'.",
)
}
ociOpts.Annotations = oci.GenOciManifestFromPkg(kclPkg)

reporter.ReportMsgTo(fmt.Sprintf("kpm: package '%s' will be pushed", kclPkg.GetPkgName()), kpmcli.GetLogWriter())
// 4. Push it.
err = kpmcli.PushToOci(tarPath, ociOpts)
if err != (*reporter.KpmEvent)(nil) {
return err
}

return nil
}
30 changes: 17 additions & 13 deletions pkg/constants/constants.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
package constants

const (
KFilePathSuffix = ".k"
TarPathSuffix = ".tar"
OciScheme = "oci"
FileEntry = "file"
FileWithKclModEntry = "file_with_kcl_mod"
UrlEntry = "url"
RefEntry = "ref"
TarEntry = "tar"
KCL_MOD = "kcl.mod"
OCI_SEPARATOR = ":"
KCL_PKG_TAR = "*.tar"
DEFAULT_KCL_FILE_NAME = "main.k"
DEFAULT_KCL_FILE_CONTENT = "The_first_kcl_program = 'Hello World!'"
KFilePathSuffix = ".k"
TarPathSuffix = ".tar"
OciScheme = "oci"
FileEntry = "file"
FileWithKclModEntry = "file_with_kcl_mod"
UrlEntry = "url"
RefEntry = "ref"
TarEntry = "tar"
KCL_MOD = "kcl.mod"
OCI_SEPARATOR = ":"
KCL_PKG_TAR = "*.tar"
DEFAULT_KCL_FILE_NAME = "main.k"
DEFAULT_KCL_FILE_CONTENT = "The_first_kcl_program = 'Hello World!'"
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_CREATE_OCI_MANIFEST_TIME = "org.opencontainers.image.created"
)
27 changes: 23 additions & 4 deletions pkg/oci/oci.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import (

v1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/thoas/go-funk"
"kcl-lang.io/kpm/pkg/constants"
"kcl-lang.io/kpm/pkg/errors"
"kcl-lang.io/kpm/pkg/opt"
pkg "kcl-lang.io/kpm/pkg/package"
"kcl-lang.io/kpm/pkg/reporter"
"kcl-lang.io/kpm/pkg/semver"
"kcl-lang.io/kpm/pkg/settings"
Expand Down Expand Up @@ -199,6 +202,11 @@ func (ociClient *OciClient) ContainsTag(tag string) (bool, *reporter.KpmEvent) {

// Push will push the oci artifacts to oci registry from local path
func (ociClient *OciClient) Push(localPath, tag string) *reporter.KpmEvent {
return ociClient.PushWithOciManifest(localPath, tag, &opt.OciManifestOptions{})
}

// PushWithManifest will push the oci artifacts to oci registry from local path
func (ociClient *OciClient) PushWithOciManifest(localPath, tag string, opts *opt.OciManifestOptions) *reporter.KpmEvent {
// 0. Create a file store
fs, err := file.New(filepath.Dir(localPath))
if err != nil {
Expand All @@ -222,10 +230,13 @@ func (ociClient *OciClient) Push(localPath, tag string) *reporter.KpmEvent {
fileDescriptors = append(fileDescriptors, fileDescriptor)
}

// 2. Pack the files and tag the packed manifest
manifestDescriptor, err := oras.Pack(*ociClient.ctx, fs, DEFAULT_OCI_ARTIFACT_TYPE, fileDescriptors, oras.PackOptions{
PackImageManifest: true,
})
// 2. Pack the files, tag the packed manifest and add metadata as annotations
packOpts := oras.PackManifestOptions{
ManifestAnnotations: opts.Annotations,
Layers: fileDescriptors,
}
manifestDescriptor, err := oras.PackManifest(*ociClient.ctx, fs, oras.PackManifestVersion1_1_RC4, DEFAULT_OCI_ARTIFACT_TYPE, packOpts)

if err != nil {
return reporter.NewErrorEvent(reporter.FailedPush, err, fmt.Sprintf("failed to pack package in '%s'", localPath))
}
Expand Down Expand Up @@ -315,3 +326,11 @@ func Push(localPath, hostName, repoName, tag string, settings *settings.Settings
// Push the oci package by the oci client.
return ociClient.Push(localPath, tag)
}

func GenOciManifestFromPkg(kclPkg *pkg.KclPkg) map[string]string {
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
}
13 changes: 9 additions & 4 deletions pkg/opt/opt.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,10 +142,11 @@ func (opts *GitOptions) Validate() error {
// OciOptions for download oci packages.
// kpm will download packages from oci registry by '{Reg}/{Repo}/{PkgName}:{Tag}'.
type OciOptions struct {
Reg string
Repo string
Tag string
PkgName string
Reg string
Repo string
Tag string
PkgName string
Annotations map[string]string
}

func (opts *OciOptions) Validate() error {
Expand Down Expand Up @@ -213,3 +214,7 @@ func ParseOciUrl(ociUrl string) (*OciOptions, *reporter.KpmEvent) {
func (oci *OciOptions) AddStoragePathSuffix(pathPrefix string) string {
return filepath.Join(filepath.Join(filepath.Join(pathPrefix, oci.Reg), oci.Repo), oci.Tag)
}

type OciManifestOptions struct {
Annotations map[string]string
}
7 changes: 4 additions & 3 deletions pkg/package/modfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,10 @@ const (

// 'Package' is the kcl package section of 'kcl.mod'.
type Package struct {
Name string `toml:"name,omitempty"` // kcl package name
Edition string `toml:"edition,omitempty"` // kcl compiler version
Version string `toml:"version,omitempty"` // kcl package version
Name string `toml:"name,omitempty"` // kcl package name
Edition string `toml:"edition,omitempty"` // kcl compiler version
Version string `toml:"version,omitempty"` // kcl package version
Description string `toml:"description,omitempty"` // kcl package description
}

// 'ModFile' is kcl package file 'kcl.mod'.
Expand Down
14 changes: 14 additions & 0 deletions pkg/package/modfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ import (
"kcl-lang.io/kpm/pkg/utils"
)

func TestModFileWithDesc(t *testing.T) {
testPath := getTestDir("test_mod_with_desc")
isExist, err := ModFileExists(testPath)
assert.Equal(t, isExist, true)
assert.Equal(t, err, nil)
modFile, err := LoadModFile(testPath)
assert.Equal(t, modFile.Pkg.Name, "test_mod_with_desc")
assert.Equal(t, modFile.Pkg.Version, "0.0.1")
assert.Equal(t, modFile.Pkg.Edition, "0.0.1")
assert.Equal(t, modFile.Pkg.Description, "This is a test module with a description")
assert.Equal(t, len(modFile.Dependencies.Deps), 0)
assert.Equal(t, err, nil)
}

func TestModFileExists(t *testing.T) {
testDir := initTestDir("test_data_modfile")
// there is no 'kcl.mod' and 'kcl.mod.lock'.
Expand Down
10 changes: 10 additions & 0 deletions pkg/package/package.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,3 +184,13 @@ const LOCK_FILE_NAME = "kcl.mod.lock"
func (kclPkg *KclPkg) GetLockFilePath() string {
return filepath.Join(kclPkg.HomePath, LOCK_FILE_NAME)
}

// GetPkgVersion returns the version of package.
func (KclPkg *KclPkg) GetPkgVersion() string {
return KclPkg.ModFile.Pkg.Version
}

// GetPkgDescription returns the description of package.
func (KclPkg *KclPkg) GetPkgDescription() string {
return KclPkg.ModFile.Pkg.Description
}
5 changes: 5 additions & 0 deletions pkg/package/test_data/test_mod_with_desc/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
name = "test_mod_with_desc"
edition = "0.0.1"
version = "0.0.1"
description = "This is a test module with a description"
Empty file.
1 change: 1 addition & 0 deletions pkg/package/test_data/test_mod_with_desc/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The_first_kcl_program = 'Hello World!'
5 changes: 5 additions & 0 deletions pkg/package/toml.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ func (mod *ModFile) UnmarshalTOML(data interface{}) error {
const NAME_FLAG = "name"
const EDITION_FLAG = "edition"
const VERSION_FLAG = "version"
const DESCRIPTION_FLAG = "description"

func (pkg *Package) UnmarshalTOML(data interface{}) error {
meta, ok := data.(map[string]interface{})
Expand All @@ -228,6 +229,10 @@ func (pkg *Package) UnmarshalTOML(data interface{}) error {
if v, ok := meta[VERSION_FLAG].(string); ok {
pkg.Version = v
}

if v, ok := meta[DESCRIPTION_FLAG].(string); ok {
pkg.Description = v
}
return nil
}

Expand Down
72 changes: 72 additions & 0 deletions test/e2e/kpm_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
package e2e

import (
"context"
"encoding/json"
"os"
"path/filepath"
"strings"

"github.com/onsi/ginkgo/v2"
"github.com/onsi/gomega"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
"kcl-lang.io/kpm/pkg/constants"
"oras.land/oras-go/v2"
"oras.land/oras-go/v2/registry/remote"
"oras.land/oras-go/v2/registry/remote/auth"
"oras.land/oras-go/v2/registry/remote/retry"
)

var _ = ginkgo.Describe("Kpm CLI Testing", func() {
Expand Down Expand Up @@ -138,4 +146,68 @@ var _ = ginkgo.Describe("Kpm CLI Testing", func() {
})
}
})

ginkgo.Context("testing 'test oci '", func() {
testSuitesRoot := filepath.Join(filepath.Join(filepath.Join(GetWorkDir(), TEST_SUITES_DIR), "kpm"), "test_oci")
testSuites := LoadAllTestSuites(testSuitesRoot)
testDataRoot := filepath.Join(filepath.Join(GetWorkDir(), TEST_SUITES_DIR), "test_data")
for _, ts := range testSuites {
ts := ts
ginkgo.It(ts.GetTestSuiteInfo(), func() {
// 1. Push a package with metadata in OCI manifest
workspace := GetWorkspace()

CopyDir(filepath.Join(testDataRoot, ts.Name), filepath.Join(workspace, ts.Name))

input := ReplaceAllKeyByValue(ts.Input, "<workspace>", filepath.Join(workspace, ts.Name))

stdout, stderr, err := ExecKpmWithWorkDir(input, filepath.Join(workspace, ts.Name))

expectedStdout := ReplaceAllKeyByValue(ts.ExpectStdout, "<workspace>", workspace)
expectedStderr := ReplaceAllKeyByValue(ts.ExpectStderr, "<workspace>", workspace)

gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
if !IsIgnore(expectedStdout) {
gomega.Expect(stdout).To(gomega.ContainSubstring(expectedStdout))
}
if !IsIgnore(expectedStderr) {
gomega.Expect(stderr).To(gomega.ContainSubstring(expectedStderr))
}

bytes, err := os.ReadFile(filepath.Join(testDataRoot, ts.Name, "expected_oci_manifest.json"))
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())

// 2. fetch the metadata in OCI manifest to check if the metadata is correct
repo, err := remote.NewRepository("localhost:5001/test/test_push_with_oci_manifest")
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
repo.PlainHTTP = true
repo.Client = &auth.Client{
Client: retry.DefaultClient,
Cache: auth.DefaultCache,
Credential: auth.StaticCredential("localhost:5001", auth.Credential{
Username: "test",
Password: "1234",
}),
}

gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
_, manifestContent, err := oras.FetchBytes(context.Background(), repo, "0.0.1", oras.DefaultFetchBytesOptions)
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
var manifest_got v1.Manifest
err = json.Unmarshal([]byte(manifestContent), &manifest_got)
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())

var manifest_expect v1.Manifest
err = json.Unmarshal(bytes, &manifest_expect)
gomega.Expect(err).ShouldNot(gomega.HaveOccurred())
gomega.Expect(len(manifest_expect.Annotations)).To(gomega.Equal(len(manifest_got.Annotations)))
gomega.Expect(manifest_expect.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_NAME]).
To(gomega.Equal(manifest_got.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_NAME]))
gomega.Expect(manifest_expect.Annotations[constants.DEFAULT_KCL_OCI_MANIFEST_VERSION]).
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]))
})
}
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
KPM_HOME=""
KCLVM_VENDOR_HOME=""
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
kpm push
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
kpm: package 'test_push_with_oci_manifest' will be pushed
kpm: pushed [registry] localhost:5001/test/test_push_with_oci_manifest
kpm: digest: sha256:
Original file line number Diff line number Diff line change
@@ -0,0 +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"}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[package]
name = "test_push_with_oci_manifest"
edition = "0.0.1"
version = "0.0.1"
description = "This is the description of the package"

Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The_first_kcl_program = 'Hello World!'

0 comments on commit 0de32be

Please sign in to comment.