diff --git a/cli/cmd/update.go b/cli/cmd/update.go index 1c89ab54..d0af1882 100644 --- a/cli/cmd/update.go +++ b/cli/cmd/update.go @@ -5,10 +5,12 @@ import ( "encoding/json" "fmt" "log" + "maps" "os" "os/exec" "path/filepath" "regexp" + "slices" "strings" "github.com/Masterminds/semver/v3" @@ -38,11 +40,6 @@ type Alias struct { semver.Version } -type LastestChanges struct { - versions []*semver.Version - latestAlias *Alias -} - func (a Alias) MarshalText() ([]byte, error) { return fmt.Appendf(nil, "%d.%d", a.Major(), a.Minor()), nil } @@ -58,6 +55,11 @@ func (a Alias) String() string { return fmt.Sprintf("%d.%d", a.Major(), a.Minor()) } +type Changes struct { + newVersions []*semver.Version + aliases []Alias +} + var updateCmd = &cobra.Command{ Use: "update", Short: "Update versions file", @@ -96,11 +98,10 @@ var updateCmd = &cobra.Command{ return fmt.Errorf("invalid min-version: %w", err) } - latestChanges, err := updateVersions( + changes, err := updateVersions( nixPath, token, versionsPath, - templatesPath, minVersion, owner, repo, @@ -109,19 +110,27 @@ var updateCmd = &cobra.Command{ return fmt.Errorf("unable to update versions: %w", err) } var messages []string - if len(latestChanges.versions) > 0 { + if len(changes.newVersions) > 0 { var formattedVersions []string - for _, newVersion := range latestChanges.versions { + for _, newVersion := range changes.newVersions { formattedVersions = append(formattedVersions, newVersion.String()) } versions := strings.Join(formattedVersions, ", ") messages = append(messages, fmt.Sprintf("Add Terraform version(s) %s", versions)) } - if latestChanges.latestAlias != nil { - messages = append( - messages, - fmt.Sprintf("Update templates to use version %s", latestChanges.latestAlias), - ) + + if templatesPath != "" { + latestAlias, err := getLatestAlias(changes.aliases) + if err != nil { + return err + } + + err = updateTemplatesVersions(templatesPath, latestAlias) + if err != nil { + return err + } + + messages = append(messages, fmt.Sprintf("Update template to use version %s", latestAlias)) } if len(messages) > 0 { @@ -135,11 +144,10 @@ func updateVersions( nixPath string, token string, versionsPath string, - templatesPath string, minVersion *semver.Version, owner string, repo string, -) (*LastestChanges, error) { +) (*Changes, error) { versions, err := readVersions(versionsPath) if err != nil { return nil, fmt.Errorf("unable to read versions: %w", err) @@ -212,14 +220,9 @@ func updateVersions( return nil, fmt.Errorf("unable to write file: %w", err) } - latestAlias, err := updateTemplatesVersions(versions, templatesPath) - if err != nil { - return nil, fmt.Errorf("unable to update templates versions: %w", err) - } - - return &LastestChanges{ - versions: newVersions, - latestAlias: latestAlias, + return &Changes{ + newVersions: newVersions, + aliases: slices.Collect(maps.Keys(versions.Aliases)), }, nil } @@ -237,29 +240,20 @@ func getLatestAlias(aliases []Alias) (*Alias, error) { return latestAlias, nil } -func updateTemplatesVersions(versions *Versions, templatesPath string) (*Alias, error) { - var aliases []Alias - for alias := range versions.Aliases { - aliases = append(aliases, alias) - } - - latestAlias, err := getLatestAlias(aliases) +func updateTemplatesVersions(templatesPath string, latestAlias *Alias) error { + files, err := filepath.Glob(fmt.Sprintf("%s/*/flake.nix", templatesPath)) if err != nil { - return nil, fmt.Errorf("unable to get latest version: %w", err) + return fmt.Errorf("unable to find flake.nix files: %w", err) } - files, err := filepath.Glob(fmt.Sprintf("%s/**/flake.nix", templatesPath)) - if err != nil { - return nil, fmt.Errorf("unable to find flake.nix files: %w", err) - } - - updated := false re := regexp.MustCompile(`"(\d+\.\d+(\.\d+)?)"`) for _, file := range files { content, err := os.ReadFile(file) if err != nil { - return nil, fmt.Errorf("unable to read file %s: %w", file, err) + log.Printf("Unable to read file %s\n", file) + continue } + updatedContent := re.ReplaceAllString( string(content), fmt.Sprintf(`"%s"`, latestAlias), @@ -271,17 +265,12 @@ func updateTemplatesVersions(versions *Versions, templatesPath string) (*Alias, err = os.WriteFile(file, []byte(updatedContent), 0644) if err != nil { - return nil, fmt.Errorf("unable to write file %s: %w", file, err) + return fmt.Errorf("unable to write file %s: %w", file, err) } log.Printf("Updated %s to version %s\n", file, latestAlias) - updated = true } - if updated { - return latestAlias, nil - } - - return nil, nil + return nil } func readVersions(versionsPath string) (*Versions, error) { @@ -385,7 +374,7 @@ func computeVendorHash(nixPath string, version *semver.Version) (string, error) nixPath, "build", "--extra-experimental-features", "nix-command flakes", "--no-link", - fmt.Sprintf(".#\"terraform-%s\"", version.String()), + fmt.Sprintf(".#\"%s-%s\"", repo, version.String()), ) output, err := cmd.CombinedOutput() @@ -405,9 +394,9 @@ func computeVendorHash(nixPath string, version *semver.Version) (string, error) func init() { updateCmd.Flags(). - StringVarP(&versionsPath, "versions", "", "versions.json", "The file to be updated") + StringVarP(&versionsPath, "versions", "", "terraform.json", "The file to be updated") updateCmd.Flags(). - StringVarP(&templatesPath, "templates-dir", "", "templates", "Directory containing templates to update versions") + StringVarP(&templatesPath, "templates-dir", "", "", "Directory containing templates to update versions") updateCmd.Flags(). StringVarP(&minVersionStr, "min-version", "", "1.0.0", "Min release version") updateCmd.Flags(). diff --git a/cli/go.mod b/cli/go.mod index 840c744e..0a6b797b 100644 --- a/cli/go.mod +++ b/cli/go.mod @@ -1,6 +1,6 @@ module github.com/stackbuilders/nixpkgs-terraform/cli -go 1.22.1 +go 1.23 require ( github.com/Masterminds/semver/v3 v3.2.1 diff --git a/flake.lock b/flake.lock index 1a9579ab..9e0ff8fa 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1763934636, - "narHash": "sha256-9glbI7f1uU+yzQCq5LwLgdZqx6svOhZWkd4JRY265fc=", + "lastModified": 1765934234, + "narHash": "sha256-pJjWUzNnjbIAMIc5gRFUuKCDQ9S1cuh3b2hKgA7Mc4A=", "owner": "nixos", "repo": "nixpkgs", - "rev": "ee09932cedcef15aaf476f9343d1dea2cb77e261", + "rev": "af84f9d270d404c17699522fab95bbf928a2d92f", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index e2f7b086..faf98d4e 100644 --- a/flake.nix +++ b/flake.nix @@ -20,7 +20,29 @@ let forAllSystems = nixpkgs.lib.genAttrs (import systems); - terraformVersions = builtins.fromJSON (builtins.readFile ./versions.json); + opentofuVersions = builtins.fromJSON (builtins.readFile ./opentofu.json); + + opentofuReleases = forAllSystems ( + system: + self.lib.mkReleases { + inherit system; + releases = opentofuVersions.releases; + namePrefix = "opentofu"; + mkRelease = self.lib.mkOpenTofu; + } + ); + + opentofuAliases = forAllSystems ( + system: + nixpkgs.lib.mapAttrs' + (cycle: version: { + name = "opentofu-${cycle}"; + value = opentofuReleases.${system}."opentofu-${version}"; + }) + opentofuVersions.aliases + ); + + terraformVersions = builtins.fromJSON (builtins.readFile ./terraform.json); terraformReleases = forAllSystems ( system: @@ -67,13 +89,15 @@ { packages = forAllSystems ( system: - terraformReleases.${system} + opentofuReleases.${system} + // opentofuAliases.${system} + // terraformReleases.${system} // terraformAliases.${system} // deprecatedReleases.${system} // deprecatedAliases.${system} ); - checks = terraformAliases; + checks = forAllSystems (system: opentofuAliases.${system} // terraformAliases.${system}); overlays = { default = @@ -84,7 +108,9 @@ "\"terraform-versions\" packages are deprecated; use the prefixed \"terraform-\" packages instead" self.packages.${prev.system}; } + // self.overlays.opentofu final prev // self.overlays.terraform final prev; + opentofu = final: prev: opentofuReleases.${prev.system} // opentofuAliases.${prev.system}; terraform = final: prev: terraformReleases.${prev.system} // terraformAliases.${prev.system}; }; diff --git a/lib/default.nix b/lib/default.nix index 1455cc8f..8d55c635 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -49,6 +49,26 @@ ]; }; + mkOpenTofu = + { system ? builtins.currentSystem + , version + , hash + , vendorHash + , + }: + let + pkgs = inputs.nixpkgs.legacyPackages.${system}; + in + pkgs.opentofu.overrideAttrs { + inherit version vendorHash; + src = pkgs.fetchFromGitHub { + inherit hash; + owner = "opentofu"; + repo = "opentofu"; + tag = "v${version}"; + }; + }; + mkReleases = { system , releases diff --git a/opentofu.json b/opentofu.json new file mode 100644 index 00000000..17245e7e --- /dev/null +++ b/opentofu.json @@ -0,0 +1,15 @@ +{ + "releases": { + "1.11.0": { + "hash": "sha256-NnYon8VrW8oSd2DQzXTSFmf0vh4i7tJIVFHVYdKYUGk=", + "vendorHash": "sha256-aPBP7mZ4NuPAYAOW20cQ6bWQUqk9mfiaeFUS/RQyW4I=" + }, + "1.11.1": { + "hash": "sha256-2mtSRszdHeHDKpIu+w/Y/P8NfoSPzPBkgQ9YgKSwrls=", + "vendorHash": "sha256-aPBP7mZ4NuPAYAOW20cQ6bWQUqk9mfiaeFUS/RQyW4I=" + } + }, + "aliases": { + "1.11": "1.11.1" + } +} \ No newline at end of file diff --git a/versions.json b/terraform.json similarity index 100% rename from versions.json rename to terraform.json