-
Notifications
You must be signed in to change notification settings - Fork 9.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
terraform modules
cmd human view
#36062
Conversation
0778f7a
to
2f7081c
Compare
2f7081c
to
272130e
Compare
terraform modules
cmd human view
The equivalence tests will be updated. Please verify the changes here. |
The equivalence tests will be updated. Please verify the changes here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Added a small opportunistic suggestion
272130e
to
4cba6bb
Compare
The equivalence tests will be updated. Please verify the changes here. |
4cba6bb
to
e4b4aa8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved with some small tweaks for style!
The following example is a representation of the human readable output that `terraform modules` returns. The nested structure represents the | ||
module composition/heirarchy within your configuration. | ||
|
||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be shell? Or something like it? We wanna make sure we get syntax highlighting if we can!
``` | |
```shell-session |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Included 👍 e2c5b39
|
||
We will introduce new major versions only within the bounds of | ||
[the Terraform 1.0 Compatibility Promises](/terraform/language/v1-compatibility-promises). | ||
|
||
## Output Format | ||
|
||
The following example is a representation of the human readable output that `terraform modules` returns. The nested structure represents the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like putting the "what" first before diving into the example, but let me know what you think!
The following example is a representation of the human readable output that `terraform modules` returns. The nested structure represents the | |
The `terraform modules` command returns a nested structure, representing module composition and hierarchy within your configuration. | |
The following example demonstrates what the `terraform modules` command returns without any additional flags: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(make sure to remove the line below if you accept this suggestion!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Included 👍 e2c5b39
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great job!
One inconsistency I was noticing between this cmd and other similar cmds that have have a json view is that when we pass the wrong argument for "-json", then we get different types of outputs. See picture:
I think the most accurate output from those 3 is the one for the "schema" cmd. The one for "show" is completely off, and the one for "modules" is slightly deceiving. Though the good thing is that it mentions that you can run "-help" and that is how the user can figure out that the proper argument is "-json".
But I was curious if you have a suggestion for a better error we could output instead "Too many command line arguments". This is not a blocker by the way. Aside from this question, I am happy with the output you have implemented, and I really like how the tree presents nested modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking good, but found a bug while testing ⬇️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tested the changes, looking great now. I would address some of @rkoron007 comments on docs as well before merging.
func (r *Resolver) findAndTrimReferencedEntries(cfg *configs.Config, parentRecord *Record, parentKey *string) { | ||
var name string | ||
var versionConstraints version.Constraints | ||
if parentKey != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
parentKey
does not need to be a pointer, we can safely check if the string is empty since no module except the root module will have an empty key.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Re-approving, great work here 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! Thank you for all your work on this!
└── "my_local_module_b"[./path/to/local/module_a/module_b] | ||
└── "my_local_module_c"[./path/to/local/module/module_a/module_b/module_c] | ||
``` | ||
|
||
The following example is a representation of the JSON output format that `terraform modules -json` returns. | ||
|
||
```javascript |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you can just use json
if this doesn't specifically need to be JavaScript:
```javascript | |
```json |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM on the basis that the human-readable output is not covered by compatibility guarantees, so my questions can be addressed in a separate PR at any time later.
// Avoid rendering the version constraint if an exact version is given i.e. 'version = "1.2.3"' | ||
if childNode.VersionConstraints != nil && childNode.VersionConstraints.String() != childNode.Version.String() { | ||
item += fmt.Sprintf(" (%s)", childNode.VersionConstraints.String()) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the motivation behind this? I'd assume that version constraints will never be so long that they would worsen the readability but correct me if I'm wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's more so to handle the case where the version constraint is specified to the exact version which would lead to a bit of redundancy– such as "mod-key' [mod-source] 1.0.0 (1.0.0). Felt that is was simpler to just omit the constraint in this case as it isn't clear that it is a version constraint. Though it might have made more sense to just append a "=" here to make the constraint more clear.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it's a redundancy because a constraint is a different thing to the version actually installed. Relatedly, there can be many semantically equal version constraints which are represented by the same canonical format via String()
.
For example:
1.0.0
=1.0.0
= 1.0.0
These are all equivalent but I'm not sure they would result in the same behaviour as above, which would further confuse users.
I would just keep it simple and always render it.
return 0 | ||
} | ||
|
||
func populateTreeNode(tree treeprint.Tree, node *moduleref.Record) { | ||
for _, childNode := range node.Children { | ||
item := fmt.Sprintf("\"%s\"[%s]", childNode.Key, childNode.Source.String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd have expected %q
instead of \"%s\"
but I'm more curious if there is a reason for quoting the module key in the human output at all? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand the code correctly I don't think this will fail, but %q
should still be used to produce correctly quoted strings. (BTW you don't need to call String()
for string formatting, that is what the fmt.Stringer
interface does for you).
Reminder for the merging maintainer: if this is a user-visible change, please update the changelog on the appropriate release branch. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, just dropping in couple late comments, but nothing that can't be fixed up later.
return 0 | ||
} | ||
|
||
func populateTreeNode(tree treeprint.Tree, node *moduleref.Record) { | ||
for _, childNode := range node.Children { | ||
item := fmt.Sprintf("\"%s\"[%s]", childNode.Key, childNode.Source.String()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand the code correctly I don't think this will fail, but %q
should still be used to produce correctly quoted strings. (BTW you don't need to call String()
for string formatting, that is what the fmt.Stringer
interface does for you).
} | ||
key := strings.Join(cfg.Path, ".") | ||
|
||
for entryKey, entry := range r.internalManifest { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generating ordered lists of values from a map like this is going to produce inconsistent output. While it may be that the order doesn't matter, users will expect to see it presented consistently, so we typically will sort the slices before presentation.
Implements a human view for what was previously a machine readable view only command
terraform modules -json
. The human view shows the nested hierarchy/composition of modules in configuration rather than the flat list given by the json alternative, as well as additional info about the provided version constraints for the module. Documentation and the command's help output has been updated in accordance with this addition.To accommodate this nested format, some reworking of
resolver.go
has been done to produce a manifest with a nested structure of records (whereas before a flat list was given).Previous context on the
modules
commandThe
modules
command was initially implemented (PR here) in order to provide a means of seeing the collection of modules in current use. This need arose as a part of the module deprecation/revocation project where a list of modules currently in config was needed (as a source of truth to check for deprecations/revocations in the agent). We found thatmodules.json
provided a historical list of all modules to ever be in configuration which wasn't suitable for our use case. This command provides the means to view the modules currently in config by cross checking this historical list with the current state of configuration. As this output (for our purposes) was only being consumed by the agent, the human view had been omitted in the initial implementation. This PR seeks to close that gap.Target Release
1.11.x
Draft CHANGELOG entry
NEW FEATURES
terraform modules
command.