Repository: helm/helm
Pull request #7272 (2019-12-19 16:58:16)

Port PR #4161 to Helmv3 - Fix incorrect timestamp when helm package
Source: https://github.com/helm/helm/pull/4161/commits/96a85a06ed48e618c53441cdc988680eb00f8e0c

bacongobbler: closes #7220
bacongobbler: would you mind fixing the failing tests?

```
GO111MODULE=on golangci-lint run
pkg/chartutil/save.go:211: File is not `gofmt`-ed with `-s` (gofmt)
		Name: name,
		Mode: 0644,
		Size: int64(len(body)),
pkg/chartutil/save_test.go:20: File is not `gofmt`-ed with `-s` (gofmt)
	"bytes"
make: *** [Makefile:85: test-style] Error 1

Exited with code exit status 2
```
Hiruma31: @bacongobbler Yep already on it, probably an indent issue considering my environment.

Patch:
diff --git a/pkg/chartutil/save.go b/pkg/chartutil/save.go
index 4ab9d3b24..fb985bb59 100644
--- a/pkg/chartutil/save.go
+++ b/pkg/chartutil/save.go
@@ -23,6 +23,7 @@ import (
 	"fmt"
 	"os"
 	"path/filepath"
+	"time"
 
 	"github.com/pkg/errors"
 	"sigs.k8s.io/yaml"
@@ -207,9 +208,10 @@ func writeTarContents(out *tar.Writer, c *chart.Chart, prefix string) error {
 func writeToTar(out *tar.Writer, name string, body []byte) error {
 	// TODO: Do we need to create dummy parent directory names if none exist?
 	h := &tar.Header{
-		Name: name,
-		Mode: 0644,
-		Size: int64(len(body)),
+		Name:    name,
+		Mode:    0644,
+		Size:    int64(len(body)),
+		ModTime: time.Now(),
 	}
 	if err := out.WriteHeader(h); err != nil {
 		return err


Test patch:
diff --git a/pkg/chartutil/save_test.go b/pkg/chartutil/save_test.go
index 8941d0368..f367d42eb 100644
--- a/pkg/chartutil/save_test.go
+++ b/pkg/chartutil/save_test.go
@@ -17,7 +17,10 @@ limitations under the License.
 package chartutil
 
 import (
+	"archive/tar"
 	"bytes"
+	"compress/gzip"
+	"io"
 	"io/ioutil"
 	"os"
 	"path"
@@ -25,6 +28,7 @@ import (
 	"regexp"
 	"strings"
 	"testing"
+	"time"
 
 	"helm.sh/helm/v3/pkg/chart"
 	"helm.sh/helm/v3/pkg/chart/loader"
@@ -99,6 +103,85 @@ func Indent(n int, text string) string {
 	return startOfLine.ReplaceAllLiteralString(text, indentation)
 }
 
+func TestSavePreservesTimestamps(t *testing.T) {
+	// Test executes so quickly that if we don't subtract a second, the
+	// check will fail because `initialCreateTime` will be identical to the
+	// written timestamp for the files.
+	initialCreateTime := time.Now().Add(-1 * time.Second)
+
+	tmp, err := ioutil.TempDir("", "helm-")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer os.RemoveAll(tmp)
+
+	c := &chart.Chart{
+		Metadata: &chart.Metadata{
+			APIVersion: chart.APIVersionV1,
+			Name:       "ahab",
+			Version:    "1.2.3.4",
+		},
+		Values: map[string]interface{}{
+			"imageName": "testimage",
+			"imageId":   42,
+		},
+		Files: []*chart.File{
+			{Name: "scheherazade/shahryar.txt", Data: []byte("1,001 Nights")},
+		},
+		Schema: []byte("{\n  \"title\": \"Values\"\n}"),
+	}
+
+	where, err := Save(c, tmp)
+	if err != nil {
+		t.Fatalf("Failed to save: %s", err)
+	}
+
+	allHeaders, err := retrieveAllHeadersFromTar(where)
+	if err != nil {
+		t.Fatalf("Failed to parse tar: %v", err)
+	}
+
+	for _, header := range allHeaders {
+		if header.ModTime.Before(initialCreateTime) {
+			t.Fatalf("File timestamp not preserved: %v", header.ModTime)
+		}
+	}
+}
+
+// We could refactor `load.go` to use this `retrieveAllHeadersFromTar` function
+// as well, so we are not duplicating components of the code which iterate
+// through the tar.
+func retrieveAllHeadersFromTar(path string) ([]*tar.Header, error) {
+	raw, err := os.Open(path)
+	if err != nil {
+		return nil, err
+	}
+	defer raw.Close()
+
+	unzipped, err := gzip.NewReader(raw)
+	if err != nil {
+		return nil, err
+	}
+	defer unzipped.Close()
+
+	tr := tar.NewReader(unzipped)
+	headers := []*tar.Header{}
+	for {
+		hd, err := tr.Next()
+		if err == io.EOF {
+			break
+		}
+
+		if err != nil {
+			return nil, err
+		}
+
+		headers = append(headers, hd)
+	}
+
+	return headers, nil
+}
+
 func TestSaveDir(t *testing.T) {
 	tmp, err := ioutil.TempDir("", "helm-")
 	if err != nil {