Skip to content

Commit 905e66e

Browse files
authored
TFx 0.1.0 release prep (#26)
* tfx workspace cv list, "workspaceName" to "workspace-name" * tfx release list (tfe and replicated), added `--all` flag * tfx registry list (module and provider), added `--max-items` and `--all` flags * fixed bug with registry module version create when the module did not exist
1 parent 7af8393 commit 905e66e

19 files changed

+134
-70
lines changed

.github/workflows/main.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: main
1+
name: Build `tfx` - Cross Compile
22

33
on:
44
push:

.github/workflows/release.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: release
1+
name: Release `tfx`
22

33
on:
44
release:

CHANGELOG.md

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8-
## [0.0.5] - 2022.08.20
8+
## [Unreleased]
9+
10+
**Added**
11+
12+
**Changed**
13+
14+
**Removed**
15+
16+
## [0.1.0] - 2022.08.21
17+
18+
First official release!
919

1020
**Added**
1121

@@ -14,7 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1424
**Changed**
1525

1626
* Moved and updated docs to the `site/` folder and published to a custom domain [tfx.rocks](tfx.rocks).
17-
* Created a styleguide and updated Commands, more information can be found at [https://tfx.rocks/about/style_guide/]()
27+
* Created a style guide and updated Commands, more information can be found at [https://tfx.rocks/about/style_guide/]()
1828
* Some of these changes are **BREAKING** changes
1929
* Mainly moving away from Command Flags that used camel case (example: "workspaceName" to "workspace-name")
2030
* Updated all of the `tfx registry module` commands to support JSON (`--json`) output.
@@ -191,6 +201,5 @@ New Commands:
191201

192202
**Removed**
193203

194-
[Unreleased]: https://github.com/straubt1/tfx/compare/v1.0.0...HEAD
195-
[0.0.1]: https://github.com/ostraubt1/tfx/compare/v0.0.0...v0.0.1
196-
[0.0.0]: https://github.com/straubt1/tfx/releases/tag/v0.0.1
204+
[Unreleased]: https://github.com/straubt1/tfx/compare/v0.1.0...HEAD
205+
[0.1.0]: https://github.com/straubt1/tfx/releases/tag/v0.1.0

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<!-- <img src="https://cdn.rawgit.com/hashicorp/terraform-website/master/content/source/assets/images/logo-hashicorp.svg" width="600px">
22
-->
3-
# Terraform Cloud/Enterprise CLI
3+
# Terraform Cloud/Terraform Enterprise CLI
44

55
[![main](https://github.com/straubt1/tfx/actions/workflows/main.yml/badge.svg)](https://github.com/straubt1/tfx/actions/workflows/main.yml)
66
![Go Version](https://img.shields.io/badge/go%20version-%3E=1.18-61CFDD.svg?style=flat-square)
@@ -15,3 +15,15 @@ The initial focus of _tfx_ was to execute the API-Driven workflow for a Workspac
1515

1616
Looking for more information?
1717
Check out our docs site [tfx.rocks](https://tfx.rocks)
18+
19+
## General Roadmap
20+
21+
Future implementation items:
22+
23+
- [ ] Create testing setup
24+
- [ ] Refactor `plan` and `apply` workflow
25+
- [ ] Support Variable Sets
26+
- [ ] Support Sentinel Publishing
27+
- [ ] Support Cloud Agents
28+
29+
Priority may changes, please submit an issue to voice changes you would like to see.

cmd/apply.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,9 @@ var (
4343

4444
func init() {
4545
// All `tfx apply` commands
46-
applyCmd.PersistentFlags().StringP("runId", "i", "", "Run Id to apply")
46+
applyCmd.PersistentFlags().StringP("run-id", "i", "", "Run Id to apply")
4747

48-
applyCmd.MarkPersistentFlagRequired("runId")
48+
applyCmd.MarkPersistentFlagRequired("run-id")
4949

5050
rootCmd.AddCommand(applyCmd)
5151
}
@@ -57,7 +57,7 @@ func runApply() error {
5757
hostname := *viperString("tfeHostname")
5858
orgName := *viperString("tfeOrganization")
5959
wsName := *viperString("workspaceName")
60-
runID := *viperString("runId")
60+
runID := *viperString("run-id")
6161

6262
client, ctx := getClientContext()
6363

cmd/helper_rest.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,7 @@ type GPGList struct {
148148
}
149149

150150
func ListGPGKeys(c TfxClientContext) (*GPGList, error) {
151+
// TODO: No pagination, waiting on go-tfe to provide a List function since it is unlikely an org would have more than 100 keys
151152
// create url "https://${HOST}/api/registry/private/v2/gpg-keys?filter%5Bnamespace%5D=${provider_namespace}"
152153
url := fmt.Sprintf(
153154
"https://%s/api/registry/private/v2/gpg-keys?filter[namespace]=%s",

cmd/plan.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,18 @@ var (
5757

5858
func init() {
5959
// All `tfx plan` commands
60-
planCmd.Flags().StringP("workspaceName", "w", "", "Workspace name")
60+
planCmd.Flags().StringP("workspace-name", "w", "", "Workspace name")
6161
planCmd.Flags().StringP("directory", "d", "./", "Directory of Terraform (optional, defaults to current directory)")
62-
planCmd.Flags().StringP("configurationId", "i", "", "Configuration Version Id (optional, i.e. cv-*)")
62+
planCmd.Flags().StringP("configuration-id", "i", "", "Configuration Version Id (optional, i.e. cv-*)")
6363
planCmd.Flags().StringP("message", "m", "", "Run Message (optional)")
6464
planCmd.Flags().Bool("speculative", false, "Perform a Speculative Plan (optional)")
6565
planCmd.Flags().Bool("destroy", false, "Perform a Destroy Plan (optional)")
66-
planCmd.Flags().StringSlice("env", []string{}, "Environment variables to write to the Workspace. Can be suplied multiple times. (optional, i.e. '--env='AWS_REGION=us-east1')")
67-
planCmd.MarkFlagRequired("workspaceName")
66+
planCmd.Flags().StringSlice("env", []string{}, "Environment variables to write to the Workspace. Can be supplied multiple times. (optional, i.e. '--env='AWS_REGION=us-east1')")
67+
planCmd.MarkFlagRequired("workspace-name")
6868

69-
planExportCmd.Flags().StringP("planId", "i", "", "Plan Id (i.e. plan-*)")
69+
planExportCmd.Flags().StringP("plan-id", "i", "", "Plan Id (i.e. plan-*)")
7070
planExportCmd.Flags().StringP("directory", "d", "", "Directory to download export to (optional, defaults to a temp directory)")
71-
planExportCmd.MarkFlagRequired("planId")
71+
planExportCmd.MarkFlagRequired("plan-id")
7272
planExportCmd.MarkFlagRequired("directory")
7373

7474
rootCmd.AddCommand(planCmd)
@@ -79,9 +79,9 @@ func runPlan() error {
7979
// Validate flags
8080
hostname := *viperString("tfeHostname")
8181
orgName := *viperString("tfeOrganization")
82-
wsName := *viperString("workspaceName")
82+
wsName := *viperString("workspace-name")
8383
dir := *viperString("directory")
84-
configID := *viperString("configurationId")
84+
configID := *viperString("configuration-id")
8585
message := *viperString("message")
8686
isSpeculative := *viperBool("speculative")
8787
isDestroy := *viperBool("destroy")
@@ -156,7 +156,7 @@ func runPlan() error {
156156
}
157157

158158
func runPlanExport() error {
159-
planID := *viperString("planId")
159+
planID := *viperString("plan-id")
160160
directory := *viperString("directory")
161161
client, ctx := getClientContext()
162162

cmd/registry_module.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
package cmd
2222

2323
import (
24+
"math"
25+
2426
tfe "github.com/hashicorp/go-tfe"
2527
"github.com/pkg/errors"
2628
"github.com/spf13/cobra"
@@ -40,8 +42,14 @@ var (
4042
Short: "List modules",
4143
Long: "List modules in the Private Module Registry of a TFx Organization.",
4244
RunE: func(cmd *cobra.Command, args []string) error {
45+
m := *viperInt("max-items")
46+
if *viperBool("all") {
47+
m = math.MaxInt
48+
}
49+
4350
return registryModuleList(
44-
getTfxClientContext())
51+
getTfxClientContext(),
52+
m)
4553
},
4654
}
4755

@@ -87,6 +95,8 @@ var (
8795

8896
func init() {
8997
// `tfx registry module list` arguments
98+
registryModuleListCmd.Flags().IntP("max-items", "m", 10, "Max number of results (optional)")
99+
registryModuleListCmd.Flags().BoolP("all", "a", false, "Retrieve all results regardless of maxItems flag (optional)")
90100

91101
// `tfx registry module create` arguments
92102
registryModuleCreateCmd.Flags().StringP("name", "n", "", "Name of the Module (no spaces)")
@@ -113,13 +123,15 @@ func init() {
113123
registryModuleCmd.AddCommand(registryModuleDeleteCmd)
114124
}
115125

116-
func registryModuleListAll(c TfxClientContext, orgName string) ([]*tfe.RegistryModule, error) {
126+
func registryModuleListAll(c TfxClientContext, orgName string, maxItems int) ([]*tfe.RegistryModule, error) {
127+
pageSize := 100
128+
if maxItems < 100 {
129+
pageSize = maxItems // Only get what we need in one page
130+
}
131+
117132
allItems := []*tfe.RegistryModule{}
118133
opts := tfe.RegistryModuleListOptions{
119-
ListOptions: tfe.ListOptions{
120-
PageNumber: 1,
121-
PageSize: 100,
122-
},
134+
ListOptions: tfe.ListOptions{PageNumber: 1, PageSize: pageSize},
123135
}
124136

125137
for {
@@ -129,6 +141,10 @@ func registryModuleListAll(c TfxClientContext, orgName string) ([]*tfe.RegistryM
129141
}
130142

131143
allItems = append(allItems, items.Items...)
144+
if len(allItems) >= maxItems {
145+
break // Hit the max, break. For maxItems > 100 it is possible to return more than max in this approach
146+
}
147+
132148
if items.CurrentPage >= items.TotalPages {
133149
break
134150
}
@@ -138,9 +154,9 @@ func registryModuleListAll(c TfxClientContext, orgName string) ([]*tfe.RegistryM
138154
return allItems, nil
139155
}
140156

141-
func registryModuleList(c TfxClientContext) error {
157+
func registryModuleList(c TfxClientContext, maxItems int) error {
142158
o.AddMessageUserProvided("List Modules for Organization:", c.OrganizationName)
143-
items, err := registryModuleListAll(c, c.OrganizationName)
159+
items, err := registryModuleListAll(c, c.OrganizationName, maxItems)
144160
if err != nil {
145161
return errors.Wrap(err, "failed to list modules")
146162
}

cmd/registry_module_version.go

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,12 @@ var (
116116
)
117117

118118
func init() {
119+
// `tfx registry module version list` arguments
120+
registryModuleVersionListCmd.Flags().StringP("name", "n", "", "Name of the Module (no spaces)")
121+
registryModuleVersionListCmd.Flags().StringP("provider", "p", "", "Name of the provider (no spaces) (i.e. aws, azure, google)")
122+
registryModuleVersionListCmd.MarkFlagRequired("name")
123+
registryModuleVersionListCmd.MarkFlagRequired("provider")
124+
119125
// `tfx registry module version create` arguments
120126
registryModuleVersionCreateCmd.Flags().StringP("name", "n", "", "Name of the Module (no spaces)")
121127
registryModuleVersionCreateCmd.Flags().StringP("provider", "p", "", "Name of the provider (no spaces) (i.e. aws, azure, google)")
@@ -125,12 +131,6 @@ func init() {
125131
registryModuleVersionCreateCmd.MarkFlagRequired("provider")
126132
registryModuleVersionCreateCmd.MarkFlagRequired("version")
127133

128-
// `tfx registry module version list` arguments
129-
registryModuleVersionListCmd.Flags().StringP("name", "n", "", "Name of the Module (no spaces)")
130-
registryModuleVersionListCmd.Flags().StringP("provider", "p", "", "Name of the provider (no spaces) (i.e. aws, azure, google)")
131-
registryModuleVersionListCmd.MarkFlagRequired("name")
132-
registryModuleVersionListCmd.MarkFlagRequired("provider")
133-
134134
// `tfx registry module version delete` arguments
135135
registryModuleVersionDeleteCmd.Flags().StringP("name", "n", "", "Name of the Module (no spaces)")
136136
registryModuleVersionDeleteCmd.Flags().StringP("provider", "p", "", "Name of the provider (no spaces) (i.e. aws, azure, google)")
@@ -189,9 +189,10 @@ func registryModuleVersionCreate(c TfxClientContext, moduleName string, provider
189189
Version: &moduleVersion,
190190
})
191191
if err != nil {
192-
errors.Wrap(err, "failed to create module version")
192+
return errors.Wrap(err, "failed to create module version")
193193
}
194-
o.AddMessageUserProvided("Module Created, Uploading...", "")
194+
195+
o.AddMessageUserProvided("Module Version Created, Uploading...", "")
195196
err = c.Client.RegistryModules.Upload(c.Context, *module, directory)
196197
if err != nil {
197198
errors.Wrap(err, "failed to upload module version")

cmd/registry_provider.go

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
package cmd
2121

2222
import (
23+
"math"
24+
2325
tfe "github.com/hashicorp/go-tfe"
2426
"github.com/pkg/errors"
2527
"github.com/spf13/cobra"
@@ -39,8 +41,14 @@ var (
3941
Short: "List Providers in a Private Registry",
4042
Long: "List Providers in a Private Registry of a TFx Organization.",
4143
RunE: func(cmd *cobra.Command, args []string) error {
44+
m := *viperInt("max-items")
45+
if *viperBool("all") {
46+
m = math.MaxInt
47+
}
48+
4249
return registryProviderList(
43-
getTfxClientContext())
50+
getTfxClientContext(),
51+
m)
4452
},
4553
}
4654

@@ -83,6 +91,8 @@ var (
8391

8492
func init() {
8593
// `tfx registry provider list` arguments
94+
registryProviderListCmd.Flags().IntP("max-items", "m", 10, "Max number of results (optional)")
95+
registryProviderListCmd.Flags().BoolP("all", "a", false, "Retrieve all results regardless of maxItems flag (optional)")
8696

8797
// `tfx registry provider create` arguments
8898
registryProviderCreateCmd.Flags().StringP("name", "n", "", "Name of the Provider")
@@ -103,14 +113,16 @@ func init() {
103113
registryProviderCmd.AddCommand(registryProviderDeleteCmd)
104114
}
105115

106-
func registryProviderListAll(c TfxClientContext) ([]*tfe.RegistryProvider, error) {
116+
func registryProviderListAll(c TfxClientContext, maxItems int) ([]*tfe.RegistryProvider, error) {
117+
pageSize := 100
118+
if maxItems < 100 {
119+
pageSize = maxItems // Only get what we need in one page
120+
}
121+
107122
allItems := []*tfe.RegistryProvider{}
108123
opts := tfe.RegistryProviderListOptions{
124+
ListOptions: tfe.ListOptions{PageNumber: 1, PageSize: pageSize},
109125
// RegistryName: tfe.PrivateRegistry, // Can restrict to just private
110-
ListOptions: tfe.ListOptions{
111-
PageNumber: 1,
112-
PageSize: 100,
113-
},
114126
// Include: &[]tfe.RegistryProviderIncludeOps{"provider-versions"}, does not work, cant get provider versions from this call?
115127
}
116128
for {
@@ -120,6 +132,10 @@ func registryProviderListAll(c TfxClientContext) ([]*tfe.RegistryProvider, error
120132
}
121133

122134
allItems = append(allItems, items.Items...)
135+
if len(allItems) >= maxItems {
136+
break // Hit the max, break. For maxItems > 100 it is possible to return more than max in this approach
137+
}
138+
123139
if items.CurrentPage >= items.TotalPages {
124140
break
125141
}
@@ -129,9 +145,9 @@ func registryProviderListAll(c TfxClientContext) ([]*tfe.RegistryProvider, error
129145
return allItems, nil
130146
}
131147

132-
func registryProviderList(c TfxClientContext) error {
148+
func registryProviderList(c TfxClientContext, maxItems int) error {
133149
o.AddMessageUserProvided("List Providers in Registry for Organization:", c.OrganizationName)
134-
items, err := registryProviderListAll(c)
150+
items, err := registryProviderListAll(c, maxItems)
135151
if err != nil {
136152
return errors.Wrap(err, "failed to list providers")
137153
}

0 commit comments

Comments
 (0)