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-08-02 00:42:54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/apko (Old) and /work/SRC/openSUSE:Factory/.apko.new.1085 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "apko" Sat Aug 2 00:42:54 2025 rev:62 rq:1297058 version:0.30.2 Changes: -------- --- /work/SRC/openSUSE:Factory/apko/apko.changes 2025-07-28 14:58:40.095573197 +0200 +++ /work/SRC/openSUSE:Factory/.apko.new.1085/apko.changes 2025-08-02 00:44:08.948521017 +0200 @@ -1,0 +2,28 @@ +Fri Aug 01 12:01:36 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 0.30.2: + * Add support for runtime-only repositories (#1790) + * build(deps): bump github/codeql-action from 3.29.4 to 3.29.5 + (#1789) + * build(deps): bump google.golang.org/api from 0.242.0 to 0.243.0 + (#1778) + * build(deps): bump github.com/docker/docker from + 28.2.2+incompatible to 28.3.3+incompatible in the go_modules + group (#1787) + +------------------------------------------------------------------- +Fri Aug 01 11:57:59 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 0.30.1: + * Revert "Add support for runtime-only repositories" (#1788) + +------------------------------------------------------------------- +Fri Aug 01 11:49:55 UTC 2025 - Johannes Kastl <opensuse_buildserv...@ojkastl.de> + +- Update to version 0.30.0: + * Add support for runtime-only repositories (#1786) + * add clean command to clear apk cache (#1746) + * build(deps): bump chainguard-dev/actions from 1.4.6 to 1.4.7 + (#1785) + +------------------------------------------------------------------- Old: ---- apko-0.29.10.obscpio New: ---- apko-0.30.2.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ apko.spec ++++++ --- /var/tmp/diff_new_pack.AV6b84/_old 2025-08-02 00:44:10.144570724 +0200 +++ /var/tmp/diff_new_pack.AV6b84/_new 2025-08-02 00:44:10.148570891 +0200 @@ -17,7 +17,7 @@ Name: apko -Version: 0.29.10 +Version: 0.30.2 Release: 0 Summary: Build OCI images from APK packages directly without Dockerfile License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.AV6b84/_old 2025-08-02 00:44:10.188572553 +0200 +++ /var/tmp/diff_new_pack.AV6b84/_new 2025-08-02 00:44:10.196572886 +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.29.10</param> + <param name="revision">v0.30.2</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.AV6b84/_old 2025-08-02 00:44:10.220573884 +0200 +++ /var/tmp/diff_new_pack.AV6b84/_new 2025-08-02 00:44:10.224574049 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/chainguard-dev/apko</param> - <param name="changesrevision">d8e6e78f84404d552e4d9ca1e5654d68a8140186</param></service></servicedata> + <param name="changesrevision">d6f3361063f4b2fc8b25994bd255440eb05b09cb</param></service></servicedata> (No newline at EOF) ++++++ apko-0.29.10.obscpio -> apko-0.30.2.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/go.mod new/apko-0.30.2/go.mod --- old/apko-0.29.10/go.mod 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/go.mod 2025-07-30 18:59:31.000000000 +0200 @@ -29,7 +29,7 @@ golang.org/x/sync v0.16.0 golang.org/x/sys v0.34.0 golang.org/x/time v0.12.0 - google.golang.org/api v0.242.0 + google.golang.org/api v0.243.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/apimachinery v0.33.3 @@ -38,7 +38,7 @@ require ( chainguard.dev/go-grpc-kit v0.17.11 // indirect - cloud.google.com/go/auth v0.16.2 // indirect + cloud.google.com/go/auth v0.16.3 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.8 // indirect cloud.google.com/go/compute/metadata v0.7.0 // indirect dario.cat/mergo v1.0.1 // indirect @@ -65,7 +65,7 @@ github.com/distribution/reference v0.6.0 // indirect github.com/docker/cli v28.3.2+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v28.2.2+incompatible // indirect + github.com/docker/docker v28.3.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.9.3 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect @@ -128,7 +128,7 @@ golang.org/x/net v0.42.0 // indirect golang.org/x/text v0.27.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 // indirect google.golang.org/grpc v1.73.0 // indirect google.golang.org/protobuf v1.36.6 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/go.sum new/apko-0.30.2/go.sum --- old/apko-0.29.10/go.sum 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/go.sum 2025-07-30 18:59:31.000000000 +0200 @@ -3,8 +3,8 @@ chainguard.dev/sdk v0.1.37 h1:4hZ2enarpA/FZ1JMXE3EOlpzd18LmdWZ7UScwdSlrSs= chainguard.dev/sdk v0.1.37/go.mod h1:4HOnG9fVNC9ruzkJLMWWUNM1iVxxBL+bKqj0STERbcs= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/auth v0.16.2 h1:QvBAGFPLrDeoiNjyfVunhQ10HKNYuOwZ5noee0M5df4= -cloud.google.com/go/auth v0.16.2/go.mod h1:sRBas2Y1fB1vZTdurouM0AzuYQBMZinrUYL8EufhtEA= +cloud.google.com/go/auth v0.16.3 h1:kabzoQ9/bobUmnseYnBO6qQG7q4a/CffFRlJSxv2wCc= +cloud.google.com/go/auth v0.16.3/go.mod h1:NucRGjaXfzP1ltpcQ7On/VTZ0H4kWB5Jy+Y9Dnm76fA= cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIiLpZnkHRbnc= cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c= cloud.google.com/go/compute/metadata v0.7.0 h1:PBWF+iiAerVNe8UCHxdOt6eHLVc3ydFeOCw78U8ytSU= @@ -81,8 +81,8 @@ github.com/docker/cli v28.3.2+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBirtxJnzDrHLEKxTAYk= github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= -github.com/docker/docker v28.2.2+incompatible h1:CjwRSksz8Yo4+RmQ339Dp/D2tGO5JxwYeqtMOEe0LDw= -github.com/docker/docker v28.2.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= +github.com/docker/docker v28.3.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/docker-credential-helpers v0.9.3 h1:gAm/VtF9wgqJMoxzT3Gj5p4AqIjCBS4wrsOh9yRqcz8= github.com/docker/docker-credential-helpers v0.9.3/go.mod h1:x+4Gbw9aGmChi3qTLZj8Dfn0TD20M/fuWy0E5+WDeCo= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= @@ -435,8 +435,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.242.0 h1:7Lnb1nfnpvbkCiZek6IXKdJ0MFuAZNAJKQfA1ws62xg= -google.golang.org/api v0.242.0/go.mod h1:cOVEm2TpdAGHL2z+UwyS+kmlGr3bVWQQ6sYEqkKje50= +google.golang.org/api v0.243.0 h1:sw+ESIJ4BVnlJcWu9S+p2Z6Qq1PjG77T8IJ1xtp4jZQ= +google.golang.org/api v0.243.0/go.mod h1:GE4QtYfaybx1KmeHMdBnNnyLzBZCVihGBXAmJu/uUr8= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -444,8 +444,8 @@ google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822 h1:oWVWY3NzT7KJppx2UKhKmzPq4SRe0LdCijVRwvGeikY= google.golang.org/genproto/googleapis/api v0.0.0-20250603155806-513f23925822/go.mod h1:h3c4v36UTKzUiuaOKQ6gr3S+0hovBtUrXzTG/i3+XEc= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822 h1:fc6jSaCT0vBduLYZHYrBBNY4dsWuvgyff9noRNDdBeE= -google.golang.org/genproto/googleapis/rpc v0.0.0-20250603155806-513f23925822/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79 h1:1ZwqphdOdWYXsUHgMpU/101nCtf/kSp9hOrcvFsnl10= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250715232539-7130f93afb79/go.mod h1:qQ0YXyHHx3XkvlzUtpXDkS29lDSafHMZBAZDc03LQ3A= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/build-cpio.go new/apko-0.30.2/internal/cli/build-cpio.go --- old/apko-0.29.10/internal/cli/build-cpio.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/build-cpio.go 2025-07-30 18:59:31.000000000 +0200 @@ -36,7 +36,7 @@ var sbomPath string var extraKeys []string var extraBuildRepos []string - var extraRuntimeRepos []string + var extraRepos []string var extraPackages []string cmd := &cobra.Command{ @@ -51,7 +51,7 @@ build.WithConfig(args[0], []string{}), build.WithExtraKeys(extraKeys), build.WithExtraBuildRepos(extraBuildRepos), - build.WithExtraRuntimeRepos(extraRuntimeRepos), + build.WithExtraRepos(extraRepos), build.WithExtraPackages(extraPackages), build.WithBuildDate(buildDate), build.WithSBOM(sbomPath), @@ -65,7 +65,7 @@ cmd.Flags().StringVar(&sbomPath, "sbom-path", "", "generate an SBOM") cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring") cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include") - cmd.Flags().StringSliceVarP(&extraRuntimeRepos, "repository-append", "r", []string{}, "path to extra repositories to include") + cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include") cmd.Flags().StringSliceVarP(&extraPackages, "package-append", "p", []string{}, "extra packages to include") return cmd diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/build-minirootfs.go new/apko-0.30.2/internal/cli/build-minirootfs.go --- old/apko-0.29.10/internal/cli/build-minirootfs.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/build-minirootfs.go 2025-07-30 18:59:31.000000000 +0200 @@ -36,7 +36,7 @@ var ignoreSignatures bool var extraKeys []string var extraBuildRepos []string - var extraRuntimeRepos []string + var extraRepos []string var extraPackages []string cmd := &cobra.Command{ @@ -50,7 +50,7 @@ build.WithConfig(args[0], []string{}), build.WithExtraKeys(extraKeys), build.WithExtraBuildRepos(extraBuildRepos), - build.WithExtraRuntimeRepos(extraRuntimeRepos), + build.WithExtraRepos(extraRepos), build.WithExtraPackages(extraPackages), build.WithTarball(args[1]), build.WithBuildDate(buildDate), @@ -67,7 +67,7 @@ cmd.Flags().BoolVar(&ignoreSignatures, "ignore-signatures", false, "ignore repository signature verification") cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring") cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include") - cmd.Flags().StringSliceVarP(&extraRuntimeRepos, "repository-append", "r", []string{}, "path to extra repositories to include") + cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include") cmd.Flags().StringSliceVarP(&extraPackages, "package-append", "p", []string{}, "extra packages to include") return cmd diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/build.go new/apko-0.30.2/internal/cli/build.go --- old/apko-0.29.10/internal/cli/build.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/build.go 2025-07-30 18:59:31.000000000 +0200 @@ -50,7 +50,7 @@ var sbomFormats []string var extraKeys []string var extraBuildRepos []string - var extraRuntimeRepos []string + var extraRepos []string var extraPackages []string var rawAnnotations []string var cacheDir string @@ -105,7 +105,7 @@ build.WithSBOMFormats(sbomFormats), build.WithExtraKeys(extraKeys), build.WithExtraBuildRepos(extraBuildRepos), - build.WithExtraRuntimeRepos(extraRuntimeRepos), + build.WithExtraRepos(extraRepos), build.WithExtraPackages(extraPackages), build.WithTags(args[1]), build.WithVCS(withVCS), @@ -127,7 +127,7 @@ cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring") cmd.Flags().StringSliceVar(&sbomFormats, "sbom-formats", sbom.DefaultOptions.Formats, "SBOM formats to output") cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include") - cmd.Flags().StringSliceVarP(&extraRuntimeRepos, "repository-append", "r", []string{}, "path to extra repositories to include") + cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include") cmd.Flags().StringSliceVarP(&extraPackages, "package-append", "p", []string{}, "extra packages to include") cmd.Flags().StringSliceVar(&rawAnnotations, "annotations", []string{}, "OCI annotations to add. Separate with colon (key:value)") cmd.Flags().StringVar(&cacheDir, "cache-dir", "", "directory to use for caching apk packages and indexes (default '' means to use system-defined cache directory)") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/clean.go new/apko-0.30.2/internal/cli/clean.go --- old/apko-0.29.10/internal/cli/clean.go 1970-01-01 01:00:00.000000000 +0100 +++ new/apko-0.30.2/internal/cli/clean.go 2025-07-30 18:59:31.000000000 +0200 @@ -0,0 +1,138 @@ +// Copyright 2025 Chainguard, Inc. +// +// 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. + +package cli + +import ( + "context" + "fmt" + "os" + "path/filepath" + + "github.com/chainguard-dev/clog" + "github.com/spf13/cobra" +) + +func cleanCmd() *cobra.Command { + var cacheDir string + var dryRun bool + + cmd := &cobra.Command{ + Use: "clean", + Short: "Clean the apko cache directory", + Long: `Clean the apko cache directory by removing all cached APK packages and APKINDEX files. + +If no cache directory is specified, the default cache directory is used: + - On Linux: ~/.cache/dev.chainguard.go-apk + - On macOS: ~/Library/Caches/dev.chainguard.go-apk + - On Windows: %LocalAppData%\dev.chainguard.go-apk`, + Example: ` apko clean + apko clean --cache-dir /custom/cache/path + apko clean --dry-run`, + RunE: func(cmd *cobra.Command, args []string) error { + return CleanImpl(cmd.Context(), cacheDir, dryRun) + }, + } + + cmd.Flags().StringVar(&cacheDir, "cache-dir", "", "directory containing the apk cache (defaults to system cache directory)") + cmd.Flags().BoolVar(&dryRun, "dry-run", false, "show cache size without deleting") + + return cmd +} + +func CleanImpl(ctx context.Context, cacheDir string, dryRun bool) error { + log := clog.FromContext(ctx) + + // Determine cache directory + if cacheDir == "" { + var err error + cacheDir, err = os.UserCacheDir() + if err != nil { + return fmt.Errorf("failed to determine user cache directory: %w", err) + } + cacheDir = filepath.Join(cacheDir, "dev.chainguard.go-apk") + } else { + var err error + cacheDir, err = filepath.Abs(cacheDir) + if err != nil { + return fmt.Errorf("failed to resolve cache directory path: %w", err) + } + } + + log.Infof("Cleaning cache directory: %s", cacheDir) + + // Check if the cache directory exists + info, err := os.Stat(cacheDir) + if err != nil { + if os.IsNotExist(err) { + log.Infof("Cache directory does not exist, nothing to clean") + return nil + } + return fmt.Errorf("failed to stat cache directory: %w", err) + } + + if !info.IsDir() { + return fmt.Errorf("cache path is not a directory: %s", cacheDir) + } + + // Calculate cache size + size, err := calculateDirSize(cacheDir) + if err != nil { + return fmt.Errorf("failed to calculate cache size: %w", err) + } + + log.Infof("Cache size: %s", formatBytes(size)) + + if dryRun { + log.Infof("Dry run mode: cache directory will not be deleted") + return nil + } + + // Remove the cache directory and all its contents + if err := os.RemoveAll(cacheDir); err != nil { + return fmt.Errorf("failed to remove cache directory: %w", err) + } + + log.Infof("Cache directory cleaned successfully") + return nil +} + +// calculateDirSize recursively calculates the total size of a directory +func calculateDirSize(path string) (int64, error) { + var size int64 + err := filepath.Walk(path, func(_ string, info os.FileInfo, err error) error { + if err != nil { + return err + } + if !info.IsDir() { + size += info.Size() + } + return nil + }) + return size, err +} + +// formatBytes formats bytes into human-readable format +func formatBytes(bytes int64) string { + const unit = 1024 + if bytes < unit { + return fmt.Sprintf("%d B", bytes) + } + div, exp := int64(unit), 0 + for n := bytes / unit; n >= unit; n /= unit { + div *= unit + exp++ + } + return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp]) +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/clean_test.go new/apko-0.30.2/internal/cli/clean_test.go --- old/apko-0.29.10/internal/cli/clean_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/apko-0.30.2/internal/cli/clean_test.go 2025-07-30 18:59:31.000000000 +0200 @@ -0,0 +1,159 @@ +// Copyright 2025 Chainguard, Inc. +// +// 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. + +package cli + +import ( + "context" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCleanImpl(t *testing.T) { + ctx := context.Background() + + t.Run("clean existing cache", func(t *testing.T) { + // Create a temporary cache directory + tmpDir := t.TempDir() + cacheDir := filepath.Join(tmpDir, "cache") + err := os.MkdirAll(cacheDir, 0755) + require.NoError(t, err) + + // Create some dummy cache files + testFiles := []string{ + "https%3A%2F%2Fdl-cdn.alpinelinux.org%2Falpine%2Fv3.18/x86_64/APKINDEX.tar.gz", + "https%3A%2F%2Fdl-cdn.alpinelinux.org%2Falpine%2Fv3.18/x86_64/package1.apk", + "https%3A%2F%2Fdl-cdn.alpinelinux.org%2Falpine%2Fv3.18/x86_64/package2.apk", + } + + for _, file := range testFiles { + dir := filepath.Dir(filepath.Join(cacheDir, file)) + err := os.MkdirAll(dir, 0755) + require.NoError(t, err) + + err = os.WriteFile(filepath.Join(cacheDir, file), []byte("dummy content"), 0644) + require.NoError(t, err) + } + + // Verify cache exists + _, err = os.Stat(cacheDir) + require.NoError(t, err) + + // Clean the cache + err = CleanImpl(ctx, cacheDir, false) + require.NoError(t, err) + + // Verify cache is gone + _, err = os.Stat(cacheDir) + require.True(t, os.IsNotExist(err)) + }) + + t.Run("dry run does not delete cache", func(t *testing.T) { + // Create a temporary cache directory + tmpDir := t.TempDir() + cacheDir := filepath.Join(tmpDir, "cache") + err := os.MkdirAll(cacheDir, 0755) + require.NoError(t, err) + + // Create a dummy cache file + testFile := filepath.Join(cacheDir, "test.apk") + err = os.WriteFile(testFile, []byte("dummy content"), 0644) + require.NoError(t, err) + + // Run clean with dry-run + err = CleanImpl(ctx, cacheDir, true) + require.NoError(t, err) + + // Verify cache still exists + _, err = os.Stat(cacheDir) + require.NoError(t, err) + _, err = os.Stat(testFile) + require.NoError(t, err) + }) + + t.Run("non-existent cache directory", func(t *testing.T) { + tmpDir := t.TempDir() + cacheDir := filepath.Join(tmpDir, "non-existent") + + // Clean should not error on non-existent directory + err := CleanImpl(ctx, cacheDir, false) + require.NoError(t, err) + }) + + t.Run("cache path is file not directory", func(t *testing.T) { + tmpDir := t.TempDir() + cacheFile := filepath.Join(tmpDir, "file") + err := os.WriteFile(cacheFile, []byte("not a directory"), 0644) + require.NoError(t, err) + + // Should error when cache path is a file + err = CleanImpl(ctx, cacheFile, false) + require.Error(t, err) + require.Contains(t, err.Error(), "not a directory") + }) +} + +func TestCalculateDirSize(t *testing.T) { + tmpDir := t.TempDir() + + // Create files with known sizes + files := map[string]int{ + "file1.txt": 100, + "file2.txt": 200, + "subdir/file3.txt": 300, + } + + totalSize := int64(0) + for path, size := range files { + fullPath := filepath.Join(tmpDir, path) + dir := filepath.Dir(fullPath) + err := os.MkdirAll(dir, 0755) + require.NoError(t, err) + + content := make([]byte, size) + err = os.WriteFile(fullPath, content, 0644) + require.NoError(t, err) + totalSize += int64(size) + } + + // Calculate directory size + size, err := calculateDirSize(tmpDir) + require.NoError(t, err) + require.Equal(t, totalSize, size) +} + +func TestFormatBytes(t *testing.T) { + tests := []struct { + bytes int64 + expected string + }{ + {0, "0 B"}, + {100, "100 B"}, + {1024, "1.0 KB"}, + {1536, "1.5 KB"}, + {1048576, "1.0 MB"}, + {1073741824, "1.0 GB"}, + {1099511627776, "1.0 TB"}, + } + + for _, tt := range tests { + t.Run(tt.expected, func(t *testing.T) { + result := formatBytes(tt.bytes) + require.Equal(t, tt.expected, result) + }) + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/commands.go new/apko-0.30.2/internal/cli/commands.go --- old/apko-0.29.10/internal/cli/commands.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/commands.go 2025-07-30 18:59:31.000000000 +0200 @@ -62,6 +62,7 @@ cmd.AddCommand(lock()) cmd.AddCommand(resolve()) cmd.AddCommand(installKeys()) + cmd.AddCommand(cleanCmd()) cmd.AddCommand(version.Version()) cmd.PersistentFlags().StringVarP(&workDir, "workdir", "C", cwd, "working dir (default is current dir where executed)") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/dot.go new/apko-0.30.2/internal/cli/dot.go --- old/apko-0.29.10/internal/cli/dot.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/dot.go 2025-07-30 18:59:31.000000000 +0200 @@ -43,7 +43,7 @@ func dotcmd() *cobra.Command { var extraKeys []string var extraBuildRepos []string - var extraRuntimeRepos []string + var extraRepos []string var archstrs []string var web, span bool var cacheDir string @@ -71,7 +71,7 @@ build.WithConfig(args[0], []string{}), build.WithExtraKeys(extraKeys), build.WithExtraBuildRepos(extraBuildRepos), - build.WithExtraRuntimeRepos(extraRuntimeRepos), + build.WithExtraRepos(extraRepos), build.WithCache(cacheDir, offline, apk.NewCache(true)), ) }, @@ -79,7 +79,7 @@ cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring") cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include") - cmd.Flags().StringSliceVarP(&extraRuntimeRepos, "repository-append", "r", []string{}, "path to extra repositories to include") + cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include") cmd.Flags().StringSliceVar(&archstrs, "arch", nil, "architectures to build for (e.g., x86_64,ppc64le,arm64) -- default is all, unless specified in config. Can also use 'host' to indicate arch of host this is running on") cmd.Flags().BoolVarP(&span, "spanning-tree", "S", false, "does something like a spanning tree to avoid a huge number of edges") cmd.Flags().BoolVar(&web, "web", false, "launch a browser") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/lock.go new/apko-0.30.2/internal/cli/lock.go --- old/apko-0.29.10/internal/cli/lock.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/lock.go 2025-07-30 18:59:31.000000000 +0200 @@ -64,7 +64,7 @@ func lockInternal(cmdName string, extension string, deprecated string) *cobra.Command { var extraKeys []string var extraBuildRepos []string - var extraRuntimeRepos []string + var extraRepos []string var archstrs []string var output string var includePaths []string @@ -93,7 +93,7 @@ build.WithConfig(args[0], includePaths), build.WithExtraKeys(extraKeys), build.WithExtraBuildRepos(extraBuildRepos), - build.WithExtraRuntimeRepos(extraRuntimeRepos), + build.WithExtraRepos(extraRepos), build.WithIncludePaths(includePaths), build.WithIgnoreSignatures(ignoreSignatures), build.WithCache(cacheDir, false, apk.NewCache(true)), @@ -104,7 +104,7 @@ cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring") cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include") - cmd.Flags().StringSliceVarP(&extraRuntimeRepos, "repository-append", "r", []string{}, "path to extra repositories to include") + cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include") cmd.Flags().StringSliceVar(&archstrs, "arch", nil, "architectures to build for (e.g., x86_64,ppc64le,arm64) -- default is all, unless specified in config. Can also use 'host' to indicate arch of host this is running on") cmd.Flags().StringVar(&output, "output", "", "path to file where lock file will be written") cmd.Flags().StringSliceVar(&includePaths, "include-paths", []string{}, "Additional include paths where to look for input files (config, base image, etc.). By default apko will search for paths only in workdir. Include paths may be absolute, or relative. Relative paths are interpreted relative to workdir. For adding extra paths for packages, use --repository-append") @@ -154,10 +154,11 @@ DeepChecksum: o.ImageConfigChecksum, }, Contents: pkglock.LockContents{ - Packages: make([]pkglock.LockPkg, 0, len(ic.Contents.Packages)), - BuildRepositories: make([]pkglock.LockRepo, 0, len(ic.Contents.BuildRepositories)), - RuntimeRepositories: make([]pkglock.LockRepo, 0, len(ic.Contents.RuntimeRepositories)), - Keyrings: make([]pkglock.LockKeyring, 0, len(ic.Contents.Keyring)), + Packages: make([]pkglock.LockPkg, 0, len(ic.Contents.Packages)), + BuildRepositories: make([]pkglock.LockRepo, 0, len(ic.Contents.BuildRepositories)), + RuntimeOnlyRepositories: make([]pkglock.LockRepo, 0, len(ic.Contents.RuntimeOnlyRepositories)), + Repositories: make([]pkglock.LockRepo, 0, len(ic.Contents.Repositories)), + Keyrings: make([]pkglock.LockKeyring, 0, len(ic.Contents.Keyring)), }, } @@ -216,41 +217,47 @@ lock.Contents.Packages = append(lock.Contents.Packages, lockPkg) } for _, repositoryURI := range ic.Contents.BuildRepositories { - repo := apk.Repository{URI: fmt.Sprintf("%s/%s", repositoryURI, arch.ToAPK())} - name, err := RemoveLabel(stripURLScheme(repo.URI)) + repoLock, err := repoLock(repositoryURI, arch) if err != nil { - return fmt.Errorf("failed to remove label from repository URI: %w", err) + return fmt.Errorf("locking build repositories: %w", err) } - url, err := RemoveLabel(repo.IndexURI()) - if err != nil { - return fmt.Errorf("failed to remove label from repository index URI: %w", err) - } - lock.Contents.BuildRepositories = append(lock.Contents.BuildRepositories, pkglock.LockRepo{ - Name: name, - URL: url, - Architecture: arch.ToAPK(), - }) - } - for _, repositoryURI := range ic.Contents.RuntimeRepositories { - repo := apk.Repository{URI: fmt.Sprintf("%s/%s", repositoryURI, arch.ToAPK())} - name, err := RemoveLabel(stripURLScheme(repo.URI)) + lock.Contents.BuildRepositories = append(lock.Contents.BuildRepositories, repoLock) + } + for _, repositoryURI := range ic.Contents.RuntimeOnlyRepositories { + repoLock, err := repoLock(repositoryURI, arch) if err != nil { - return fmt.Errorf("failed to remove label from repository URI: %w", err) + return fmt.Errorf("locking runtime repositories: %w", err) } - url, err := RemoveLabel(repo.IndexURI()) + lock.Contents.RuntimeOnlyRepositories = append(lock.Contents.RuntimeOnlyRepositories, repoLock) + } + for _, repositoryURI := range ic.Contents.Repositories { + repoLock, err := repoLock(repositoryURI, arch) if err != nil { - return fmt.Errorf("failed to remove label from repository index URI: %w", err) + return fmt.Errorf("locking repositories: %w", err) } - lock.Contents.RuntimeRepositories = append(lock.Contents.RuntimeRepositories, pkglock.LockRepo{ - Name: name, - URL: url, - Architecture: arch.ToAPK(), - }) + lock.Contents.Repositories = append(lock.Contents.Repositories, repoLock) } } return lock.SaveToFile(output) } +func repoLock(repositoryURI string, arch types.Architecture) (pkglock.LockRepo, error) { + repo := apk.Repository{URI: fmt.Sprintf("%s/%s", repositoryURI, arch.ToAPK())} + name, err := RemoveLabel(stripURLScheme(repo.URI)) + if err != nil { + return pkglock.LockRepo{}, fmt.Errorf("failed to remove label from repository URI: %w", err) + } + url, err := RemoveLabel(repo.IndexURI()) + if err != nil { + return pkglock.LockRepo{}, fmt.Errorf("failed to remove label from repository index URI: %w", err) + } + return pkglock.LockRepo{ + Name: name, + URL: url, + Architecture: arch.ToAPK(), + }, nil +} + func stripURLScheme(url string) string { return strings.TrimPrefix( strings.TrimPrefix(url, "https://"), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/publish.go new/apko-0.30.2/internal/cli/publish.go --- old/apko-0.29.10/internal/cli/publish.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/publish.go 2025-07-30 18:59:31.000000000 +0200 @@ -46,7 +46,7 @@ var archstrs []string var extraKeys []string var extraBuildRepos []string - var extraRuntimeRepos []string + var extraRepos []string var extraPackages []string var rawAnnotations []string var withVCS bool @@ -112,7 +112,7 @@ build.WithSBOMFormats(sbomFormats), build.WithExtraKeys(extraKeys), build.WithExtraBuildRepos(extraBuildRepos), - build.WithExtraRuntimeRepos(extraRuntimeRepos), + build.WithExtraRepos(extraRepos), build.WithExtraPackages(extraPackages), build.WithTags(args[1:]...), build.WithVCS(withVCS), @@ -142,7 +142,7 @@ cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring") cmd.Flags().StringSliceVar(&sbomFormats, "sbom-formats", sbom.DefaultOptions.Formats, "SBOM formats to output") cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include") - cmd.Flags().StringSliceVarP(&extraRuntimeRepos, "repository-append", "r", []string{}, "path to extra repositories to include") + cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include") cmd.Flags().StringSliceVarP(&extraPackages, "package-append", "p", []string{}, "extra packages to include") cmd.Flags().StringSliceVar(&rawAnnotations, "annotations", []string{}, "OCI annotations to add. Separate with colon (key:value)") cmd.Flags().StringVar(&cacheDir, "cache-dir", "", "directory to use for caching apk packages and indexes (default '' means to use system-defined cache directory)") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/publish_test.go new/apko-0.30.2/internal/cli/publish_test.go --- old/apko-0.29.10/internal/cli/publish_test.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/publish_test.go 2025-07-30 18:59:31.000000000 +0200 @@ -167,7 +167,7 @@ // This test will fail if we ever make a change in apko that changes the image. // Sometimes, this is intentional, and we need to change this and bump the version. - want := "sha256:66dc21761826860d1152e8a6defa7919ad3f65af5d56fd75164c4c36ba85c648" + want := "sha256:d930d3cea6e6b1e53f388302a0bbe6ddff31db9952a667ed2ab6b93c1eeade6c" require.Equal(t, want, digest.String()) im, err := idx.IndexManifest() @@ -196,5 +196,8 @@ if strings.Contains(string(b), "./packages") { t.Errorf("etc/apk/repositories contains build_repositories entry %q", "./packages") } + if !strings.Contains(string(b), "apk.cgr.dev/runtime-only-repo") { + t.Errorf("etc/apk/repositories does not contain expected runtime_repositories entry %q", "apk.cgr.dev/runtime-only-repo") + } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/show-config.go new/apko-0.30.2/internal/cli/show-config.go --- old/apko-0.29.10/internal/cli/show-config.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/show-config.go 2025-07-30 18:59:31.000000000 +0200 @@ -31,7 +31,7 @@ func showConfig() *cobra.Command { var extraKeys []string var extraBuildRepos []string - var extraRuntimeRepos []string + var extraRepos []string var cacheDir string var offline bool @@ -49,7 +49,7 @@ build.WithConfig(args[0], []string{}), build.WithExtraKeys(extraKeys), build.WithExtraBuildRepos(extraBuildRepos), - build.WithExtraRuntimeRepos(extraRuntimeRepos), + build.WithExtraRepos(extraRepos), build.WithCache(cacheDir, offline, apk.NewCache(true)), ) }, @@ -57,7 +57,7 @@ cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring") cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include") - cmd.Flags().StringSliceVarP(&extraRuntimeRepos, "repository-append", "r", []string{}, "path to extra repositories to include") + cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include") cmd.Flags().StringVar(&cacheDir, "cache-dir", "", "directory to use for caching apk packages and indexes (default '' means to use system-defined cache directory)") cmd.Flags().BoolVar(&offline, "offline", false, "do not use network to fetch packages (cache must be pre-populated)") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/show-packages.go new/apko-0.30.2/internal/cli/show-packages.go --- old/apko-0.29.10/internal/cli/show-packages.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/show-packages.go 2025-07-30 18:59:31.000000000 +0200 @@ -63,7 +63,7 @@ func showPackages() *cobra.Command { var extraKeys []string var extraBuildRepos []string - var extraRuntimeRepos []string + var extraRepos []string var archstrs []string var format string var tmpl string @@ -108,7 +108,7 @@ build.WithConfig(args[0], []string{}), build.WithExtraKeys(extraKeys), build.WithExtraBuildRepos(extraBuildRepos), - build.WithExtraRuntimeRepos(extraRuntimeRepos), + build.WithExtraRepos(extraRepos), build.WithCache(cacheDir, offline, apk.NewCache(true)), ) }, @@ -116,7 +116,7 @@ cmd.Flags().StringSliceVarP(&extraKeys, "keyring-append", "k", []string{}, "path to extra keys to include in the keyring") cmd.Flags().StringSliceVarP(&extraBuildRepos, "build-repository-append", "b", []string{}, "path to extra repositories to include") - cmd.Flags().StringSliceVarP(&extraRuntimeRepos, "repository-append", "r", []string{}, "path to extra repositories to include") + cmd.Flags().StringSliceVarP(&extraRepos, "repository-append", "r", []string{}, "path to extra repositories to include") cmd.Flags().StringSliceVar(&archstrs, "arch", nil, "architectures to build for (e.g., x86_64,ppc64le,arm64) -- default is all, unless specified in config. Can also use 'host' to indicate arch of host this is running on") cmd.Flags().StringVar(&format, "format", showPkgsFormatDefault, "format for showing packages; if pre-defined from list, will use that, else go template. See https://pkg.go.dev/text/template for more information. Available vars are `.Name`, `.Version`, `.Source`") cmd.Flags().StringVar(&cacheDir, "cache-dir", "", "directory to use for caching apk packages and indexes (default '' means to use system-defined cache directory)") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/testdata/apko.lock.json new/apko-0.30.2/internal/cli/testdata/apko.lock.json --- old/apko-0.29.10/internal/cli/testdata/apko.lock.json 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/testdata/apko.lock.json 2025-07-30 18:59:31.000000000 +0200 @@ -12,6 +12,7 @@ } ], "build_repositories": [], + "runtime_repositories": [], "repositories": [ { "name": "./testdata/packages/x86_64", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/testdata/image_on_top.apko.lock.json new/apko-0.30.2/internal/cli/testdata/image_on_top.apko.lock.json --- old/apko-0.29.10/internal/cli/testdata/image_on_top.apko.lock.json 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/testdata/image_on_top.apko.lock.json 2025-07-30 18:59:31.000000000 +0200 @@ -12,6 +12,7 @@ } ], "build_repositories": [], + "runtime_repositories": [], "repositories": [ { "name": "./testdata/packages/x86_64", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/internal/cli/testdata/layering.yaml new/apko-0.30.2/internal/cli/testdata/layering.yaml --- old/apko-0.29.10/internal/cli/testdata/layering.yaml 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/internal/cli/testdata/layering.yaml 2025-07-30 18:59:31.000000000 +0200 @@ -3,6 +3,8 @@ - ./testdata/melange.rsa.pub build_repositories: - ./packages + runtime_repositories: + - apk.cgr.dev/runtime-only-repo repositories: - ./testdata/packages packages: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/apk.go new/apko-0.30.2/pkg/build/apk.go --- old/apko-0.29.10/pkg/build/apk.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/apk.go 2025-07-30 18:59:31.000000000 +0200 @@ -30,7 +30,10 @@ // // We do not include the build-time repositories here, because this is // what defines the /etc/apk/repositories file in the final image. - runtimeRepos := sets.List(sets.New(bc.ic.Contents.RuntimeRepositories...).Insert(bc.o.ExtraRuntimeRepos...)) + runtimeRepos := sets.List( + sets.New(bc.ic.Contents.Repositories...). + Insert(bc.ic.Contents.RuntimeOnlyRepositories...). + Insert(bc.o.ExtraRepos...)) if err := bc.apk.SetRepositories(ctx, runtimeRepos); err != nil { return fmt.Errorf("failed to set apk repositories: %w", err) } @@ -45,11 +48,14 @@ // We set the repositories file to be the union of all of the // repositories when we initialize things, and we overwrite it // with just the runtime repositories when we are done. + // + // We do not include the runtime-only repositories here, because those repos + // should not be used at build time. buildRepos := sets.List( sets.New(bc.ic.Contents.BuildRepositories...). - Insert(bc.ic.Contents.RuntimeRepositories...). + Insert(bc.ic.Contents.Repositories...). Insert(bc.o.ExtraBuildRepos...). - Insert(bc.o.ExtraRuntimeRepos...), + Insert(bc.o.ExtraRepos...), ) if err := bc.apk.InitDB(ctx, buildRepos...); err != nil { return fmt.Errorf("failed to initialize apk database: %w", err) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/build_test.go new/apko-0.30.2/pkg/build/build_test.go --- old/apko-0.29.10/pkg/build/build_test.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/build_test.go 2025-07-30 18:59:31.000000000 +0200 @@ -195,9 +195,9 @@ bc, err := build.New(ctx, fs.NewMemFS(), build.WithImageConfiguration(types.ImageConfiguration{ Contents: types.ImageContents{ - RuntimeRepositories: []string{s.URL}, - Keyring: []string{s.URL + "/melange.rsa.pub"}, - Packages: []string{"pretend-baselayout"}, + Repositories: []string{s.URL}, + Keyring: []string{s.URL + "/melange.rsa.pub"}, + Packages: []string{"pretend-baselayout"}, }, Archs: types.ParseArchitectures([]string{"amd64", "arm64"}), }), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/lock.go new/apko-0.30.2/pkg/build/lock.go --- old/apko-0.29.10/pkg/build/lock.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/lock.go 2025-07-30 18:59:31.000000000 +0200 @@ -41,7 +41,7 @@ } input.Contents.BuildRepositories = sets.List(sets.New(input.Contents.BuildRepositories...).Insert(o.ExtraBuildRepos...)) - input.Contents.RuntimeRepositories = sets.List(sets.New(input.Contents.RuntimeRepositories...).Insert(o.ExtraRuntimeRepos...)) + input.Contents.Repositories = sets.List(sets.New(input.Contents.Repositories...).Insert(o.ExtraRepos...)) input.Contents.Keyring = sets.List(sets.New(input.Contents.Keyring...).Insert(o.ExtraKeyFiles...)) mc, err := NewMultiArch(ctx, input.Archs, append(opts, WithImageConfiguration(*input))...) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/options.go new/apko-0.30.2/pkg/build/options.go --- old/apko-0.29.10/pkg/build/options.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/options.go 2025-07-30 18:59:31.000000000 +0200 @@ -131,9 +131,9 @@ } } -func WithExtraRuntimeRepos(repos []string) Option { +func WithExtraRepos(repos []string) Option { return func(bc *Context) error { - bc.o.ExtraRuntimeRepos = repos + bc.o.ExtraRepos = repos return nil } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/types/image_configuration.go new/apko-0.30.2/pkg/build/types/image_configuration.go --- old/apko-0.29.10/pkg/build/types/image_configuration.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/types/image_configuration.go 2025-07-30 18:59:31.000000000 +0200 @@ -73,19 +73,9 @@ } } - runtimeRepos := make([]string, 0, len(ic.Contents.RuntimeRepositories)) - for _, repo := range ic.Contents.RuntimeRepositories { - repo = strings.TrimRight(repo, "/") - runtimeRepos = append(runtimeRepos, repo) - } - ic.Contents.RuntimeRepositories = runtimeRepos - - buildRepos := make([]string, 0, len(ic.Contents.BuildRepositories)) - for _, repo := range ic.Contents.BuildRepositories { - repo = strings.TrimRight(repo, "/") - buildRepos = append(buildRepos, repo) - } - ic.Contents.BuildRepositories = buildRepos + ic.Contents.BuildRepositories = trimRepos(ic.Contents.BuildRepositories) + ic.Contents.RuntimeOnlyRepositories = trimRepos(ic.Contents.RuntimeOnlyRepositories) + ic.Contents.Repositories = trimRepos(ic.Contents.Repositories) // The top level components restriction is on the conservative side. Some of them would probably work out of the box. // If someone needs any of them, it should be a matter of testing and hopefully doing minor changes. @@ -105,6 +95,15 @@ return nil } +func trimRepos(repos []string) []string { + result := make([]string, 0, len(repos)) + for _, repo := range repos { + repo = strings.TrimRight(repo, "/") + result = append(result, repo) + } + return result +} + // Merge this configuration into the target, with the target taking precedence. func (ic *ImageConfiguration) MergeInto(target *ImageConfiguration) error { if reflect.ValueOf(target.Entrypoint).IsZero() { @@ -166,7 +165,8 @@ func (i *ImageContents) MergeInto(target *ImageContents) error { target.Keyring = slices.Concat(i.Keyring, target.Keyring) target.BuildRepositories = slices.Concat(i.BuildRepositories, target.BuildRepositories) - target.RuntimeRepositories = slices.Concat(i.RuntimeRepositories, target.RuntimeRepositories) + target.RuntimeOnlyRepositories = slices.Concat(i.RuntimeOnlyRepositories, target.RuntimeOnlyRepositories) + target.Repositories = slices.Concat(i.Repositories, target.Repositories) target.Packages = slices.Concat(i.Packages, target.Packages) if target.BaseImage == nil { target.BaseImage = i.BaseImage @@ -244,7 +244,8 @@ log.Infof("image configuration:") log.Infof(" contents:") log.Infof(" build repositories: %v", ic.Contents.BuildRepositories) - log.Infof(" runtime repositories: %v", ic.Contents.RuntimeRepositories) + log.Infof(" runtime repositories: %v", ic.Contents.RuntimeOnlyRepositories) + log.Infof(" repositories: %v", ic.Contents.Repositories) log.Infof(" keyring: %v", ic.Contents.Keyring) log.Infof(" packages: %v", ic.Contents.Packages) if ic.Entrypoint.Type != "" || ic.Entrypoint.Command != "" || len(ic.Entrypoint.Services) != 0 { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/types/image_configuration_test.go new/apko-0.30.2/pkg/build/types/image_configuration_test.go --- old/apko-0.29.10/pkg/build/types/image_configuration_test.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/types/image_configuration_test.go 2025-07-30 18:59:31.000000000 +0200 @@ -27,7 +27,8 @@ require.NoError(t, ic.Load(ctx, configPath, []string{"testdata"}, hasher)) require.ElementsMatch(t, ic.Contents.BuildRepositories, []string{"secret repository"}) - require.ElementsMatch(t, ic.Contents.RuntimeRepositories, []string{"repository"}) + require.ElementsMatch(t, ic.Contents.RuntimeOnlyRepositories, []string{"runtime repository"}) + require.ElementsMatch(t, ic.Contents.Repositories, []string{"repository"}) require.ElementsMatch(t, ic.Contents.Keyring, []string{"key"}) require.ElementsMatch(t, ic.Contents.Packages, []string{"package"}) } @@ -41,7 +42,8 @@ require.NoError(t, ic.Load(ctx, configPath, []string{}, hasher)) require.ElementsMatch(t, ic.Contents.BuildRepositories, []string{"secret repository", "other_secret repository"}) - require.ElementsMatch(t, ic.Contents.RuntimeRepositories, []string{"repository"}) + require.ElementsMatch(t, ic.Contents.RuntimeOnlyRepositories, []string{"runtime repository", "other runtime repository"}) + require.ElementsMatch(t, ic.Contents.Repositories, []string{"repository"}) require.ElementsMatch(t, ic.Contents.Keyring, []string{"key"}) require.ElementsMatch(t, ic.Contents.Packages, []string{"package", "other_package"}) } @@ -75,10 +77,10 @@ name: "simple blend of contents", source: types.ImageConfiguration{ Contents: types.ImageContents{ - Keyring: []string{"foo"}, - BuildRepositories: []string{"foo"}, - RuntimeRepositories: []string{"foo"}, - Packages: []string{"foo"}, + Keyring: []string{"foo"}, + BuildRepositories: []string{"foo"}, + Repositories: []string{"foo"}, + Packages: []string{"foo"}, }, Environment: map[string]string{ "EXTRA": "foo", @@ -94,18 +96,18 @@ }, target: types.ImageConfiguration{ Contents: types.ImageContents{ - Keyring: []string{"bar"}, - BuildRepositories: []string{"bar"}, - RuntimeRepositories: []string{"bar"}, - Packages: []string{"bar"}, + Keyring: []string{"bar"}, + BuildRepositories: []string{"bar"}, + Repositories: []string{"bar"}, + Packages: []string{"bar"}, }, }, expected: types.ImageConfiguration{ Contents: types.ImageContents{ - Keyring: []string{"foo", "bar"}, - BuildRepositories: []string{"foo", "bar"}, - RuntimeRepositories: []string{"foo", "bar"}, - Packages: []string{"foo", "bar"}, + Keyring: []string{"foo", "bar"}, + BuildRepositories: []string{"foo", "bar"}, + Repositories: []string{"foo", "bar"}, + Packages: []string{"foo", "bar"}, }, Environment: map[string]string{ "EXTRA": "foo", @@ -123,36 +125,36 @@ name: "simple blend of contents", source: types.ImageConfiguration{ Contents: types.ImageContents{ - Keyring: []string{"foo"}, - BuildRepositories: []string{"foo"}, - RuntimeRepositories: []string{"foo"}, - Packages: []string{"foo"}, + Keyring: []string{"foo"}, + BuildRepositories: []string{"foo"}, + Repositories: []string{"foo"}, + Packages: []string{"foo"}, }, }, target: types.ImageConfiguration{ Contents: types.ImageContents{ - Keyring: []string{"bar"}, - BuildRepositories: []string{"bar"}, - RuntimeRepositories: []string{"bar"}, - Packages: []string{"bar"}, + Keyring: []string{"bar"}, + BuildRepositories: []string{"bar"}, + Repositories: []string{"bar"}, + Packages: []string{"bar"}, }, }, expected: types.ImageConfiguration{ Contents: types.ImageContents{ - Keyring: []string{"foo", "bar"}, - BuildRepositories: []string{"foo", "bar"}, - RuntimeRepositories: []string{"foo", "bar"}, - Packages: []string{"foo", "bar"}, + Keyring: []string{"foo", "bar"}, + BuildRepositories: []string{"foo", "bar"}, + Repositories: []string{"foo", "bar"}, + Packages: []string{"foo", "bar"}, }, }, }, { name: "conflict resolution", source: types.ImageConfiguration{ Contents: types.ImageContents{ - Keyring: []string{"foo"}, - BuildRepositories: []string{"foo"}, - RuntimeRepositories: []string{"foo"}, - Packages: []string{"foo"}, + Keyring: []string{"foo"}, + BuildRepositories: []string{"foo"}, + Repositories: []string{"foo"}, + Packages: []string{"foo"}, }, Cmd: "foo", StopSignal: "foo", @@ -197,10 +199,10 @@ }, expected: types.ImageConfiguration{ Contents: types.ImageContents{ - Keyring: []string{"foo"}, - BuildRepositories: []string{"foo"}, - RuntimeRepositories: []string{"foo"}, - Packages: []string{"foo"}, + Keyring: []string{"foo"}, + BuildRepositories: []string{"foo"}, + Repositories: []string{"foo"}, + Packages: []string{"foo"}, }, Cmd: "bar", StopSignal: "bar", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/types/schema.json new/apko-0.30.2/pkg/build/types/schema.json --- old/apko-0.29.10/pkg/build/types/schema.json 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/types/schema.json 2025-07-30 18:59:31.000000000 +0200 @@ -148,6 +148,13 @@ "type": "array", "description": "A list of apk repositories to use for pulling packages at build time,\nwhich are not installed into /etc/apk/repositories in the image (to\ninstall packages at runtime)" }, + "runtime_repositories": { + "items": { + "type": "string" + }, + "type": "array", + "description": "A list of apk repositories that are installed into /etc/apk/repositories in the image but not used\nat build time" + }, "repositories": { "items": { "type": "string" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/types/testdata/overlay/base.apko.yaml new/apko-0.30.2/pkg/build/types/testdata/overlay/base.apko.yaml --- old/apko-0.29.10/pkg/build/types/testdata/overlay/base.apko.yaml 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/types/testdata/overlay/base.apko.yaml 2025-07-30 18:59:31.000000000 +0200 @@ -1,9 +1,11 @@ contents: build_repositories: - "secret repository" + runtime_repositories: + - "runtime repository" repositories: - "repository" keyring: - "key" packages: - - "package" \ No newline at end of file + - "package" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/types/testdata/overlay/overlay_with_package.apko.yaml new/apko-0.30.2/pkg/build/types/testdata/overlay/overlay_with_package.apko.yaml --- old/apko-0.29.10/pkg/build/types/testdata/overlay/overlay_with_package.apko.yaml 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/types/testdata/overlay/overlay_with_package.apko.yaml 2025-07-30 18:59:31.000000000 +0200 @@ -3,5 +3,7 @@ contents: build_repositories: - "other_secret repository" + runtime_repositories: + - "other runtime repository" packages: - - "other_package" \ No newline at end of file + - "other_package" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/build/types/types.go new/apko-0.30.2/pkg/build/types/types.go --- old/apko-0.29.10/pkg/build/types/types.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/build/types/types.go 2025-07-30 18:59:31.000000000 +0200 @@ -79,10 +79,13 @@ // which are not installed into /etc/apk/repositories in the image (to // install packages at runtime) BuildRepositories []string `json:"build_repositories,omitempty" yaml:"build_repositories,omitempty"` + // A list of apk repositories that are installed into /etc/apk/repositories in the image but not used + // at build time + RuntimeOnlyRepositories []string `json:"runtime_repositories,omitempty" yaml:"runtime_repositories,omitempty"` // A list of apk repositories to use for pulling packages during both the // initial construction of the image, and also at runtime by seeding them // into /etc/apk/repositories in the resulting image. - RuntimeRepositories []string `json:"repositories,omitempty" yaml:"repositories,omitempty"` + Repositories []string `json:"repositories,omitempty" yaml:"repositories,omitempty"` // A list of public keys used to verify the desired repositories Keyring []string `json:"keyring,omitempty" yaml:"keyring,omitempty"` // A list of packages to include in the image @@ -106,13 +109,13 @@ ri.BuildRepositories[idx] = parsed.Redacted() } - for idx, repo := range ri.RuntimeRepositories { + for idx, repo := range ri.Repositories { rawURL := repo parsed, err := url.Parse(rawURL) if err != nil { return nil, fmt.Errorf("parsing repository URL: %w", err) } - ri.RuntimeRepositories[idx] = parsed.Redacted() + ri.Repositories[idx] = parsed.Redacted() } for idx, key := range ri.Keyring { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/lock/lock.go new/apko-0.30.2/pkg/lock/lock.go --- old/apko-0.29.10/pkg/lock/lock.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/lock/lock.go 2025-07-30 18:59:31.000000000 +0200 @@ -24,9 +24,10 @@ } type LockContents struct { - Keyrings []LockKeyring `json:"keyring"` - BuildRepositories []LockRepo `json:"build_repositories"` - RuntimeRepositories []LockRepo `json:"repositories"` + Keyrings []LockKeyring `json:"keyring"` + BuildRepositories []LockRepo `json:"build_repositories"` + RuntimeOnlyRepositories []LockRepo `json:"runtime_repositories"` + Repositories []LockRepo `json:"repositories"` // Packages in order of installation -> for a single architecture. Packages []LockPkg `json:"packages"` } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.29.10/pkg/options/options.go new/apko-0.30.2/pkg/options/options.go --- old/apko-0.29.10/pkg/options/options.go 2025-07-26 01:32:16.000000000 +0200 +++ new/apko-0.30.2/pkg/options/options.go 2025-07-30 18:59:31.000000000 +0200 @@ -40,7 +40,7 @@ SBOMFormats []string `json:"sbomFormats,omitempty"` ExtraKeyFiles []string `json:"extraKeyFiles,omitempty"` ExtraBuildRepos []string `json:"extraBuildRepos,omitempty"` - ExtraRuntimeRepos []string `json:"extraRepos,omitempty"` + ExtraRepos []string `json:"extraRepos,omitempty"` ExtraPackages []string `json:"extraPackages,omitempty"` Arch types.Architecture `json:"arch,omitempty"` TempDirPath string `json:"tempDirPath,omitempty"` ++++++ apko.obsinfo ++++++ --- /var/tmp/diff_new_pack.AV6b84/_old 2025-08-02 00:44:10.672592669 +0200 +++ /var/tmp/diff_new_pack.AV6b84/_new 2025-08-02 00:44:10.676592835 +0200 @@ -1,5 +1,5 @@ name: apko -version: 0.29.10 -mtime: 1753486336 -commit: d8e6e78f84404d552e4d9ca1e5654d68a8140186 +version: 0.30.2 +mtime: 1753894771 +commit: d6f3361063f4b2fc8b25994bd255440eb05b09cb ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/apko/vendor.tar.gz /work/SRC/openSUSE:Factory/.apko.new.1085/vendor.tar.gz differ: char 13, line 1