Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package apko for openSUSE:Factory checked in at 2025-04-29 16:41:33 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/apko (Old) and /work/SRC/openSUSE:Factory/.apko.new.30101 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "apko" Tue Apr 29 16:41:33 2025 rev:47 rq:1273304 version:0.27.1 Changes: -------- --- /work/SRC/openSUSE:Factory/apko/apko.changes 2025-04-25 22:20:16.901988359 +0200 +++ /work/SRC/openSUSE:Factory/.apko.new.30101/apko.changes 2025-04-29 16:41:51.881930689 +0200 @@ -1,0 +2,7 @@ +Tue Apr 29 05:55:15 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 0.27.1: + * Allow an empty layering object for legacy behavior (#1643) + * apk: expose ParsedConstraint version (#1640) + +------------------------------------------------------------------- Old: ---- apko-0.27.0.obscpio New: ---- apko-0.27.1.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ apko.spec ++++++ --- /var/tmp/diff_new_pack.LvOVfn/_old 2025-04-29 16:41:53.269988991 +0200 +++ /var/tmp/diff_new_pack.LvOVfn/_new 2025-04-29 16:41:53.277989326 +0200 @@ -17,7 +17,7 @@ Name: apko -Version: 0.27.0 +Version: 0.27.1 Release: 0 Summary: Build OCI images from APK packages directly without Dockerfile License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.LvOVfn/_old 2025-04-29 16:41:53.441996215 +0200 +++ /var/tmp/diff_new_pack.LvOVfn/_new 2025-04-29 16:41:53.453996719 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/chainguard-dev/apko</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.27.0</param> + <param name="revision">v0.27.1</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.LvOVfn/_old 2025-04-29 16:41:53.517999408 +0200 +++ /var/tmp/diff_new_pack.LvOVfn/_new 2025-04-29 16:41:53.521999575 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/chainguard-dev/apko</param> - <param name="changesrevision">61a72971841931d7724fa6b6967e25e32446d371</param></service></servicedata> + <param name="changesrevision">b8c0ef48c73abc28e61d88481785136b92325359</param></service></servicedata> (No newline at EOF) ++++++ apko-0.27.0.obscpio -> apko-0.27.1.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.27.0/internal/cli/testdata/empty-layering.yaml new/apko-0.27.1/internal/cli/testdata/empty-layering.yaml --- old/apko-0.27.0/internal/cli/testdata/empty-layering.yaml 1970-01-01 01:00:00.000000000 +0100 +++ new/apko-0.27.1/internal/cli/testdata/empty-layering.yaml 2025-04-28 21:42:42.000000000 +0200 @@ -0,0 +1,17 @@ +contents: + keyring: + - ./testdata/melange.rsa.pub + repositories: + - ./testdata/packages + packages: + - replayout + +entrypoint: + command: /bin/sh -l + +archs: +- x86_64 +- aarch64 + +# Empty layering configuration +layering: {} \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.27.0/pkg/apk/apk/repo.go new/apko-0.27.1/pkg/apk/apk/repo.go --- old/apko-0.27.0/pkg/apk/apk/repo.go 2025-04-23 18:19:02.000000000 +0200 +++ new/apko-0.27.1/pkg/apk/apk/repo.go 2025-04-28 21:42:42.000000000 +0200 @@ -316,7 +316,7 @@ return } - conflicting := filterPackages(providers, dq, withVersion(parsed.version, parsed.dep), withPreferPin(parsed.pin)) + conflicting := filterPackages(providers, dq, withVersion(parsed.Version, parsed.dep), withPreferPin(parsed.pin)) for _, conflict := range conflicting { if _, dqed := dq[conflict.RepositoryPackage]; dqed { @@ -331,14 +331,14 @@ func (p *PkgResolver) conflictingVersion(constraint ParsedConstraint, conflict *repositoryPackage) bool { // If the constraint is not a virtual, everything will conflict with it. // TODO: Figure out if this logic is actually equivalent to how apk disqualifies virtual. - if constraint.version != "" { + if constraint.Version != "" { return true } // From here on, "the same version" really means it's a virtual, but let's keep the diff small until we revisit. if conflict.Name == constraint.Name { - return conflict.Version != constraint.version + return conflict.Version != constraint.Version } for _, confProv := range conflict.Provides { @@ -348,7 +348,7 @@ continue } - if confConstraint.version == constraint.version { + if confConstraint.Version == constraint.Version { // If the versions are the same, they shouldn't conflict. return false } @@ -407,7 +407,7 @@ } // We don't care about virtuals, actually. - if constraint.version == "" { + if constraint.Version == "" { continue } @@ -442,7 +442,7 @@ continue } - requiredVersion, err := cachedParseVersion(parsed.version) + requiredVersion, err := cachedParseVersion(parsed.Version) if err != nil { // This shouldn't happen but return an error to be safe. return fmt.Errorf("parsing constraint %q: %w", constraint, err) @@ -466,10 +466,10 @@ if pp.Name != parsed.Name { continue } - actualVersion, err := cachedParseVersion(pp.version) + actualVersion, err := cachedParseVersion(pp.Version) // skip invalid ones if err != nil { - dq[provider.RepositoryPackage] = fmt.Sprintf("parsing %q: %v", pp.version, err) + dq[provider.RepositoryPackage] = fmt.Sprintf("parsing %q: %v", pp.Version, err) continue } if !parsed.dep.satisfies(actualVersion, requiredVersion) { @@ -608,7 +608,7 @@ for _, subDep := range installIfPkg.InstallIf { // two possibilities: package name, or name=version constraint := cachedResolvePackageNameVersionPin(subDep) - name, version := constraint.Name, constraint.version + name, version := constraint.Name, constraint.Version // precise match of whatever it is, take it and continue if _, ok := added[subDep]; ok { matchCount++ @@ -638,7 +638,7 @@ // returns multiple in case you need to see all potential matches. func (p *PkgResolver) ResolvePackage(pkgName string, dq map[*RepositoryPackage]string) ([]*RepositoryPackage, error) { constraint := cachedResolvePackageNameVersionPin(pkgName) - name, version, compare, pin := constraint.Name, constraint.version, constraint.dep, constraint.pin + name, version, compare, pin := constraint.Name, constraint.Version, constraint.dep, constraint.pin pkgsWithVersions, ok := p.nameMap[name] if !ok { return nil, fmt.Errorf("nothing provides %q", name) @@ -664,7 +664,7 @@ // This is like ResolvePackage but we only care about the best match and not all matches. func (p *PkgResolver) resolvePackage(pkgName string, dq map[*RepositoryPackage]string) (*RepositoryPackage, error) { constraint := cachedResolvePackageNameVersionPin(pkgName) - name, version, compare, pin := constraint.Name, constraint.version, constraint.dep, constraint.pin + name, version, compare, pin := constraint.Name, constraint.Version, constraint.dep, constraint.pin pkgsWithVersions, ok := p.nameMap[name] if !ok { @@ -747,7 +747,7 @@ // this package might be pinned to a version constraint := cachedResolvePackageNameVersionPin(dep) - name, version, compare := constraint.Name, constraint.version, constraint.dep + name, version, compare := constraint.Name, constraint.Version, constraint.dep // see if we provide this if myProvides[name] || myProvides[dep] { // we provide this, so skip it @@ -792,7 +792,7 @@ satisfiedByProvide := false for _, provide := range picked.Provides { prostraint := cachedResolvePackageNameVersionPin(provide) - pname, pversion, pcompare := prostraint.Name, prostraint.version, prostraint.dep + pname, pversion, pcompare := prostraint.Name, prostraint.Version, prostraint.dep if pname != name { continue } @@ -1070,7 +1070,7 @@ } for _, prov := range pkg.Provides { constraint := cachedResolvePackageNameVersionPin(prov) - pName, pVersion := constraint.Name, constraint.version + pName, pVersion := constraint.Name, constraint.Version if pVersion == "" { pVersion = pkg.Version } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.27.0/pkg/apk/apk/repo_test.go new/apko-0.27.1/pkg/apk/apk/repo_test.go --- old/apko-0.27.0/pkg/apk/apk/repo_test.go 2025-04-23 18:19:02.000000000 +0200 +++ new/apko-0.27.1/pkg/apk/apk/repo_test.go 2025-04-28 21:42:42.000000000 +0200 @@ -988,11 +988,11 @@ for pkgver := range provs { parsed := ResolvePackageNameVersionPin(pkgver) - packages[pkgver] = &Package{Name: parsed.Name, Version: parsed.version} + packages[pkgver] = &Package{Name: parsed.Name, Version: parsed.Version} } for pkgver := range deps { parsed := ResolvePackageNameVersionPin(pkgver) - packages[pkgver] = &Package{Name: parsed.Name, Version: parsed.version} + packages[pkgver] = &Package{Name: parsed.Name, Version: parsed.Version} } for pkgver, pkgProvs := range provs { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.27.0/pkg/apk/apk/version.go new/apko-0.27.1/pkg/apk/apk/version.go --- old/apko-0.27.0/pkg/apk/apk/version.go 2025-04-23 18:19:02.000000000 +0200 +++ new/apko-0.27.1/pkg/apk/apk/version.go 2025-04-28 21:42:42.000000000 +0200 @@ -351,16 +351,16 @@ type ParsedConstraint struct { Name string - version string + Version string dep versionDependency pin string } func (p ParsedConstraint) SatisfiedBy(v Version) (bool, error) { - if p.version == "" { + if p.Version == "" { return true, nil } - pv, err := cachedParseVersion(p.version) + pv, err := cachedParseVersion(p.Version) if err != nil { return false, err } @@ -399,7 +399,7 @@ // layout: [full match, name, =version, =|>|<, version, @pin, pin] p := ParsedConstraint{ Name: parts[0][1], - version: parts[0][4], + Version: parts[0][4], pin: parts[0][6], dep: versionAny, } @@ -511,7 +511,7 @@ } for _, prov := range pkg.Provides { - version := cachedResolvePackageNameVersionPin(prov).version + version := cachedResolvePackageNameVersionPin(prov).Version if version == "" { continue } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.27.0/pkg/apk/apk/version_test.go new/apko-0.27.1/pkg/apk/apk/version_test.go --- old/apko-0.27.0/pkg/apk/apk/version_test.go 2025-04-23 18:19:02.000000000 +0200 +++ new/apko-0.27.1/pkg/apk/apk/version_test.go 2025-04-28 21:42:42.000000000 +0200 @@ -943,7 +943,7 @@ t.Run(tt.input, func(t *testing.T) { constraint := ResolvePackageNameVersionPin(tt.input) require.Equal(t, tt.name, constraint.Name) - require.Equal(t, tt.version, constraint.version) + require.Equal(t, tt.version, constraint.Version) require.Equal(t, tt.dep, constraint.dep) require.Equal(t, tt.pin, constraint.pin) }) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.27.0/pkg/build/build.go new/apko-0.27.1/pkg/build/build.go --- old/apko-0.27.0/pkg/build/build.go 2025-04-23 18:19:02.000000000 +0200 +++ new/apko-0.27.1/pkg/build/build.go 2025-04-28 21:42:42.000000000 +0200 @@ -118,6 +118,11 @@ ctx, span := otel.Tracer("apko").Start(ctx, "BuildLayer") defer span.End() + // Check if a non-empty layering strategy is supplied + if bc.ic.Layering != nil && !(bc.ic.Layering.Strategy == "" && bc.ic.Layering.Budget == 0) { + return "", nil, fmt.Errorf("cannot use BuildLayer with a layering strategy, use BuildLayers instead") + } + // build image filesystem if err := bc.BuildImage(ctx); err != nil { return "", nil, err @@ -134,7 +139,10 @@ ctx, span := otel.Tracer("apko").Start(ctx, "BuildLayers") defer span.End() - if bc.ic.Layering == nil { + // Use the legacy (single-layer) strategy when: + // 1. Layering is nil (original behavior) + // 2. Layering is empty (i.e., layering: {}) + if bc.ic.Layering == nil || (bc.ic.Layering.Strategy == "" && bc.ic.Layering.Budget == 0) { _, layer, err := bc.BuildLayer(ctx) if err != nil { return nil, err diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.27.0/pkg/build/build_test.go new/apko-0.27.1/pkg/build/build_test.go --- old/apko-0.27.0/pkg/build/build_test.go 2025-04-23 18:19:02.000000000 +0200 +++ new/apko-0.27.1/pkg/build/build_test.go 2025-04-28 21:42:42.000000000 +0200 @@ -50,6 +50,52 @@ require.Len(t, layers, 2) } +func TestBuildLayersWithEmptyLayering(t *testing.T) { + ctx := context.Background() + + // Use the empty-layering.yaml file we created in testdata + opts := []build.Option{ + build.WithConfig("empty-layering.yaml", []string{"testdata"}), + } + + bc, err := build.New(ctx, fs.NewMemFS(), opts...) + if err != nil { + t.Fatal(err) + } + + // Should build successfully and return a single layer + layers, err := bc.BuildLayers(ctx) + if err != nil { + t.Fatal(err) + } + + // Should fall back to the legacy single-layer approach with empty layering + require.Len(t, layers, 1) + + // BuildLayer should also work with empty layering + _, _, err = bc.BuildLayer(ctx) + require.NoError(t, err, "BuildLayer should not fail with empty layering") +} + +func TestBuildLayerWithLayeringStrategy(t *testing.T) { + ctx := context.Background() + + // Use a config with a non-empty layering strategy + opts := []build.Option{ + build.WithConfig("layering.yaml", []string{"testdata"}), + } + + bc, err := build.New(ctx, fs.NewMemFS(), opts...) + if err != nil { + t.Fatal(err) + } + + // Should return an error when trying to use BuildLayer with a layering strategy + _, _, err = bc.BuildLayer(ctx) + require.Error(t, err) + require.Contains(t, err.Error(), "cannot use BuildLayer with a layering strategy") +} + func TestBuildImage(t *testing.T) { ctx := context.Background() ++++++ apko.obsinfo ++++++ --- /var/tmp/diff_new_pack.LvOVfn/_old 2025-04-29 16:41:53.890015033 +0200 +++ /var/tmp/diff_new_pack.LvOVfn/_new 2025-04-29 16:41:53.898015369 +0200 @@ -1,5 +1,5 @@ name: apko -version: 0.27.0 -mtime: 1745425142 -commit: 61a72971841931d7724fa6b6967e25e32446d371 +version: 0.27.1 +mtime: 1745869362 +commit: b8c0ef48c73abc28e61d88481785136b92325359 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/apko/vendor.tar.gz /work/SRC/openSUSE:Factory/.apko.new.30101/vendor.tar.gz differ: char 13, line 1