diff --git a/main.go b/main.go index f8efb8ff..6a2c1572 100644 --- a/main.go +++ b/main.go @@ -562,10 +562,10 @@ func validateRepo(c *cli.Context) { logrus.Infof("Checking if Git is clean after generating charts") _, _, status = getGitInfo() - if !status.IsClean() { - logrus.Warnf("Generated charts produced the following changes in Git.\n%s", status) - logrus.Fatalf("Please commit these changes and run validation again.") + if err := validate.StatusExceptions(status); err != nil { + logrus.Fatal(err) } + logrus.Infof("Successfully validated that current charts and assets are up to date.") } diff --git a/pkg/git/git.go b/pkg/git/git.go index fd4f295a..fbfb8386 100644 --- a/pkg/git/git.go +++ b/pkg/git/git.go @@ -278,6 +278,32 @@ func (g *Git) CheckFileExists(file, branch string) error { return exec.Command("git", "-C", g.Dir, "cat-file", "-e", target).Run() } +// FullReset performs a hard reset, cleans the repository and restores it +func (g *Git) FullReset() error { + if err := g.HardHEADReset(); err != nil { + return err + } + if err := g.ForceClean(); err != nil { + return err + } + return g.Restore() +} + +// HardHEADReset = git reset --hard HEAD +func (g *Git) HardHEADReset() error { + return exec.Command("git", "-C", g.Dir, "reset", "--hard", "HEAD").Run() +} + +// ForceClean = git clean -fdx +func (g *Git) ForceClean() error { + return exec.Command("git", "-C", g.Dir, "clean", "-fdx").Run() +} + +// Restore = git restore . +func (g *Git) Restore() error { + return exec.Command("git", "-C", g.Dir, "restore", ".").Run() +} + // ResetHEAD resets the HEAD of the git repository // ex: git reset HEAD func (g *Git) ResetHEAD() error { diff --git a/pkg/validate/validate.go b/pkg/validate/validate.go index c35d8f94..7a353eb3 100644 --- a/pkg/validate/validate.go +++ b/pkg/validate/validate.go @@ -1,12 +1,15 @@ package validate import ( + "errors" "fmt" "path/filepath" "strings" "github.com/go-git/go-billy/v5" + "github.com/go-git/go-git/v5" "github.com/rancher/charts-build-scripts/pkg/filesystem" + bashGit "github.com/rancher/charts-build-scripts/pkg/git" "github.com/rancher/charts-build-scripts/pkg/lifecycle" "github.com/rancher/charts-build-scripts/pkg/options" "github.com/rancher/charts-build-scripts/pkg/path" @@ -212,3 +215,56 @@ func copyAndUnzip(repoFs billy.Filesystem, upstreamPath, localPath string) error } return nil } + +// StatusExceptions checks if the git repository is clean and if it is not, it checks if the changes are allowed +func StatusExceptions(status git.Status) error { + if !status.IsClean() { + if err := validateExceptions(status); err != nil { + logrus.Errorf("git is not clean: %s\n", err.Error()) + logrus.Errorf("status:\n%s\n", status) + return errors.New("Repository must be clean to run validation") + } + + g, err := bashGit.OpenGitRepo(".") + if err != nil { + return err + } + if err := g.FullReset(); err != nil { + return err + } + } + + return nil +} + +// validateExceptions checks if the changes are allowed +func validateExceptions(status git.Status) error { + /** + * The following exceptions are allowed to be modified, they were wrongly released with .orig files on the final production version. + * This does not break anything and it is not allowed to modify already released charts. + */ + exceptions := map[string][]string{ + "rancher-istio": {"105.4.0+up1.23.2"}, + "prometheus-federator": {"103.0.0+up0.4.0", "103.0.1+up0.4.1", "104.0.0+up0.4.0"}, + } + + for changedFile, _ := range status { + if changedFile == "index.yaml" { + continue + } + + for exceptionChart, exceptionVersions := range exceptions { + if !strings.Contains(changedFile, exceptionChart) { + continue + } + + for _, exceptionVersion := range exceptionVersions { + if !strings.Contains(changedFile, exceptionVersion) { + return fmt.Errorf("chart: %s - version: %s is not allowed to be modified", exceptionChart, exceptionVersion) + } + } + } + } + + return nil +}