Skip to content
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

Merged
merged 6 commits into from
Dec 16, 2024
Merged

Conversation

Maed223
Copy link
Contributor

@Maed223 Maed223 commented Nov 19, 2024

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).

Screenshot 2024-11-20 at 5 17 24 PM

Previous context on the modules command

The 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 that modules.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

  • A human readable view for the terraform modules command.

@Maed223 Maed223 force-pushed the TF-19313/modules-cmd-human-view branch from 0778f7a to 2f7081c Compare November 19, 2024 15:43
@Maed223 Maed223 force-pushed the TF-19313/modules-cmd-human-view branch from 2f7081c to 272130e Compare November 19, 2024 16:07
@Maed223 Maed223 changed the title Tf 19313/modules cmd human view terraform modules cmd human view Nov 19, 2024
@Maed223 Maed223 marked this pull request as ready for review November 19, 2024 16:09
@Maed223 Maed223 requested review from a team as code owners November 19, 2024 16:09
Copy link
Contributor

The equivalence tests will be updated. Please verify the changes here.

Copy link
Contributor

The equivalence tests will be updated. Please verify the changes here.

rkoron007
rkoron007 previously approved these changes Nov 19, 2024
Copy link
Contributor

@rkoron007 rkoron007 left a 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

website/docs/cli/commands/modules.mdx Show resolved Hide resolved
Copy link
Contributor

The equivalence tests will be updated. Please verify the changes here.

rkoron007
rkoron007 previously approved these changes Nov 21, 2024
Copy link
Contributor

@rkoron007 rkoron007 left a 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.

```
Copy link
Contributor

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!

Suggested change
```
```shell-session

Copy link
Contributor Author

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
Copy link
Contributor

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!

Suggested change
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:

Copy link
Contributor

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!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Included 👍 e2c5b39

@uturunku1 uturunku1 self-requested a review November 22, 2024 21:29
Copy link
Contributor

@uturunku1 uturunku1 left a 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:

Screenshot 2024-11-22 at 1 41 00 PM

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.

internal/moduleref/record.go Show resolved Hide resolved
internal/command/views/modules.go Outdated Show resolved Hide resolved
Copy link
Contributor

@sebasslash sebasslash left a 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 ⬇️

internal/moduleref/resolver.go Outdated Show resolved Hide resolved
internal/command/views/modules.go Outdated Show resolved Hide resolved
sebasslash
sebasslash previously approved these changes Dec 6, 2024
Copy link
Contributor

@sebasslash sebasslash left a 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 {
Copy link
Contributor

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.

Copy link
Contributor

@sebasslash sebasslash left a 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 👍

Copy link
Contributor

@rkoron007 rkoron007 left a 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
Copy link
Contributor

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:

Suggested change
```javascript
```json

Copy link
Member

@radeksimko radeksimko left a 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.

Comment on lines +60 to +63
// 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())
}
Copy link
Member

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.

Copy link
Contributor Author

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.

Copy link
Member

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())
Copy link
Member

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? 🤔

Copy link
Member

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).

@Maed223 Maed223 merged commit e6bd282 into main Dec 16, 2024
8 checks passed
@Maed223 Maed223 deleted the TF-19313/modules-cmd-human-view branch December 16, 2024 15:34
Copy link
Contributor

Reminder for the merging maintainer: if this is a user-visible change, please update the changelog on the appropriate release branch.

Copy link
Member

@jbardin jbardin left a 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())
Copy link
Member

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 {
Copy link
Member

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants