Repository: knative/client (go)

Issue:
Add `--scale-activation` flag to match new Serving option
<!-- If you need to report a security issue with Knative, send an email to knative-security@googlegroups.com. -->

### Feature request

Consider adding a new Ksvc flag to specify activation scale value. That represents number of replicas to be scaled from zero when service is activated.

Ref: https://github.com/knative/serving/pull/13161 (note it's an update PR to introduce new & current name of option)
https://github.com/knative/serving/pull/13136 (first PR with former name)

### UI Example



```
kn service create hello --image .../myapp --scale-activation 2
```

/kind good-first-issue

/cc @dprotaso @psschwei 
<!--
Optional Classifications, remove the '> ' to select:
> /kind good-first-issue
> /kind proposal
> /kind doc
> /kind cleanup
-->


Pull request description:
Add --scale-activation flag to match new Serving option
## Description
Add --scale-activation flag to match new Serving option
<!-- Please add a short summary about what the pull request is going to bring on the table -->

## Changes

<!-- Please add list of more detailed changes. These changes should be reflected also in the commit messages -->

* Added the flag
* Added unit and e2e tests

## Reference

<!-- Please add the corresponding issue number which this pull request is about to fix -->
Fixes #1713 

**Release Note**

<!-- Enter your extended release note in the below block. If the PR requires
additional action from users switching to the new release, include the string
"action required". If no release note is required, write "NONE". -->

```release-note
Add `--scale-activation` flag to `service create` command options
```

<!--
Please add an entry to CHANGELOG.adoc file, too, as part of your Pull Request.

In the following cases, add a short description of PR to the unreleased section in CHANGELOG.adoc:

- 🎁 New feature
- 🐛 Bug fix
- ✨ Feature Update
- 🐣 Refactoring
- 🗑️ Remove feature or internal logic

See other entries in CHANGELOG.adoc as an example for how to add the entry, including a reference to the corresponding issue/PR

PLEASE DON'T ADD THAT LINE HERE IN THE PULL-REQUEST DESCRIPTION BUT DIRECTLY IN CHANGELOG.ADOC AND ADD CHANGELOG.ADOC AS PART OF YOUR PULL-REQUEST.
-->

<!--
To automatically lint go code in this pull request uncomment the line below. You get feedback as comments on your pull request then -->

<!--
/lint
-->


Patch:
diff --git a/docs/cmd/kn_service_apply.md b/docs/cmd/kn_service_apply.md
index 04448c46..fa816735 100644
--- a/docs/cmd/kn_service_apply.md
+++ b/docs/cmd/kn_service_apply.md
@@ -65,6 +65,7 @@ kn service apply s0 --filename my-svc.yml
       --request strings                   The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
       --revision-name string              The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants (e.g. {{.Service}}-{{.Random 5}}-{{.Generation}})
       --scale string                      Set the Minimum and Maximum number of replicas. You can use this flag to set both to a single value, or set a range with min/max values, or set either min or max values without specifying the other. Example: --scale 5 (scale-min = 5, scale-max = 5) or --scale 1..5 (scale-min = 1, scale-max = 5) or --scale 1.. (scale-min = 1, scale-max = unchanged) or --scale ..5 (scale-min = unchanged, scale-max = 5)
+      --scale-activation int              Minimum non-zero value that a service should scale to.
       --scale-init int                    Initial number of replicas with which a service starts. Can be 0 or a positive integer.
       --scale-max int                     Maximum number of replicas.
       --scale-metric string               Set the name of the metric the PodAutoscaler should scale on. Example: --scale-metric rps (to scale on rps) or --scale-metric concurrency (to scale on concurrency). The default metric is concurrency.
diff --git a/docs/cmd/kn_service_create.md b/docs/cmd/kn_service_create.md
index 3133ec40..0221644d 100644
--- a/docs/cmd/kn_service_create.md
+++ b/docs/cmd/kn_service_create.md
@@ -90,6 +90,7 @@ kn service create NAME --image IMAGE
       --request strings                   The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
       --revision-name string              The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants (e.g. {{.Service}}-{{.Random 5}}-{{.Generation}})
       --scale string                      Set the Minimum and Maximum number of replicas. You can use this flag to set both to a single value, or set a range with min/max values, or set either min or max values without specifying the other. Example: --scale 5 (scale-min = 5, scale-max = 5) or --scale 1..5 (scale-min = 1, scale-max = 5) or --scale 1.. (scale-min = 1, scale-max = unchanged) or --scale ..5 (scale-min = unchanged, scale-max = 5)
+      --scale-activation int              Minimum non-zero value that a service should scale to.
       --scale-init int                    Initial number of replicas with which a service starts. Can be 0 or a positive integer.
       --scale-max int                     Maximum number of replicas.
       --scale-metric string               Set the name of the metric the PodAutoscaler should scale on. Example: --scale-metric rps (to scale on rps) or --scale-metric concurrency (to scale on concurrency). The default metric is concurrency.
diff --git a/docs/cmd/kn_service_update.md b/docs/cmd/kn_service_update.md
index 42295def..89280731 100644
--- a/docs/cmd/kn_service_update.md
+++ b/docs/cmd/kn_service_update.md
@@ -77,6 +77,7 @@ kn service update NAME
       --request strings                   The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
       --revision-name string              The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants (e.g. {{.Service}}-{{.Random 5}}-{{.Generation}})
       --scale string                      Set the Minimum and Maximum number of replicas. You can use this flag to set both to a single value, or set a range with min/max values, or set either min or max values without specifying the other. Example: --scale 5 (scale-min = 5, scale-max = 5) or --scale 1..5 (scale-min = 1, scale-max = 5) or --scale 1.. (scale-min = 1, scale-max = unchanged) or --scale ..5 (scale-min = unchanged, scale-max = 5)
+      --scale-activation int              Minimum non-zero value that a service should scale to.
       --scale-init int                    Initial number of replicas with which a service starts. Can be 0 or a positive integer.
       --scale-max int                     Maximum number of replicas.
       --scale-metric string               Set the name of the metric the PodAutoscaler should scale on. Example: --scale-metric rps (to scale on rps) or --scale-metric concurrency (to scale on concurrency). The default metric is concurrency.
diff --git a/pkg/kn/commands/service/configuration_edit_flags.go b/pkg/kn/commands/service/configuration_edit_flags.go
index b2dcbcba..17c9798a 100644
--- a/pkg/kn/commands/service/configuration_edit_flags.go
+++ b/pkg/kn/commands/service/configuration_edit_flags.go
@@ -41,6 +41,7 @@ type ConfigurationEditFlags struct {
 	Scale               string
 	MinScale            int
 	MaxScale            int
+	ScaleActivation     int
 	ScaleTarget         int
 	ScaleMetric         string
 	ConcurrencyLimit    int
@@ -94,6 +95,9 @@ func (p *ConfigurationEditFlags) addSharedFlags(command *cobra.Command) {
 	command.Flags().IntVar(&p.MaxScale, "scale-max", 0, "Maximum number of replicas.")
 	p.markFlagMakesRevision("scale-max")
 
+	command.Flags().IntVar(&p.ScaleActivation, "scale-activation", 0, "Minimum non-zero value that a service should scale to.")
+	p.markFlagMakesRevision("scale-activation")
+
 	command.Flags().StringVar(&p.ScaleMetric, "scale-metric", "", "Set the name of the metric the PodAutoscaler should scale on. "+
 		"Example: --scale-metric rps (to scale on rps) or --scale-metric concurrency (to scale on concurrency). The default metric is concurrency.")
 	p.markFlagMakesRevision("scale-metric")
@@ -358,6 +362,10 @@ func (p *ConfigurationEditFlags) Apply(
 		servinglib.UpdateScaleMetric(template, p.ScaleMetric)
 	}
 
+	if cmd.Flags().Changed("scale-activation") {
+		servinglib.UpdateScaleActivation(template, p.ScaleActivation)
+	}
+
 	if cmd.Flags().Changed("concurrency-limit") {
 		err = servinglib.UpdateConcurrencyLimit(template, int64(p.ConcurrencyLimit))
 		if err != nil {
diff --git a/pkg/serving/config_changes.go b/pkg/serving/config_changes.go
index 56847797..6e7b9a7b 100644
--- a/pkg/serving/config_changes.go
+++ b/pkg/serving/config_changes.go
@@ -77,6 +77,11 @@ func UpdateScaleTarget(template *servingv1.RevisionTemplateSpec, target int) err
 	return UpdateRevisionTemplateAnnotation(template, autoscaling.TargetAnnotationKey, strconv.Itoa(target))
 }
 
+//UpdateScaleActivation updates the scale activation annotation
+func UpdateScaleActivation(template *servingv1.RevisionTemplateSpec, activation int) error {
+	return UpdateRevisionTemplateAnnotation(template, autoscaling.ActivationScaleKey, strconv.Itoa(activation))
+}
+
 // UpdateScaleUtilization updates container target utilization percentage annotation
 func UpdateScaleUtilization(template *servingv1.RevisionTemplateSpec, target int) error {
 	return UpdateRevisionTemplateAnnotation(template, autoscaling.TargetUtilizationPercentageKey, strconv.Itoa(target))


Test patch:
diff --git a/pkg/kn/commands/service/configuration_edit_flags_test.go b/pkg/kn/commands/service/configuration_edit_flags_test.go
index e5596656..853407e8 100644
--- a/pkg/kn/commands/service/configuration_edit_flags_test.go
+++ b/pkg/kn/commands/service/configuration_edit_flags_test.go
@@ -20,6 +20,7 @@ import (
 	"gotest.tools/v3/assert"
 	"knative.dev/client/pkg/kn/commands"
 	"knative.dev/client/pkg/util"
+	"knative.dev/serving/pkg/apis/autoscaling"
 )
 
 func TestApplyPullPolicyFlag(t *testing.T) {
@@ -60,3 +61,17 @@ func TestScaleMetric(t *testing.T) {
 	err := editFlags.Apply(&svc, nil, cmd)
 	assert.NilError(t, err)
 }
+
+func TestScaleActivation(t *testing.T) {
+	var editFlags ConfigurationEditFlags
+	knParams := &commands.KnParams{}
+	cmd, _, _ := commands.CreateTestKnCommand(NewServiceCreateCommand(knParams), knParams)
+
+	editFlags.AddCreateFlags(cmd)
+	svc := createTestService("test-svc", []string{"test-svc-00001"}, goodConditions())
+	cmd.SetArgs([]string{"--scale-activation", "2"})
+	cmd.Execute()
+	err := editFlags.Apply(&svc, nil, cmd)
+	assert.NilError(t, err)
+	assert.Equal(t, svc.Spec.Template.Annotations[autoscaling.ActivationScaleKey], "2")
+}
diff --git a/test/e2e/service_options_test.go b/test/e2e/service_options_test.go
index ab11b01c..ce1962c4 100644
--- a/test/e2e/service_options_test.go
+++ b/test/e2e/service_options_test.go
@@ -231,6 +231,10 @@ func TestServiceOptions(t *testing.T) {
 	test.ServiceDelete(r, "svc17")
 	_, err = kubectl.Run("delete", "-n", it.Namespace(), "configmap", "test-cm2")
 	assert.NilError(t, err)
+
+	t.Log("create and validate a service with scale activation")
+	serviceCreateWithOptions(r, "svc18", "--scale-activation", "2")
+	validateServiceActivation(r, "svc18", 2)
 }
 
 func serviceCreateWithOptions(r *test.KnRunResultCollector, serviceName string, options ...string) {
@@ -384,3 +388,12 @@ func validateServiceEnvVariables(r *test.KnRunResultCollector, serviceName strin
 		}
 	}
 }
+
+func validateServiceActivation(r *test.KnRunResultCollector, serviceName string, activation int) {
+	out := r.KnTest().Kn().Run("service", "describe", serviceName, "-o", "json")
+	r.AssertNoError(out)
+	var svc servingv1.Service
+	json.Unmarshal([]byte(out.Stdout), &svc)
+	activationStr := strconv.Itoa(activation)
+	assert.Check(r.T(), svc.Spec.Template.Annotations[autoscaling.ActivationScaleKey] == activationStr)
+}