Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package timoni for openSUSE:Factory checked in at 2023-10-10 20:58:53 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/timoni (Old) and /work/SRC/openSUSE:Factory/.timoni.new.28202 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "timoni" Tue Oct 10 20:58:53 2023 rev:8 rq:1116322 version:0.14.2 Changes: -------- --- /work/SRC/openSUSE:Factory/timoni/timoni.changes 2023-10-08 12:21:53.177854164 +0200 +++ /work/SRC/openSUSE:Factory/.timoni.new.28202/timoni.changes 2023-10-10 20:59:07.655530953 +0200 @@ -1,0 +2,9 @@ +Sun Oct 08 15:56:41 UTC 2023 - ka...@b1-systems.de + +- Update to version 0.14.2: + * Log bundle apply duration + * Print artifact URL and digest after push + * bundle: Pull all modules before attempting apply + * Uninstall bundle instances in reverse order + +------------------------------------------------------------------- Old: ---- timoni-0.14.1.obscpio New: ---- timoni-0.14.2.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ timoni.spec ++++++ --- /var/tmp/diff_new_pack.3r8tg7/_old 2023-10-10 20:59:09.659603627 +0200 +++ /var/tmp/diff_new_pack.3r8tg7/_new 2023-10-10 20:59:09.663603772 +0200 @@ -19,7 +19,7 @@ %define __arch_install_post export NO_BRP_STRIP_DEBUG=true Name: timoni -Version: 0.14.1 +Version: 0.14.2 Release: 0 Summary: Package manager for Kubernetes, powered by CUE and inspired by Helm License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.3r8tg7/_old 2023-10-10 20:59:09.691604787 +0200 +++ /var/tmp/diff_new_pack.3r8tg7/_new 2023-10-10 20:59:09.695604932 +0200 @@ -3,7 +3,7 @@ <param name="url">https://github.com/stefanprodan/timoni</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.14.1</param> + <param name="revision">v0.14.2</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.3r8tg7/_old 2023-10-10 20:59:09.711605512 +0200 +++ /var/tmp/diff_new_pack.3r8tg7/_new 2023-10-10 20:59:09.715605657 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/stefanprodan/timoni</param> - <param name="changesrevision">f68b7c3560cecfd4e1ade1eb14b53b226bcd54c9</param></service></servicedata> + <param name="changesrevision">a5f6a97af9c0ea269b1502e18e3ff43617a06ea6</param></service></servicedata> (No newline at EOF) ++++++ timoni-0.14.1.obscpio -> timoni-0.14.2.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/cmd/timoni/artifact_push.go new/timoni-0.14.2/cmd/timoni/artifact_push.go --- old/timoni-0.14.1/cmd/timoni/artifact_push.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/cmd/timoni/artifact_push.go 2023-10-08 17:02:46.000000000 +0200 @@ -160,7 +160,12 @@ } } - log.Info(fmt.Sprintf("digest: %s", colorizeSubject(digestURL))) + digest, err := oci.ParseDigest(digestURL) + if err != nil { + return err + } + log.Info(fmt.Sprintf("artifact: %s", colorizeSubject(ociURL))) + log.Info(fmt.Sprintf("digest: %s", colorizeSubject(digest.DigestStr()))) return nil } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/cmd/timoni/bundle_apply.go new/timoni-0.14.2/cmd/timoni/bundle_apply.go --- old/timoni-0.14.1/cmd/timoni/bundle_apply.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/cmd/timoni/bundle_apply.go 2023-10-08 17:02:46.000000000 +0200 @@ -22,6 +22,7 @@ "io" "maps" "os" + "path" "strings" "time" @@ -99,6 +100,7 @@ } func runBundleApplyCmd(cmd *cobra.Command, _ []string) error { + start := time.Now() files := bundleApplyArgs.files for i, file := range files { if file == "-" { @@ -174,55 +176,64 @@ } } - log.Info(fmt.Sprintf("applying %v instance(s)", len(bundle.Instances))) + ctxPull, cancel := context.WithTimeout(ctx, rootArgs.timeout) + defer cancel() + + for _, instance := range bundle.Instances { + spin := StartSpinner(fmt.Sprintf("pulling %s", instance.Module.Repository)) + pullErr := fetchBundleInstanceModule(ctxPull, instance, tmpDir) + spin.Stop() + if pullErr != nil { + return pullErr + } + } kubeVersion, err := runtime.ServerVersion(kubeconfigArgs) if err != nil { return err } + if bundleApplyArgs.dryrun || bundleApplyArgs.diff { + log.Info(fmt.Sprintf("applying %v instance(s) %s", + len(bundle.Instances), colorizeDryRun("(server dry run)"))) + } else { + log.Info(fmt.Sprintf("applying %v instance(s)", + len(bundle.Instances))) + } + for _, instance := range bundle.Instances { - log.Info(fmt.Sprintf("applying instance %s", instance.Name)) - if err := applyBundleInstance(logr.NewContext(ctx, log), cuectx, instance, kubeVersion); err != nil { + if err := applyBundleInstance(logr.NewContext(ctx, log), cuectx, instance, kubeVersion, tmpDir); err != nil { return err } } + elapsed := time.Since(start) if bundleApplyArgs.dryrun || bundleApplyArgs.diff { - log.Info(fmt.Sprintf("applied %v instance(s) (server dry run)", len(bundle.Instances))) + log.Info(fmt.Sprintf("applied successfully %s", + colorizeDryRun("(server dry run)"))) } else { - log.Info("applied successfully") + log.Info(fmt.Sprintf("applied successfully in %s", elapsed.Round(time.Second))) } return nil } -func applyBundleInstance(ctx context.Context, cuectx *cue.Context, instance engine.BundleInstance, kubeVersion string) error { - moduleVersion := instance.Module.Version - sourceURL := fmt.Sprintf("%s:%s", instance.Module.Repository, instance.Module.Version) +func fetchBundleInstanceModule(ctx context.Context, instance *engine.BundleInstance, rootDir string) error { + modDir := path.Join(rootDir, instance.Name) + if err := os.MkdirAll(modDir, os.ModePerm); err != nil { + return err + } + moduleVersion := instance.Module.Version if moduleVersion == apiv1.LatestVersion && instance.Module.Digest != "" { - sourceURL = fmt.Sprintf("%s@%s", instance.Module.Repository, instance.Module.Digest) moduleVersion = "@" + instance.Module.Digest } - log := LoggerBundleInstance(ctx, instance.Bundle, instance.Name) - log.Info(fmt.Sprintf("pulling %s", sourceURL)) - - tmpDir, err := os.MkdirTemp("", apiv1.FieldManager) - if err != nil { - return err - } - defer os.RemoveAll(tmpDir) - - ctxPull, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() - fetcher := engine.NewFetcher( - ctxPull, + ctx, instance.Module.Repository, moduleVersion, - tmpDir, + modDir, bundleApplyArgs.creds.String(), ) mod, err := fetcher.Fetch() @@ -235,11 +246,19 @@ mod.Digest, instance.Module.Version, instance.Module.Digest) } + instance.Module = *mod + return nil +} + +func applyBundleInstance(ctx context.Context, cuectx *cue.Context, instance *engine.BundleInstance, kubeVersion string, rootDir string) error { + log := LoggerBundleInstance(ctx, instance.Bundle, instance.Name) + + modDir := path.Join(rootDir, instance.Name, "module") builder := engine.NewModuleBuilder( cuectx, instance.Name, instance.Namespace, - fetcher.GetModuleRoot(), + modDir, bundleApplyArgs.pkg.String(), ) @@ -247,23 +266,24 @@ return err } - mod.Name, err = builder.GetModuleName() + modName, err := builder.GetModuleName() if err != nil { return err } + instance.Module.Name = modName - log.Info(fmt.Sprintf("using module %s version %s", mod.Name, mod.Version)) - + log.Info(fmt.Sprintf("applying module %s version %s", + colorizeSubject(instance.Module.Name), colorizeSubject(instance.Module.Version))) err = builder.WriteValuesFileWithDefaults(instance.Values) if err != nil { return err } - builder.SetVersionInfo(mod.Version, kubeVersion) + builder.SetVersionInfo(instance.Module.Version, kubeVersion) buildResult, err := builder.Build() if err != nil { - return describeErr(fetcher.GetModuleRoot(), "failed to build instance", err) + return describeErr(modDir, "failed to build instance", err) } finalValues, err := builder.GetValues(buildResult) @@ -299,7 +319,7 @@ return fmt.Errorf("instance init failed: %w", err) } - im := runtime.NewInstanceManager(instance.Name, instance.Namespace, finalValues, *mod) + im := runtime.NewInstanceManager(instance.Name, instance.Namespace, finalValues, instance.Module) if im.Instance.Labels == nil { im.Instance.Labels = make(map[string]string) @@ -317,28 +337,39 @@ if bundleApplyArgs.dryrun || bundleApplyArgs.diff { if !nsExists { - log.Info(colorizeJoin(colorizeNamespaceFromArgs(), ssa.CreatedAction, dryRunServer)) + log.Info(colorizeJoin(colorizeSubject("Namespace/"+instance.Namespace), + ssa.CreatedAction, dryRunServer)) } - if err := instanceDryRunDiff(logr.NewContext(ctx, log), rm, objects, staleObjects, nsExists, tmpDir, bundleApplyArgs.diff); err != nil { + if err := instanceDryRunDiff( + logr.NewContext(ctx, log), + rm, + objects, + staleObjects, + nsExists, + rootDir, + bundleApplyArgs.diff, + ); err != nil { return err } - log.Info("applied successfully (server dry run)") + log.Info(colorizeJoin("applied successfully", colorizeDryRun("(server dry run)"))) return nil } if !exists { - log.Info(fmt.Sprintf("installing %s in namespace %s", instance.Name, instance.Namespace)) + log.Info(fmt.Sprintf("installing %s in namespace %s", + colorizeSubject(instance.Name), colorizeSubject(instance.Namespace))) if err := sm.Apply(ctx, &im.Instance, true); err != nil { return fmt.Errorf("instance init failed: %w", err) } if !nsExists { - log.Info(colorizeJoin(colorizeNamespaceFromArgs(), ssa.CreatedAction)) + log.Info(colorizeJoin(colorizeSubject("Namespace/"+instance.Namespace), ssa.CreatedAction)) } } else { - log.Info(fmt.Sprintf("upgrading %s in namespace %s", instance.Name, instance.Namespace)) + log.Info(fmt.Sprintf("upgrading %s in namespace %s", + colorizeSubject(instance.Name), colorizeSubject(instance.Namespace))) } applyOpts := runtime.ApplyOptions(bundleApplyArgs.force, rootArgs.timeout) @@ -407,7 +438,7 @@ return nil } -func bundleInstancesOwnershipConflicts(bundleInstances []engine.BundleInstance) error { +func bundleInstancesOwnershipConflicts(bundleInstances []*engine.BundleInstance) error { var conflicts []string rm, err := runtime.NewResourceManager(kubeconfigArgs) if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/cmd/timoni/bundle_apply_test.go new/timoni-0.14.2/cmd/timoni/bundle_apply_test.go --- old/timoni-0.14.1/cmd/timoni/bundle_apply_test.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/cmd/timoni/bundle_apply_test.go 2023-10-08 17:02:46.000000000 +0200 @@ -304,7 +304,6 @@ output, err := executeCommandWithIn("bundle apply -f - -p main --wait", r) g.Expect(err).ToNot(HaveOccurred()) g.Expect(output).To(ContainSubstring(modVer1)) - g.Expect(output).To(ContainSubstring(modDigestv1)) }) t.Run("creates instance for module version digest", func(t *testing.T) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/cmd/timoni/bundle_build.go new/timoni-0.14.2/cmd/timoni/bundle_build.go --- old/timoni-0.14.1/cmd/timoni/bundle_build.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/cmd/timoni/bundle_build.go 2023-10-08 17:02:46.000000000 +0200 @@ -21,9 +21,11 @@ "fmt" "maps" "os" + "path" "sort" "strings" + "cuelang.org/go/cue" "cuelang.org/go/cue/cuecontext" "github.com/fluxcd/pkg/ssa" "github.com/spf13/cobra" @@ -142,12 +144,21 @@ var sb strings.Builder + ctxPull, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) + defer cancel() + + for _, instance := range bundle.Instances { + if err := fetchBundleInstanceModule(ctxPull, instance, tmpDir); err != nil { + return err + } + } + for i, instance := range bundle.Instances { sb.WriteString("---\n") sb.WriteString(fmt.Sprintf("# Instance: %s\n", instance.Name)) sb.WriteString("---\n") - instance, err := buildBundleInstance(instance) + instance, err := buildBundleInstance(ctx, instance, tmpDir) if err != nil { return err } @@ -163,45 +174,14 @@ return nil } -func buildBundleInstance(instance engine.BundleInstance) (string, error) { - moduleVersion := instance.Module.Version - - if moduleVersion == apiv1.LatestVersion && instance.Module.Digest != "" { - moduleVersion = "@" + instance.Module.Digest - } - - tmpDir, err := os.MkdirTemp("", apiv1.FieldManager) - if err != nil { - return "", err - } - defer os.RemoveAll(tmpDir) - - ctxPull, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) - defer cancel() +func buildBundleInstance(cuectx *cue.Context, instance *engine.BundleInstance, rootDir string) (string, error) { + modDir := path.Join(rootDir, instance.Name, "module") - fetcher := engine.NewFetcher( - ctxPull, - instance.Module.Repository, - moduleVersion, - tmpDir, - bundleBuildArgs.creds.String(), - ) - mod, err := fetcher.Fetch() - if err != nil { - return "", err - } - - if instance.Module.Digest != "" && mod.Digest != instance.Module.Digest { - return "", fmt.Errorf("the upstream digest %s of version %s doesn't match the specified digest %s", - mod.Digest, instance.Module.Version, instance.Module.Digest) - } - - cuectx := cuecontext.New() builder := engine.NewModuleBuilder( cuectx, instance.Name, instance.Namespace, - fetcher.GetModuleRoot(), + modDir, bundleBuildArgs.pkg.String(), ) @@ -209,19 +189,22 @@ return "", err } - mod.Name, err = builder.GetModuleName() + modName, err := builder.GetModuleName() if err != nil { return "", err } + instance.Module.Name = modName err = builder.WriteValuesFileWithDefaults(instance.Values) if err != nil { return "", err } + builder.SetVersionInfo(instance.Module.Version, "") + buildResult, err := builder.Build() if err != nil { - return "", describeErr(fetcher.GetModuleRoot(), "failed to build instance", err) + return "", describeErr(modDir, "failed to build instance", err) } bundleBuildSets, err := builder.GetApplySets(buildResult) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/cmd/timoni/bundle_delete.go new/timoni-0.14.2/cmd/timoni/bundle_delete.go --- old/timoni-0.14.1/cmd/timoni/bundle_delete.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/cmd/timoni/bundle_delete.go 2023-10-08 17:02:46.000000000 +0200 @@ -102,9 +102,15 @@ return err } - for _, instance := range instances { + if len(instances) == 0 { + return fmt.Errorf("no instances found in bundle") + } + + // delete in revers order (last installed, first to uninstall) + for index := len(instances) - 1; index >= 0; index-- { + instance := instances[index] log.Info(fmt.Sprintf("deleting instance %s from bundle %s", instance.Name, bundleDelArgs.name)) - if err := deleteBundleInstance(ctx, engine.BundleInstance{ + if err := deleteBundleInstance(ctx, &engine.BundleInstance{ Bundle: bundle, Name: instance.Name, Namespace: instance.Namespace, @@ -159,7 +165,8 @@ return fmt.Errorf("no instances found in bundle") } - for _, instance := range bundle.Instances { + for index := len(bundle.Instances) - 1; index >= 0; index-- { + instance := bundle.Instances[index] log.Info(fmt.Sprintf("deleting instance %s", instance.Name)) if err := deleteBundleInstance(ctx, instance, bundleDelArgs.wait, bundleDelArgs.dryrun); err != nil { return err @@ -169,7 +176,7 @@ return nil } -func deleteBundleInstance(ctx context.Context, instance engine.BundleInstance, wait bool, dryrun bool) error { +func deleteBundleInstance(ctx context.Context, instance *engine.BundleInstance, wait bool, dryrun bool) error { log := LoggerBundle(ctx, instance.Bundle) sm, err := runtime.NewResourceManager(kubeconfigArgs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/cmd/timoni/list.go new/timoni-0.14.2/cmd/timoni/list.go --- old/timoni-0.14.1/cmd/timoni/list.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/cmd/timoni/list.go 2023-10-08 17:02:46.000000000 +0200 @@ -19,6 +19,7 @@ import ( "context" "io" + "sort" apiv1 "github.com/stefanprodan/timoni/api/v1alpha1" @@ -66,6 +67,11 @@ return err } + // alphabetical sort by instance name + sort.Slice(instances, func(i, j int) bool { + return instances[i].Name < instances[j].Name + }) + var rows [][]string for _, inv := range instances { row := []string{} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/cmd/timoni/mod_pull.go new/timoni-0.14.2/cmd/timoni/mod_pull.go --- old/timoni-0.14.1/cmd/timoni/mod_pull.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/cmd/timoni/mod_pull.go 2023-10-08 17:02:46.000000000 +0200 @@ -137,19 +137,17 @@ } } - spin := StartSpinner("pulling module") - defer spin.Stop() - ctx, cancel := context.WithTimeout(context.Background(), rootArgs.timeout) defer cancel() + spin := StartSpinner(fmt.Sprintf("pulling %s", ociURL)) opts := oci.Options(ctx, pullModArgs.creds.String()) err := oci.PullArtifact(ociURL, pullModArgs.output, apiv1.AnyContentType, opts) + spin.Stop() if err != nil { return err } - spin.Stop() log.Info(fmt.Sprintf("extracted: %s", colorizeSubject(pullModArgs.output))) return nil diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/cmd/timoni/mod_push.go new/timoni-0.14.2/cmd/timoni/mod_push.go --- old/timoni-0.14.1/cmd/timoni/mod_push.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/cmd/timoni/mod_push.go 2023-10-08 17:02:46.000000000 +0200 @@ -201,6 +201,7 @@ if err != nil { return err } + log.Info(fmt.Sprintf("artifact: %s", colorizeSubject(ociURL))) log.Info(fmt.Sprintf("digest: %s", colorizeSubject(digest.DigestStr()))) } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/internal/engine/bundle_builder.go new/timoni-0.14.2/internal/engine/bundle_builder.go --- old/timoni-0.14.1/internal/engine/bundle_builder.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/internal/engine/bundle_builder.go 2023-10-08 17:02:46.000000000 +0200 @@ -41,7 +41,7 @@ type Bundle struct { Name string - Instances []BundleInstance + Instances []*BundleInstance } type BundleInstance struct { @@ -165,7 +165,7 @@ return nil, fmt.Errorf("lookup %s failed: %w", apiv1.BundleInstancesSelector.String(), instances.Err()) } - var list []BundleInstance + var list []*BundleInstance iter, err := instances.Fields(cue.Concrete(true)) if err != nil { return nil, err @@ -189,7 +189,7 @@ values := expr.LookupPath(cue.ParsePath(apiv1.BundleValuesSelector.String())) - list = append(list, BundleInstance{ + list = append(list, &BundleInstance{ Bundle: bundleName, Name: name, Namespace: namespace, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/timoni-0.14.1/internal/runtime/storage.go new/timoni-0.14.2/internal/runtime/storage.go --- old/timoni-0.14.1/internal/runtime/storage.go 2023-10-06 17:53:11.000000000 +0200 +++ new/timoni-0.14.2/internal/runtime/storage.go 2023-10-08 17:02:46.000000000 +0200 @@ -19,6 +19,7 @@ import ( "context" "fmt" + "sort" "strings" "time" @@ -110,29 +111,40 @@ // List returns the instances found in the given namespace. func (s *StorageManager) List(ctx context.Context, namespace, bundle string) ([]*apiv1.Instance, error) { var res []*apiv1.Instance - cmList := &corev1.SecretList{} + instanceList := &corev1.SecretList{} labels := s.getOwnerLabels() if bundle != "" { labels[apiv1.BundleNameLabelKey] = bundle } - err := s.resManager.Client().List(ctx, cmList, client.InNamespace(namespace), labels) + err := s.resManager.Client().List(ctx, instanceList, client.InNamespace(namespace), labels) if err != nil { return res, err } - for _, cm := range cmList.Items { - if _, ok := cm.Data[storageDataKey]; !ok { + if len(instanceList.Items) == 0 { + return res, nil + } + + var instances = instanceList.Items + + // order list by installed date + sort.Slice(instances, func(i, j int) bool { + return instances[i].CreationTimestamp.Before(&instances[j].CreationTimestamp) + }) + + for _, instance := range instances { + if _, ok := instance.Data[storageDataKey]; !ok { return res, fmt.Errorf("instance data not found in Secret/%s/%s", - cm.GetNamespace(), cm.GetName()) + instance.GetNamespace(), instance.GetName()) } var inst apiv1.Instance - err = json.Unmarshal(cm.Data[storageDataKey], &inst) + err = json.Unmarshal(instance.Data[storageDataKey], &inst) if err != nil { return res, fmt.Errorf("invalid instance found in Secret/%s/%s: %w", - cm.GetNamespace(), cm.GetName(), err) + instance.GetNamespace(), instance.GetName(), err) } - inst.Labels = cm.Labels + inst.Labels = instance.Labels res = append(res, &inst) } ++++++ timoni.obsinfo ++++++ --- /var/tmp/diff_new_pack.3r8tg7/_old 2023-10-10 20:59:09.999615956 +0200 +++ /var/tmp/diff_new_pack.3r8tg7/_new 2023-10-10 20:59:10.003616101 +0200 @@ -1,5 +1,5 @@ name: timoni -version: 0.14.1 -mtime: 1696607591 -commit: f68b7c3560cecfd4e1ade1eb14b53b226bcd54c9 +version: 0.14.2 +mtime: 1696777366 +commit: a5f6a97af9c0ea269b1502e18e3ff43617a06ea6 ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/timoni/vendor.tar.gz /work/SRC/openSUSE:Factory/.timoni.new.28202/vendor.tar.gz differ: char 5, line 1