Repository: knative-sandbox/kn-plugin-func
Pull request #651 (2021-11-11 14:32:26)

feat: function creation timestamp
<!-- Thanks for sending a pull request! -->

# Changes

- :gift: function creation timestamp

It is becoming clear that a timestamp of when a Function successfully completed the creation process will be valuable.  In particular this will help with a few forthcoming PRs currently WIP, I'm separating this into its own PR to solicit feedback such as consequences unanticipated.

knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative-sandbox/kn-plugin-func/pull/651#" title="Author self-approved">lkingland</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative-sandbox%2Fkn-plugin-func).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/knative-sandbox/kn-plugin-func/blob/main/OWNERS)~~ [lkingland]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->
codecov[bot]: # [Codecov](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) Report
> Merging [#651](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) (1ed925b) into [main](https://codecov.io/gh/knative-sandbox/kn-plugin-func/commit/fc1e874a5d2e61025cd6e032318a0a22a638343c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) (fc1e874) will **increase** coverage by `0.04%`.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651/graphs/tree.svg?width=650&height=150&src=pr&token=da1B9bMsQ9&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox)](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox)

```diff
@@            Coverage Diff             @@
##             main     #651      +/-   ##
==========================================
+ Coverage   36.26%   36.31%   +0.04%     
==========================================
  Files          38       38              
  Lines        3847     3850       +3     
==========================================
+ Hits         1395     1398       +3     
  Misses       2268     2268              
  Partials      184      184              
```


| [Impacted Files](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox) | Coverage Δ | |
|---|---|---|
| [function.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-ZnVuY3Rpb24uZ28=) | `57.57% <ø> (ø)` | |
| [client.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y2xpZW50Lmdv) | `60.53% <100.00%> (+0.17%)` | :arrow_up: |
| [config.go](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox#diff-Y29uZmlnLmdv) | `62.13% <100.00%> (+0.31%)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox). Last update [fc1e874...1ed925b](https://codecov.io/gh/knative-sandbox/kn-plugin-func/pull/651?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=knative-sandbox).

lance: /lgtm
/approve
knative-prow-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/knative-sandbox/kn-plugin-func/pull/651#issuecomment-966439484" title="Approved">lance</a>*, *<a href="https://github.com/knative-sandbox/kn-plugin-func/pull/651#" title="Author self-approved">lkingland</a>*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=knative-sandbox%2Fkn-plugin-func).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com/knative-sandbox/kn-plugin-func/blob/main/OWNERS)~~ [lance,lkingland]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/client.go b/client.go
index d1c92d47..34306f16 100644
--- a/client.go
+++ b/client.go
@@ -481,7 +481,8 @@ func (c *Client) Create(f Function) (err error) {
 		return
 	}
 
-	// Write the Function metadata (func.yaml)
+	// Mark it as having been created via this client library and Write (save)
+	f.Created = time.Now()
 	if err = writeConfig(f); err != nil {
 		return
 	}
diff --git a/config.go b/config.go
index 11624cfa..6b4296b3 100644
--- a/config.go
+++ b/config.go
@@ -8,6 +8,7 @@ import (
 	"path/filepath"
 	"regexp"
 	"strings"
+	"time"
 
 	"gopkg.in/yaml.v2"
 	"k8s.io/apimachinery/pkg/api/resource"
@@ -146,6 +147,7 @@ type Config struct {
 	Annotations     map[string]string `yaml:"annotations"`
 	Options         Options           `yaml:"options"`
 	Labels          Labels            `yaml:"labels"`
+	Created         time.Time         `yaml:"created"`
 	// Add new values to the toConfig/fromConfig functions.
 }
 
@@ -268,6 +270,7 @@ func fromConfig(c Config) (f Function) {
 		Annotations:     c.Annotations,
 		Options:         c.Options,
 		Labels:          c.Labels,
+		Created:         c.Created,
 	}
 }
 
@@ -289,6 +292,7 @@ func toConfig(f Function) Config {
 		Annotations:     f.Annotations,
 		Options:         f.Options,
 		Labels:          f.Labels,
+		Created:         f.Created,
 	}
 }
 
diff --git a/function.go b/function.go
index a0114c77..0697f98d 100644
--- a/function.go
+++ b/function.go
@@ -7,6 +7,7 @@ import (
 	"os"
 	"path/filepath"
 	"strings"
+	"time"
 )
 
 type Function struct {
@@ -75,6 +76,11 @@ type Function struct {
 
 	// Health endpoints specified by the language pack
 	HealthEndpoints HealthEndpoints
+
+	// Created time is the moment that creation was successfully completed
+	// according to the client which is in charge of what constitutes being
+	// fully "Created" (aka initialized)
+	Created time.Time
 }
 
 // NewFunction loads a Function from a path on disk. use .Initialized() to determine if
diff --git a/schema/func_yaml-schema.json b/schema/func_yaml-schema.json
index f982af45..5f1983a7 100644
--- a/schema/func_yaml-schema.json
+++ b/schema/func_yaml-schema.json
@@ -18,7 +18,8 @@
 				"envs",
 				"annotations",
 				"options",
-				"labels"
+				"labels",
+				"created"
 			],
 			"properties": {
 				"name": {
@@ -96,6 +97,10 @@
 						"$ref": "#/definitions/Label"
 					},
 					"type": "array"
+				},
+				"created": {
+					"type": "string",
+					"format": "date-time"
 				}
 			},
 			"additionalProperties": false,


Test patch:
diff --git a/client_test.go b/client_test.go
index 8ba35035..12d6ac97 100644
--- a/client_test.go
+++ b/client_test.go
@@ -12,6 +12,7 @@ import (
 	"path/filepath"
 	"reflect"
 	"testing"
+	"time"
 
 	fn "knative.dev/kn-plugin-func"
 	"knative.dev/kn-plugin-func/mock"
@@ -877,6 +878,29 @@ func TestRuntimes(t *testing.T) {
 	}
 }
 
+// TestCreateStamp ensures that the creation timestamp is set on functions
+// which are successfully initialized using the client library.
+func TestCreateStamp(t *testing.T) {
+	root := "testdata/example.com/testCreateStamp"
+	defer using(t, root)()
+
+	start := time.Now()
+
+	client := fn.New(fn.WithRegistry(TestRegistry))
+
+	if err := client.New(context.Background(), fn.Function{Root: root}); err != nil {
+		t.Fatal(err)
+	}
+
+	f, err := fn.NewFunction(root)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if !f.Created.After(start) {
+		t.Fatalf("expected function timestamp to be after '%v', got '%v'", start, f.Created)
+	}
+}
+
 // Helpers ----
 
 // USING:  Make specified dir.  Return deferrable cleanup fn.
diff --git a/cmd/delete_test.go b/cmd/delete_test.go
index 7eba6437..895a4b48 100644
--- a/cmd/delete_test.go
+++ b/cmd/delete_test.go
@@ -63,6 +63,7 @@ builders:
 envs: []
 annotations: {}
 labels: []
+created: 2021-01-01T00:00:00+00:00
 `
 	if err := ioutil.WriteFile("func.yaml", []byte(funcYaml), 0600); err != nil {
 		t.Fatal(err)