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

Adds a new markdown representation of example conversion failures #619

Merged
merged 9 commits into from Dec 6, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
48 changes: 26 additions & 22 deletions pkg/tfgen/docs.go
Expand Up @@ -18,9 +18,6 @@ import (
"bytes"
"encoding/json"
"fmt"
"github.com/hashicorp/go-multierror"
"golang.org/x/text/cases"
"golang.org/x/text/language"
"io"
"os"
"os/exec"
Expand All @@ -30,6 +27,10 @@ import (
"strings"
"sync"

"github.com/hashicorp/go-multierror"
"golang.org/x/text/cases"
"golang.org/x/text/language"

"github.com/pulumi/pulumi-terraform-bridge/v3/pkg/tf2pulumi/gen/python"
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
"github.com/spf13/afero"
Expand Down Expand Up @@ -1246,7 +1247,7 @@ func (g *Generator) convertHCLToString(hcl, path, languageName string) (string,
convertedHcl = strings.TrimSpace(string(output))
}

g.coverageTracker.languageConversionSuccess(languageName)
g.coverageTracker.languageConversionSuccess(languageName, convertedHcl)
return convertedHcl, nil
}

Expand Down Expand Up @@ -1356,10 +1357,14 @@ func (g *Generator) convertHCL(hcl, path, exampleTitle string, languages []strin
}

result.WriteString(hclConversionsToString(hclConversions))
if len(failedLangs) == 0 {
return result.String(), nil
}

if len(failedLangs) == len(languages) {
hclAllLangsConversionFailures++
isCompleteFailure := len(failedLangs) == len(languages)

if isCompleteFailure {
hclAllLangsConversionFailures++
if exampleTitle == "" {
g.warn(fmt.Sprintf("unable to convert HCL example for Pulumi entity '%s': %v. The example will be dropped "+
"from any generated docs or SDKs.", path, err))
Expand All @@ -1372,22 +1377,20 @@ func (g *Generator) convertHCL(hcl, path, exampleTitle string, languages []strin
}

// Log the results when an example fails to convert to some languages, but not all
if len(failedLangs) > 0 && len(failedLangs) < len(languages) {
var failedLangsStrings []string

for lang := range failedLangs {
failedLangsStrings = append(failedLangsStrings, lang)

switch lang {
case convert.LanguageTypescript:
hclTypeScriptPartialConversionFailures++
case convert.LanguagePython:
hclPythonPartialConversionFailures++
case convert.LanguageCSharp:
hclCSharpPartialConversionFailures++
case convert.LanguageGo:
hclGoPartialConversionFailures++
}
var failedLangsStrings []string

for lang := range failedLangs {
failedLangsStrings = append(failedLangsStrings, lang)

switch lang {
case convert.LanguageTypescript:
hclTypeScriptPartialConversionFailures++
case convert.LanguagePython:
hclPythonPartialConversionFailures++
case convert.LanguageCSharp:
hclCSharpPartialConversionFailures++
case convert.LanguageGo:
hclGoPartialConversionFailures++
}

if exampleTitle == "" {
Expand All @@ -1403,6 +1406,7 @@ func (g *Generator) convertHCL(hcl, path, exampleTitle string, languages []strin
// At least one language out of the given set has been generated, which is considered a success
// nolint:ineffassign
err = nil

dixler marked this conversation as resolved.
Show resolved Hide resolved
}

return result.String(), nil
Expand Down
118 changes: 118 additions & 0 deletions pkg/tfgen/examples_coverage_exporter.go
Expand Up @@ -56,6 +56,10 @@ func (ce *coverageExportUtil) tryExport(outputDirectory string) error {
if err != nil {
return err
}
err = ce.exportMarkdown(outputDirectory, "summary.md")
if err != nil {
return err
}
return ce.exportHumanReadable(outputDirectory, "shortSummary.txt")
}

Expand Down Expand Up @@ -294,6 +298,120 @@ func (ce *coverageExportUtil) exportOverall(outputDirectory string, fileName str
return marshalAndWriteJSON(providerStatistic, jsonOutputLocation)
}

// The fifth mode, which provides outputs a markdown file with:
// - the example's name
// - the original HCL
// - the conversion results for all languages
func (ce *coverageExportUtil) exportMarkdown(outputDirectory string, fileName string) error {

// The Coverage Tracker data structure is flattened down to the example level, and they all
// get individually written to the file in order to not have the "{ }" brackets at the start and end
type FlattenedExample struct {
ExampleName string
OriginalHCL string `json:"OriginalHCL,omitempty"`
ConversionResults map[string]*LanguageConversionResult
}

// All the examples in the tracker are iterated by page ID + index, and marshalled into one large byte
// array separated by \n, making the end result look like a bunch of Json files that got concatenated
var brokenExamples []FlattenedExample

for _, page := range ce.Tracker.EncounteredPages {
for index, example := range page.Examples {
flattenedName := page.Name
if len(page.Examples) > 1 {
flattenedName += fmt.Sprintf("#%d", index)
}

noErrors := true
for _, result := range example.ConversionResults {
if result.FailureSeverity == Success {
continue
}
noErrors = false
}
if noErrors {
break
}

brokenExamples = append(brokenExamples, FlattenedExample{
ExampleName: flattenedName,
OriginalHCL: example.OriginalHCL,
ConversionResults: example.ConversionResults,
})
}
}
targetFile, err := createEmptyFile(outputDirectory, fileName)
if err != nil {
return err
}

out := ""
for _, example := range brokenExamples {

successes := make(map[string]LanguageConversionResult)
failures := make(map[string]LanguageConversionResult)

for lang, result := range example.ConversionResults {
if result.FailureSeverity == Success {
successes[lang] = *result
continue
}
failures[lang] = *result
}

isCompleteFailure := len(successes) == 0

// print example header
summaryText := "*partial failure*"
if isCompleteFailure {
summaryText = "**complete failure**"
}

out += "\n---\n"
out += fmt.Sprintf("\n## [%s] %s\n", summaryText, example.ExampleName)

// print original HCL
out += "\n### HCL\n"
out += "\n```terraform\n"
out += example.OriginalHCL + "\n"
out += "\n```\n"

// print failures
out += "\n### Failed Languages\n"
for lang, err := range failures {
out += fmt.Sprintf("\n#### %s\n", lang)
out += "\n```text\n"

errMsg := err.FailureInfo
if len(err.FailureInfo) > 1000 {
// truncate extremely long error messages
errMsg = err.FailureInfo[:1000]
}
out += errMsg
out += "\n```\n"
}

if isCompleteFailure {
// it's a complete failure, no successes to print
continue
}

// print successes
out += "\n### Successes\n"
for lang, success := range successes {
out += "\n<details>\n"
out += fmt.Sprintf("\n<summary>%s</summary>\n", lang)
out += fmt.Sprintf("\n```%s\n", lang)
out += success.Program
out += "\n```\n"
out += "\n</details>\n"
}
}

return os.WriteFile(targetFile, []byte(out), 0600)
}

// The fourth mode, which simply gives the provider name, and success percentage.
func (ce *coverageExportUtil) exportHumanReadable(outputDirectory string, fileName string) error {

Expand Down
4 changes: 3 additions & 1 deletion pkg/tfgen/examples_coverage_tracker.go
Expand Up @@ -76,6 +76,7 @@ type Example struct {
type LanguageConversionResult struct {
FailureSeverity int // This conversion's outcome: [Success, Warning, Failure, Fatal]
FailureInfo string // Additional in-depth information
Program string // Converted program

// How many times this example has been converted to this language.
// It is expected that this will be equal to 1.
Expand Down Expand Up @@ -116,14 +117,15 @@ func (ct *CoverageTracker) foundExample(pageName string, hcl string) {
}

// Used when: current example has been successfully converted to a certain language
func (ct *CoverageTracker) languageConversionSuccess(languageName string) {
func (ct *CoverageTracker) languageConversionSuccess(languageName string, program string) {
if ct == nil {
return
}
ct.insertLanguageConversionResult(languageName, LanguageConversionResult{
FailureSeverity: Success,
FailureInfo: "",
TranslationCount: 1,
Program: program,
})
}

Expand Down