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

Handle code blocks in import section #2382

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 83 additions & 44 deletions pkg/tfgen/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -1166,6 +1166,42 @@ func flattenListAttributeKey(attribute string) string {
return strings.ReplaceAll(attribute, ".0", "")
}

func parseImportShellLine(section, token string) string {
if strings.Contains(section, "terraform import") {
// First, remove the `$`
section := strings.Replace(section, "$ ", "", -1)
// Next, remove `terraform import` from the codeblock
section = strings.Replace(section, "terraform import ", "", -1)
importString := ""
parts := strings.Split(section, " ")
for i, p := range parts {
switch i {
case 0:
if !isBlank(p) {
// split the string on . and take the last item
// this gets the identifier broken from the tf resource
ids := strings.Split(p, ".")
name := ids[len(ids)-1]
importString = fmt.Sprintf("%s %s", importString, name)
}
default:
if !isBlank(p) {
importString = fmt.Sprintf("%s %s", importString, p)
}
}
}
var tok string
if token != "" {
tok = token
} else {
tok = "MISSING_TOK"
}
importCommand := fmt.Sprintf("$ pulumi import %s%s", tok, importString)
return importCommand
}
return section
}

func (p *tfMarkdownParser) parseImports(subsection []string) {
var token string
if p.info != nil && p.info.GetTok() != "" {
Expand Down Expand Up @@ -1206,65 +1242,68 @@ func (p *tfMarkdownParser) parseImports(subsection []string) {
}

var importDocString string
for _, section := range subsection {
var i = 0

for i < len(subsection) {
section := subsection[i]
trimmedSection := strings.TrimSpace(section)
if strings.Contains(section, "**NOTE:") || strings.Contains(section, "**Please Note:") ||
strings.Contains(section, "**Note:**") {
// This is a Terraform import specific comment that we don't need to parse or include in our docs
i++
continue
}

// Skip another redundant comment
if strings.Contains(section, "Import is supported using the following syntax") {
i++
continue
}

// Remove the shell comment characters to avoid writing this line as a Markdown H1:
section = strings.TrimPrefix(section, "# ")

// There are multiple variations of codeblocks for import syntax
section = strings.Replace(section, "```shell", "", -1)
section = strings.Replace(section, "```sh", "", -1)
section = strings.Replace(section, "```", "", -1)

if strings.Contains(section, "terraform import") {
// First, remove the `$`
section := strings.Replace(section, "$ ", "", -1)
// Next, remove `terraform import` from the codeblock
section = strings.Replace(section, "terraform import ", "", -1)
importString := ""
parts := strings.Split(section, " ")
for i, p := range parts {
switch i {
case 0:
if !isBlank(p) {
// split the string on . and take the last item
// this gets the identifier broken from the tf resource
ids := strings.Split(p, ".")
name := ids[len(ids)-1]
importString = fmt.Sprintf("%s %s", importString, name)
}
default:
if !isBlank(p) {
importString = fmt.Sprintf("%s %s", importString, p)
}
// Handle terraform blocks - pass them whole without changes
if trimmedSection == "```terraform" || trimmedSection == "```hcl" {
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use https://github.com/pulumi/pulumi-terraform-bridge/blob/master/pkg/tfgen/docs.go#L2353 for this check - it contains the current known detection patterns for TF code. 🙏

for {
section = subsection[i]
trimmedSection := strings.TrimSpace(section)
importDocString = importDocString + section + "\n"
i++
if trimmedSection == "```" {
break
}
}
var tok string
if token != "" {
tok = token
} else {
tok = "MISSING_TOK"
}
importCommand := fmt.Sprintf("$ pulumi import %s%s\n", tok, importString)
importDetails := "```sh\n" + importCommand + "```\n\n"
importDocString = importDocString + importDetails
} else {
if !isBlank(section) {
// Ensure every section receives a line break.
section = section + "\n\n"
importDocString = importDocString + section
importDocString = importDocString + "\n"
continue
}

// Handle script blocks - replace terraform import with pulumi import
if strings.HasPrefix(trimmedSection, "```") {
initial := true
for {
section = subsection[i]
Copy link
Contributor

Choose a reason for hiding this comment

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

This line panics when running this code against pulumi-gcp.

trimmedSection := strings.TrimSpace(section)
if initial {
// ``` and ```shell are removed when converting to programming language comment
importDocString = importDocString + "```sh" + "\n"
} else {
importDocString = importDocString + parseImportShellLine(section, token) + "\n"
}
i++
if trimmedSection == "```" && !initial {
break
}
initial = false
}
importDocString = importDocString + "\n"
continue
}

if !isBlank(section) {
// Ensure every section receives a line break.
section = section + "\n\n"
importDocString = importDocString + section
}

i++
}

if len(importDocString) > 0 {
Expand Down
7 changes: 6 additions & 1 deletion pkg/tfgen/docs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1785,7 +1785,7 @@ func TestParseImports_NoOverrides(t *testing.T) {
"",
},
token: "snowflake:index/accountGrant:AccountGrant",
expected: "## Import\n\nformat is account name | | | privilege | true/false for with_grant_option\n\n```sh\n$ pulumi import snowflake:index/accountGrant:AccountGrant example 'accountName|||USAGE|true'\n```\n\n",
expected: "## Import\n\n```sh\n# format is account name | | | privilege | true/false for with_grant_option\n$ pulumi import snowflake:index/accountGrant:AccountGrant example 'accountName|||USAGE|true'\n```\n\n",
},
{
input: []string{
Expand Down Expand Up @@ -1830,6 +1830,11 @@ func TestParseImports_NoOverrides(t *testing.T) {
token: "aws:lambda/layerVersion:LayerVersion",
expectedFile: "test_data/parse-imports/lambdalayer-expected.md",
},
{
input: readlines(t, "test_data/parse-imports/docker_container.md"),
token: "docker:index/container:Container",
expectedFile: "test_data/parse-imports/docker_container-expected.md",
},
}

for _, tt := range tests {
Expand Down
38 changes: 38 additions & 0 deletions pkg/tfgen/test_data/convertExamples/docker_container.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Import is supported using the following syntax by providing the `id`:

```shell
#!/bin/bash
terraform import docker_container.foo id
```

### Example

Assuming you created a `container` as follows

```shell
#!/bin/bash
docker run --name foo -p8080:80 -d nginx
# prints the container ID
9a550c0f0163d39d77222d3efd58701b625d47676c25c686c95b5b92d1cba6fd
```

you provide the definition for the resource as follows

```terraform
resource "docker_container" "foo" {
name = "foo"
image = "nginx"

ports {
internal = "80"
external = "8080"
}
}
```

then the import command is as follows

```shell
#!/bin/bash
terraform import docker_container.foo 9a550c0f0163d39d77222d3efd58701b625d47676c25c686c95b5b92d1cba6fd
```
39 changes: 39 additions & 0 deletions pkg/tfgen/test_data/parse-imports/docker_container-expected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Import

```sh
#!/bin/bash
$ pulumi import docker:index/container:Container foo id
```

### Example

Assuming you created a `container` as follows

```sh
#!/bin/bash
docker run --name foo -p8080:80 -d nginx
# prints the container ID
9a550c0f0163d39d77222d3efd58701b625d47676c25c686c95b5b92d1cba6fd
```

you provide the definition for the resource as follows

```terraform
guineveresaenger marked this conversation as resolved.
Show resolved Hide resolved
resource "docker_container" "foo" {
name = "foo"
image = "nginx"

ports {
internal = "80"
external = "8080"
}
}
```

then the import command is as follows

```sh
#!/bin/bash
$ pulumi import docker:index/container:Container foo 9a550c0f0163d39d77222d3efd58701b625d47676c25c686c95b5b92d1cba6fd
```

38 changes: 38 additions & 0 deletions pkg/tfgen/test_data/parse-imports/docker_container.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
Import is supported using the following syntax by providing the `id`:

```shell
#!/bin/bash
terraform import docker_container.foo id
```

### Example

Assuming you created a `container` as follows

```shell
#!/bin/bash
docker run --name foo -p8080:80 -d nginx
# prints the container ID
9a550c0f0163d39d77222d3efd58701b625d47676c25c686c95b5b92d1cba6fd
```

you provide the definition for the resource as follows

```terraform
resource "docker_container" "foo" {
name = "foo"
image = "nginx"

ports {
internal = "80"
external = "8080"
}
}
```

then the import command is as follows

```shell
#!/bin/bash
terraform import docker_container.foo 9a550c0f0163d39d77222d3efd58701b625d47676c25c686c95b5b92d1cba6fd
```