Repository: GoogleContainerTools/kpt
Pull request #3745 (2023-01-23 21:46:46)

add command for deletion proposal of porch package revisions
The CLI counterpart of https://github.com/GoogleContainerTools/kpt/pull/3678 - adds a command `kpt alpha rpkg propose-delete` to propose deletion of published package revisions.


Patch:
diff --git a/commands/alpha/rpkg/proposedelete/command.go b/commands/alpha/rpkg/proposedelete/command.go
new file mode 100644
index 00000000..b685bb58
--- /dev/null
+++ b/commands/alpha/rpkg/proposedelete/command.go
@@ -0,0 +1,117 @@
+// Copyright 2022 Google LLC
+//
+// 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 proposedelete
+
+import (
+	"context"
+	"fmt"
+	"strings"
+
+	"github.com/GoogleContainerTools/kpt/internal/errors"
+	"github.com/GoogleContainerTools/kpt/internal/util/porch"
+	"github.com/GoogleContainerTools/kpt/porch/api/porch/v1alpha1"
+	"github.com/spf13/cobra"
+	"k8s.io/cli-runtime/pkg/genericclioptions"
+	"sigs.k8s.io/controller-runtime/pkg/client"
+)
+
+const (
+	command = "cmdrpkgpropose-delete"
+)
+
+func newRunner(ctx context.Context, rcg *genericclioptions.ConfigFlags) *runner {
+	r := &runner{
+		ctx: ctx,
+		cfg: rcg,
+	}
+	c := &cobra.Command{
+		Use:        "propose-delete PACKAGE",
+		Aliases:    []string{"propose-del"},
+		SuggestFor: []string{},
+		PreRunE:    r.preRunE,
+		RunE:       r.runE,
+		Hidden:     porch.HidePorchCommands,
+	}
+	r.Command = c
+
+	// Create flags
+
+	return r
+}
+
+func NewCommand(ctx context.Context, rcg *genericclioptions.ConfigFlags) *cobra.Command {
+	return newRunner(ctx, rcg).Command
+}
+
+type runner struct {
+	ctx     context.Context
+	cfg     *genericclioptions.ConfigFlags
+	client  client.Client
+	Command *cobra.Command
+}
+
+func (r *runner) preRunE(cmd *cobra.Command, args []string) error {
+	const op errors.Op = command + ".preRunE"
+
+	client, err := porch.CreateClientWithFlags(r.cfg)
+	if err != nil {
+		return errors.E(op, err)
+	}
+	r.client = client
+	return nil
+}
+
+func (r *runner) runE(_ *cobra.Command, args []string) error {
+	const op errors.Op = command + ".runE"
+	var messages []string
+	namespace := *r.cfg.Namespace
+
+	for _, name := range args {
+		pr := &v1alpha1.PackageRevision{}
+		if err := r.client.Get(r.ctx, client.ObjectKey{
+			Namespace: namespace,
+			Name:      name,
+		}, pr); err != nil {
+			return errors.E(op, err)
+		}
+
+		switch pr.Spec.Lifecycle {
+		case v1alpha1.PackageRevisionLifecyclePublished:
+			// ok
+		case v1alpha1.PackageRevisionLifecycleDeletionProposed:
+			fmt.Fprintf(r.Command.OutOrStderr(), "%s is already proposed for deletion\n", name)
+			continue
+		default:
+			msg := fmt.Sprintf("can only propose published packages for deletion; package %s is not published", name)
+			messages = append(messages, msg)
+			fmt.Fprintln(r.Command.ErrOrStderr(), msg)
+			continue
+		}
+
+		pr.Spec.Lifecycle = v1alpha1.PackageRevisionLifecycleDeletionProposed
+		if err := r.client.Update(r.ctx, pr); err != nil {
+			messages = append(messages, err.Error())
+			fmt.Fprintf(r.Command.ErrOrStderr(), "%s failed (%s)\n", name, err)
+		} else {
+			fmt.Fprintf(r.Command.OutOrStderr(), "%s proposed for deletion\n", name)
+		}
+	}
+
+	if len(messages) > 0 {
+		return errors.E(op, fmt.Errorf("errors:\n  %s", strings.Join(messages, "\n  ")))
+	}
+
+	return nil
+}
diff --git a/commands/alpha/rpkg/rpkgcmd.go b/commands/alpha/rpkg/rpkgcmd.go
index 72006bec..c379448d 100644
--- a/commands/alpha/rpkg/rpkgcmd.go
+++ b/commands/alpha/rpkg/rpkgcmd.go
@@ -26,6 +26,7 @@ import (
 	"github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/get"
 	initialization "github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/init"
 	"github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/propose"
+	"github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/proposedelete"
 	"github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/pull"
 	"github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/push"
 	"github.com/GoogleContainerTools/kpt/commands/alpha/rpkg/reject"
@@ -80,6 +81,7 @@ func NewCommand(ctx context.Context, version string) *cobra.Command {
 		del.NewCommand(ctx, kubeflags),
 		copy.NewCommand(ctx, kubeflags),
 		update.NewCommand(ctx, kubeflags),
+		proposedelete.NewCommand(ctx, kubeflags),
 	)
 
 	return repo
diff --git a/commands/alpha/rpkg/update/discover.go b/commands/alpha/rpkg/update/discover.go
index c8cc4577..1c3519f5 100644
--- a/commands/alpha/rpkg/update/discover.go
+++ b/commands/alpha/rpkg/update/discover.go
@@ -163,7 +163,7 @@ func (r *runner) getRepositories() (*configapi.RepositoryList, error) {
 func (r *runner) getUpstreamRevisions(repo configapi.Repository, upstreamPackageName string) []porchapi.PackageRevision {
 	var result []porchapi.PackageRevision
 	for _, pkgRev := range r.prs {
-		if pkgRev.Spec.Lifecycle != porchapi.PackageRevisionLifecyclePublished {
+		if !porchapi.LifecycleIsPublished(pkgRev.Spec.Lifecycle) {
 			// only consider published packages
 			continue
 		}
diff --git a/go.mod b/go.mod
index a0de9fef..1180a028 100644
--- a/go.mod
+++ b/go.mod
@@ -3,7 +3,7 @@ module github.com/GoogleContainerTools/kpt
 go 1.18
 
 require (
-	github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221028161857-aa271f292cc0
+	github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230121152246-dc44dbd18a33
 	github.com/bytecodealliance/wasmtime-go v0.39.0
 	github.com/cpuguy83/go-md2man/v2 v2.0.2
 	github.com/go-errors/errors v1.4.2
diff --git a/go.sum b/go.sum
index d9f8d74e..ba8bfc72 100644
--- a/go.sum
+++ b/go.sum
@@ -87,8 +87,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
 github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Djarvur/go-err113 v0.0.0-20210108212216-aea10b59be24/go.mod h1:4UJr5HIiMZrwgkSPdsjy2uOQExX/WEILpIrO9UPGuXs=
-github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221028161857-aa271f292cc0 h1:Nay/s1StXHUKyIxerpXb8o0hZUkRjrbteLO6ardI26Y=
-github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221028161857-aa271f292cc0/go.mod h1:ASrhnLAL4ahTuiUJyepqcpVRXIoRMJyDs8/eSxwhgZM=
+github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230121152246-dc44dbd18a33 h1:9M1bvq7hU/JTY4VVcqhCQT0eAa5HznrFaLAm2ldfe70=
+github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230121152246-dc44dbd18a33/go.mod h1:ASrhnLAL4ahTuiUJyepqcpVRXIoRMJyDs8/eSxwhgZM=
 github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
 github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
 github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
diff --git a/porch/go.mod b/porch/go.mod
index 435c0b5e..e89f34b9 100644
--- a/porch/go.mod
+++ b/porch/go.mod
@@ -17,7 +17,7 @@ require (
 	github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/set-namespace v0.4.1
 	github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/starlark v0.4.3
 	github.com/GoogleContainerTools/kpt-functions-sdk/go/fn v0.0.0-20220506190241-f85503febd54
-	github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20221028161857-aa271f292cc0
+	github.com/GoogleContainerTools/kpt/porch/api v0.0.0-20230121152246-dc44dbd18a33
 	github.com/bluekeyes/go-gitdiff v0.6.1
 	github.com/go-git/go-billy/v5 v5.3.1
 	github.com/go-git/go-git/v5 v5.4.3-0.20220408232334-4f916225cb2f


Test patch:
diff --git a/e2e/testdata/porch/rpkg-lifecycle/config.yaml b/e2e/testdata/porch/rpkg-lifecycle/config.yaml
index f7f47796..46c18fd8 100644
--- a/e2e/testdata/porch/rpkg-lifecycle/config.yaml
+++ b/e2e/testdata/porch/rpkg-lifecycle/config.yaml
@@ -23,6 +23,17 @@ commands:
       - git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034
     stderr: |
       git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034 proposed
+  - args:
+      - alpha
+      - rpkg
+      - propose-delete
+      - git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034
+      - --namespace=rpkg-lifecycle
+    exitCode: 1
+    stderr: |
+      can only propose published packages for deletion; package git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034 is not published
+      Error: errors:
+        can only propose published packages for deletion; package git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034 is not published 
   - args:
       - alpha
       - rpkg
@@ -50,6 +61,17 @@ commands:
     stdout: |
       NAME                                           PACKAGE             WORKSPACENAME   REVISION   LATEST   LIFECYCLE   REPOSITORY
       git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034   lifecycle-package   lifecycle                  false    Draft       git
+  - args:
+      - alpha
+      - rpkg
+      - propose-delete
+      - git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034
+      - --namespace=rpkg-lifecycle
+    exitCode: 1
+    stderr: |
+      can only propose published packages for deletion; package git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034 is not published
+      Error: errors:
+        can only propose published packages for deletion; package git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034 is not published 
   - args:
       - alpha
       - rpkg
@@ -95,3 +117,44 @@ commands:
       git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034 failed (admission webhook "packagerevdeletion.google.com" denied the request: failed to delete package revision "git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034": published PackageRevisions must be proposed for deletion by setting spec.lifecycle to 'DeletionProposed' prior to deletion)
       Error: errors:
         admission webhook "packagerevdeletion.google.com" denied the request: failed to delete package revision "git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034": published PackageRevisions must be proposed for deletion by setting spec.lifecycle to 'DeletionProposed' prior to deletion 
+  - args:
+      - alpha
+      - rpkg
+      - propose-delete
+      - git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034
+      - --namespace=rpkg-lifecycle
+    stderr: |
+      git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034 proposed for deletion
+  - args:
+      - alpha
+      - rpkg
+      - propose-delete
+      - git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034
+      - --namespace=rpkg-lifecycle
+    stderr: |
+      git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034 is already proposed for deletion
+  - args:
+      - alpha
+      - rpkg
+      - get
+      - git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034
+      - --namespace=rpkg-lifecycle
+    stdout: |
+      NAME                                           PACKAGE             WORKSPACENAME   REVISION   LATEST   LIFECYCLE          REPOSITORY
+      git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034   lifecycle-package   lifecycle       v1         true     DeletionProposed   git
+  - args:
+      - alpha
+      - rpkg
+      - delete
+      - git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034
+      - --namespace=rpkg-lifecycle
+    stderr: |
+      git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034 deleted
+  - args:
+      - alpha
+      - rpkg
+      - get
+      - git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034
+      - --namespace=rpkg-lifecycle
+    stderr: "Error: the server could not find the requested resource (get packagerevisions.porch.kpt.dev git-017a8366a5e0d9b35ae6dc489d4d3f68046d6034) \n"
+    exitCode: 1