Skip to content

Commit bc926ee

Browse files
feat(sdk): return final package ref after publish (#3911)
Signed-off-by: Austin Abro <[email protected]>
1 parent f7d6755 commit bc926ee

File tree

9 files changed

+72
-89
lines changed

9 files changed

+72
-89
lines changed

src/cmd/package.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1237,7 +1237,8 @@ func (o *packagePublishOptions) run(cmd *cobra.Command, args []string) error {
12371237
RemoteOptions: defaultRemoteOptions(),
12381238
CachePath: cachePath,
12391239
}
1240-
return packager.PublishSkeleton(ctx, packageSource, dstRef, skeletonOpts)
1240+
_, err = packager.PublishSkeleton(ctx, packageSource, dstRef, skeletonOpts)
1241+
return err
12411242
}
12421243

12431244
if helpers.IsOCIURL(packageSource) && pkgConfig.PublishOpts.SigningKeyPath == "" {
@@ -1313,7 +1314,8 @@ func (o *packagePublishOptions) run(cmd *cobra.Command, args []string) error {
13131314
RemoteOptions: defaultRemoteOptions(),
13141315
}
13151316

1316-
return packager.PublishPackage(ctx, pkgLayout, dstRef, publishPackageOpts)
1317+
_, err = packager.PublishPackage(ctx, pkgLayout, dstRef, publishPackageOpts)
1318+
return err
13171319
}
13181320

13191321
type packagePullOptions struct{}

src/pkg/packager/create.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func Create(ctx context.Context, packagePath string, output string, opts CreateO
7575
if err != nil {
7676
return "", err
7777
}
78-
remote, err := zoci.NewRemote(ctx, ref, oci.PlatformForArch(pkgLayout.Pkg.Build.Architecture),
78+
remote, err := zoci.NewRemote(ctx, ref.String(), oci.PlatformForArch(pkgLayout.Pkg.Build.Architecture),
7979
oci.WithPlainHTTP(opts.PlainHTTP), oci.WithInsecureSkipVerify(opts.InsecureSkipTLSVerify))
8080
if err != nil {
8181
return "", err
@@ -84,7 +84,7 @@ func Create(ctx context.Context, packagePath string, output string, opts CreateO
8484
if err != nil {
8585
return "", err
8686
}
87-
packageLocation = ref
87+
packageLocation = ref.String()
8888
} else {
8989
packageLocation, err = pkgLayout.Archive(ctx, output, opts.MaxPackageSizeMB)
9090
if err != nil {

src/pkg/packager/publish.go

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type PublishFromOCIOptions struct {
3333
}
3434

3535
// PublishFromOCI takes a source and destination registry reference and a PublishFromOCIOpts and copies the package from the source to the destination.
36+
// src and dst are references to the full package ref, e.g. my-registry.com/my-namespace/my-package:0.0.1
3637
func PublishFromOCI(ctx context.Context, src registry.Reference, dst registry.Reference, opts PublishFromOCIOptions) (err error) {
3738
l := logger.From(ctx)
3839
start := time.Now()
@@ -89,24 +90,35 @@ type PublishPackageOptions struct {
8990
RemoteOptions
9091
}
9192

92-
// PublishPackage takes a Path to the location of the built package, a ref to a registry, and a PublishOpts and uploads to the target OCI registry.
93-
func PublishPackage(ctx context.Context, pkgLayout *layout.PackageLayout, dst registry.Reference, opts PublishPackageOptions) error {
93+
// PublishPackage takes a package layout and pushes the package to the given registry.
94+
// dst is the path to the registry namespace, e.g. my-registry.com/my-namespace. The full package ref is created using the package name and returned
95+
func PublishPackage(ctx context.Context, pkgLayout *layout.PackageLayout, dst registry.Reference, opts PublishPackageOptions) (registry.Reference, error) {
9496
l := logger.From(ctx)
9597

9698
// Validate inputs
9799
l.Debug("validating PublishOpts")
98100
if err := dst.ValidateRegistry(); err != nil {
99-
return fmt.Errorf("invalid registry: %w", err)
101+
return registry.Reference{}, fmt.Errorf("invalid registry: %w", err)
100102
}
101103
if pkgLayout == nil {
102-
return fmt.Errorf("package layout must be specified")
104+
return registry.Reference{}, fmt.Errorf("package layout must be specified")
103105
}
104106

105107
if err := pkgLayout.SignPackage(opts.SigningKeyPath, opts.SigningKeyPassword); err != nil {
106-
return fmt.Errorf("unable to sign package: %w", err)
108+
return registry.Reference{}, fmt.Errorf("unable to sign package: %w", err)
107109
}
108110

109-
return pushToRemote(ctx, pkgLayout, dst, opts.OCIConcurrency, opts.RemoteOptions)
111+
// Build Reference for remote from registry location and pkg
112+
pkgRef, err := zoci.ReferenceFromMetadata(dst.String(), pkgLayout.Pkg)
113+
if err != nil {
114+
return registry.Reference{}, err
115+
}
116+
117+
if err := pushToRemote(ctx, pkgLayout, pkgRef, opts.OCIConcurrency, opts.RemoteOptions); err != nil {
118+
return registry.Reference{}, err
119+
}
120+
121+
return pkgRef, nil
110122
}
111123

112124
// PublishSkeletonOptions declares the parameters to publish a skeleton package.
@@ -122,17 +134,18 @@ type PublishSkeletonOptions struct {
122134
RemoteOptions
123135
}
124136

125-
// PublishSkeleton takes a Path to the location of the build package, a ref to a registry, and a PublishOpts and uploads the skeleton package to the target OCI registry.
126-
func PublishSkeleton(ctx context.Context, path string, ref registry.Reference, opts PublishSkeletonOptions) error {
137+
// PublishSkeleton takes a Path to the package definition and uploads a skeleton package to the given a registry.
138+
// dst is the path to the registry namespace, e.g. my-registry.com/my-namespace. The full package ref is created using the package name and returned
139+
func PublishSkeleton(ctx context.Context, path string, ref registry.Reference, opts PublishSkeletonOptions) (registry.Reference, error) {
127140
l := logger.From(ctx)
128141

129142
// Validate inputs
130143
l.Debug("validating PublishOpts")
131144
if err := ref.ValidateRegistry(); err != nil {
132-
return fmt.Errorf("invalid registry: %w", err)
145+
return registry.Reference{}, fmt.Errorf("invalid registry: %w", err)
133146
}
134147
if path == "" {
135-
return fmt.Errorf("path must be specified")
148+
return registry.Reference{}, fmt.Errorf("path must be specified")
136149
}
137150

138151
// Load package layout
@@ -141,7 +154,7 @@ func PublishSkeleton(ctx context.Context, path string, ref registry.Reference, o
141154
CachePath: opts.CachePath,
142155
})
143156
if err != nil {
144-
return err
157+
return registry.Reference{}, err
145158
}
146159
// Create skeleton buildpath
147160
createOpts := layout.AssembleSkeletonOptions{
@@ -150,16 +163,16 @@ func PublishSkeleton(ctx context.Context, path string, ref registry.Reference, o
150163
}
151164
pkgLayout, err := layout.AssembleSkeleton(ctx, pkg, path, createOpts)
152165
if err != nil {
153-
return fmt.Errorf("unable to create skeleton: %w", err)
166+
return registry.Reference{}, fmt.Errorf("unable to create skeleton: %w", err)
154167
}
155-
156-
err = pushToRemote(ctx, pkgLayout, ref, opts.OCIConcurrency, opts.RemoteOptions)
168+
// Build Reference for remote from registry location and pkg
169+
pkgRef, err := zoci.ReferenceFromMetadata(ref.String(), pkgLayout.Pkg)
157170
if err != nil {
158-
return err
171+
return registry.Reference{}, err
159172
}
160-
packageRef, err := zoci.ReferenceFromMetadata(ref.String(), pkgLayout.Pkg)
173+
err = pushToRemote(ctx, pkgLayout, pkgRef, opts.OCIConcurrency, opts.RemoteOptions)
161174
if err != nil {
162-
return err
175+
return registry.Reference{}, err
163176
}
164177
l.Info("skeleton packages contain metadata and local resources to allow for remote component imports")
165178
ex := []v1alpha1.ZarfComponent{}
@@ -168,31 +181,25 @@ func PublishSkeleton(ctx context.Context, path string, ref registry.Reference, o
168181
Name: fmt.Sprintf("import-%s", c.Name),
169182
Import: v1alpha1.ZarfComponentImport{
170183
Name: c.Name,
171-
URL: helpers.OCIURLPrefix + packageRef,
184+
URL: helpers.OCIURLPrefix + pkgRef.String(),
172185
},
173186
})
174187
}
175-
err = utils.ColorPrintYAML(ex, nil, true)
188+
err = utils.ColorPrintYAML(ex, nil, false)
176189
if err != nil {
177-
return err
190+
return registry.Reference{}, err
178191
}
179192
l.Info("find more info on skeleton packages at https://docs.zarf.dev/faq/#what-is-a-skeleton-zarf-package")
180-
return nil
193+
return pkgRef, nil
181194
}
182195

183-
// pushToRemote pushes a package to a remote at ref.
196+
// pushToRemote pushes a package to the given reference
184197
func pushToRemote(ctx context.Context, layout *layout.PackageLayout, ref registry.Reference, concurrency int, remoteOpts RemoteOptions) error {
185-
// Build Reference for remote from registry location and pkg
186-
r, err := zoci.ReferenceFromMetadata(ref.String(), layout.Pkg)
187-
if err != nil {
188-
return err
189-
}
190-
191198
arch := layout.Pkg.Metadata.Architecture
192199
// Set platform
193-
p := oci.PlatformForArch(arch)
200+
platform := oci.PlatformForArch(arch)
194201

195-
remote, err := zoci.NewRemote(ctx, r, p, oci.WithPlainHTTP(remoteOpts.PlainHTTP), oci.WithInsecureSkipVerify(remoteOpts.InsecureSkipTLSVerify))
202+
remote, err := zoci.NewRemote(ctx, ref.String(), platform, oci.WithPlainHTTP(remoteOpts.PlainHTTP), oci.WithInsecureSkipVerify(remoteOpts.InsecureSkipTLSVerify))
196203
if err != nil {
197204
return fmt.Errorf("could not instantiate remote: %w", err)
198205
}

src/pkg/packager/publish_test.go

Lines changed: 19 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ func TestPublishError(t *testing.T) {
104104

105105
for _, tc := range tt {
106106
t.Run(tc.name, func(t *testing.T) {
107-
err := PublishPackage(context.Background(), tc.packageLayout, tc.ref, tc.opts)
107+
_, err := PublishPackage(context.Background(), tc.packageLayout, tc.ref, tc.opts)
108108
require.ErrorContains(t, err, tc.expectErr.Error())
109109
})
110110
}
@@ -191,7 +191,7 @@ func TestPublishSkeleton(t *testing.T) {
191191
registryRef := createRegistry(ctx, t)
192192

193193
// Publish test package
194-
err := PublishSkeleton(ctx, tc.path, registryRef, tc.opts)
194+
ref, err := PublishSkeleton(ctx, tc.path, registryRef, tc.opts)
195195
require.NoError(t, err)
196196

197197
// Read and unmarshall expected
@@ -203,10 +203,7 @@ func TestPublishSkeleton(t *testing.T) {
203203
// This verifies that publish deletes the manifest that is auto created by oras
204204
require.NoFileExists(t, expectedPkg.Metadata.Name)
205205

206-
// Format url and instantiate remote
207-
ref, err := zoci.ReferenceFromMetadata(registryRef.String(), expectedPkg)
208-
require.NoError(t, err)
209-
rmt, err := zoci.NewRemote(ctx, ref, zoci.PlatformForSkeleton(), oci.WithPlainHTTP(true))
206+
rmt, err := zoci.NewRemote(ctx, ref.String(), zoci.PlatformForSkeleton(), oci.WithPlainHTTP(true))
210207
require.NoError(t, err)
211208

212209
// Fetch from remote and compare
@@ -261,14 +258,10 @@ func TestPublishPackage(t *testing.T) {
261258
require.NoError(t, err)
262259

263260
// Publish test package
264-
err = PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
265-
require.NoError(t, err)
266-
267-
// Format url and instantiate remote
268-
packageRef, err := zoci.ReferenceFromMetadata(registryRef.String(), layoutExpected.Pkg)
261+
packageRef, err := PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
269262
require.NoError(t, err)
270263

271-
layoutActual := pullFromRemote(ctx, t, packageRef, "amd64", tc.publicKeyPath, t.TempDir())
264+
layoutActual := pullFromRemote(ctx, t, packageRef.String(), "amd64", tc.publicKeyPath, t.TempDir())
272265
require.Equal(t, layoutExpected.Pkg, layoutActual.Pkg, "Uploaded package is not identical to downloaded package")
273266
if tc.opts.SigningKeyPath != "" {
274267
require.FileExists(t, filepath.Join(layoutActual.DirPath(), layout.Signature))
@@ -302,23 +295,19 @@ func TestPublishPackageDeterministic(t *testing.T) {
302295
require.NoError(t, err)
303296

304297
// Publish test package
305-
err = PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
306-
require.NoError(t, err)
307-
308-
// Format url and instantiate remote
309-
packageRef, err := zoci.ReferenceFromMetadata(registryRef.String(), layoutExpected.Pkg)
298+
packageRef, err := PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
310299
require.NoError(t, err)
311300

312301
// Attempt to get the digest
313302
platform := oci.PlatformForArch(layoutExpected.Pkg.Build.Architecture)
314-
remote, err := zoci.NewRemote(ctx, packageRef, platform, oci.WithPlainHTTP(tc.opts.PlainHTTP))
303+
remote, err := zoci.NewRemote(ctx, packageRef.String(), platform, oci.WithPlainHTTP(tc.opts.PlainHTTP))
315304
require.NoError(t, err)
316305
desc, err := remote.ResolveRoot(ctx)
317306
require.NoError(t, err)
318307
expectedDigest := desc.Digest.String()
319308

320309
// Re-publish the package to ensure the digest does not change
321-
err = PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
310+
_, err = PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
322311
require.NoError(t, err)
323312
// Publish creates a local oci manifest file using the package name, which gets deleted
324313
require.NoFileExists(t, layoutExpected.Pkg.Metadata.Name)
@@ -357,21 +346,19 @@ func TestPublishCopySHA(t *testing.T) {
357346
require.NoError(t, err)
358347

359348
// Publish test package
360-
err = PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
349+
srcRef, err := PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
361350
require.NoError(t, err)
362351

363352
// Setup destination registry
364353
dstRegistryRef := createRegistry(ctx, t)
365354

366355
// This gets the test package digest from the first package publish
367356
localRepo := &remote.Repository{PlainHTTP: true}
368-
ociSrc := fmt.Sprintf("%s/%s", registryRef.String(), "test:0.0.1")
369-
localRepo.Reference, err = registry.ParseReference(ociSrc)
357+
localRepo.Reference = srcRef
358+
indexDesc, err := oras.Resolve(ctx, localRepo, srcRef.String(), oras.ResolveOptions{})
370359
require.NoError(t, err)
371-
indexDesc, err := oras.Resolve(ctx, localRepo, ociSrc, oras.ResolveOptions{})
372-
require.NoError(t, err)
373-
src := fmt.Sprintf("%s/%s@%s", registryRef.String(), "test:0.0.1", indexDesc.Digest)
374-
srcRef, err := registry.ParseReference(src)
360+
src := fmt.Sprintf("%s@%s", srcRef, indexDesc.Digest)
361+
srcRefWithDigest, err := registry.ParseReference(src)
375362
require.NoError(t, err)
376363

377364
dst := fmt.Sprintf("%s/%s", dstRegistryRef.String(), "test:0.0.1")
@@ -385,18 +372,15 @@ func TestPublishCopySHA(t *testing.T) {
385372
}
386373

387374
// Publish test package to the destination registry
388-
err = PublishFromOCI(ctx, srcRef, dstRef, opts)
375+
err = PublishFromOCI(ctx, srcRefWithDigest, dstRef, opts)
389376
require.NoError(t, err)
390377

391378
// This verifies that publish deletes the manifest that is auto created by oras
392379
require.NoFileExists(t, layoutExpected.Pkg.Metadata.Name)
393-
// Format url and instantiate remote
394-
packageRef, err := zoci.ReferenceFromMetadata(dstRegistryRef.String(), layoutExpected.Pkg)
395-
require.NoError(t, err)
396380

397-
pkgRefsha := fmt.Sprintf("%s@%s", packageRef, indexDesc.Digest)
381+
pkgRefSha := fmt.Sprintf("%s@%s", dstRef.String(), indexDesc.Digest)
398382

399-
layoutActual := pullFromRemote(ctx, t, pkgRefsha, layoutExpected.Pkg.Build.Architecture, "", t.TempDir())
383+
layoutActual := pullFromRemote(ctx, t, pkgRefSha, layoutExpected.Pkg.Build.Architecture, "", t.TempDir())
400384
require.Equal(t, layoutExpected.Pkg, layoutActual.Pkg, "Uploaded package is not identical to downloaded package")
401385
})
402386
}
@@ -428,14 +412,11 @@ func TestPublishCopyTag(t *testing.T) {
428412
require.NoError(t, err)
429413

430414
// Publish test package
431-
err = PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
415+
srcRef, err := PublishPackage(ctx, layoutExpected, registryRef, tc.opts)
432416
require.NoError(t, err)
433417

434418
dstRegistryRef := createRegistry(ctx, t)
435419

436-
src := fmt.Sprintf("%s/%s", registryRef.String(), "test:0.0.1")
437-
srcRegistry, err := registry.ParseReference(src)
438-
require.NoError(t, err)
439420
dst := fmt.Sprintf("%s/%s", dstRegistryRef.String(), "test:0.0.1")
440421
dstRegistry, err := registry.ParseReference(dst)
441422
require.NoError(t, err)
@@ -447,16 +428,13 @@ func TestPublishCopyTag(t *testing.T) {
447428
}
448429

449430
// Publish test package
450-
err = PublishFromOCI(ctx, srcRegistry, dstRegistry, opts)
431+
err = PublishFromOCI(ctx, srcRef, dstRegistry, opts)
451432
require.NoError(t, err)
452433

453434
// This verifies that publish deletes the manifest that is auto created by oras
454435
require.NoFileExists(t, layoutExpected.Pkg.Metadata.Name)
455-
// Format url and instantiate remote
456-
packageRef, err := zoci.ReferenceFromMetadata(dstRegistryRef.String(), layoutExpected.Pkg)
457-
require.NoError(t, err)
458436

459-
layoutActual := pullFromRemote(ctx, t, packageRef, layoutExpected.Pkg.Build.Architecture, "", t.TempDir())
437+
layoutActual := pullFromRemote(ctx, t, dstRegistry.String(), layoutExpected.Pkg.Build.Architecture, "", t.TempDir())
460438

461439
require.Equal(t, layoutExpected.Pkg, layoutActual.Pkg, "Uploaded package is not identical to downloaded package")
462440
})

src/pkg/utils/io_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ func TestGetFinalExecutableCommand(t *testing.T) {
4141
}
4242

4343
for _, tt := range tests {
44+
// Tests can't run in parallel since global state is being changed
4445
t.Run(tt.name, func(t *testing.T) {
45-
t.Parallel()
4646
config.ActionsCommandZarfPrefix = tt.actionCommandZarfPrefix
4747
config.ActionsUseSystemZarf = tt.actionUsesSystemZarf
4848
cmd, err := GetFinalExecutableCommand()

src/pkg/zoci/copier.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package zoci
77
import (
88
"bytes"
99
"context"
10-
"fmt"
1110

1211
"github.com/defenseunicorns/pkg/oci"
1312
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -53,6 +52,6 @@ func CopyPackage(ctx context.Context, src *Remote, dst *Remote, concurrency int)
5352
return err
5453
}
5554

56-
src.Log().Info(fmt.Sprintf("Published %s to %s", src.Repo().Reference, dst.Repo().Reference))
55+
l.Info("package copied successfully", "source", src.Repo().Reference, "destination", dst.Repo().Reference)
5756
return nil
5857
}

src/pkg/zoci/pull.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/defenseunicorns/pkg/oci"
1515
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
1616
"github.com/zarf-dev/zarf/src/api/v1alpha1"
17+
"github.com/zarf-dev/zarf/src/pkg/logger"
1718
"github.com/zarf-dev/zarf/src/pkg/packager/layout"
1819
"github.com/zarf-dev/zarf/src/pkg/transform"
1920
"github.com/zarf-dev/zarf/src/pkg/utils"
@@ -37,8 +38,7 @@ func (r *Remote) PullPackage(ctx context.Context, destinationDir string, concurr
3738
}
3839

3940
layerSize := oci.SumDescsSize(layersToPull)
40-
// TODO (@austinabro321) change this and other r.Log() calls to the proper slog format
41-
r.Log().Info(fmt.Sprintf("Pulling %s, size: %s", r.Repo().Reference, utils.ByteFormat(float64(layerSize), 2)))
41+
logger.From(ctx).Info("pulling package", "name", r.Repo().Reference, "size", utils.ByteFormat(float64(layerSize), 2))
4242

4343
dst, err := file.New(destinationDir)
4444
if err != nil {

0 commit comments

Comments
 (0)