diff --git a/.github/workflows/code-health.yml b/.github/workflows/code-health.yml index 9005a20..befc4db 100644 --- a/.github/workflows/code-health.yml +++ b/.github/workflows/code-health.yml @@ -46,9 +46,9 @@ jobs: go-version-file: 'go.mod' cache: false # see https://github.com/golangci/golangci-lint-action/issues/807 - name: golangci-lint - uses: golangci/golangci-lint-action@55c2c1448f86e01eaae002a5a3a9624417608d84 + uses: golangci/golangci-lint-action@1481404843c368bc19ca9406f87d6e0fc97bdcfd with: - version: v1.64.7 # Also update GOLANGCI_VERSION variable in GNUmakefile when updating this version + version: v2.0.2 # Also update GOLANGCI_VERSION variable in GNUmakefile when updating this version - name: actionlint run: | make tools diff --git a/.golangci.yml b/.golangci.yml index db8910f..18f77ef 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -1,107 +1,96 @@ -linters-settings: - gocritic: - enabled-tags: - - diagnostic - - experimental - - opinionated - - performance - - style - govet: - enable-all: true - - revive: - # see https://github.com/mgechev/revive#available-rules for details. - ignore-generated-header: true - severity: warning - rules: - - name: blank-imports - - name: context-as-argument - - name: context-keys-type - - name: dot-imports - - name: error-return - - name: error-strings - - name: error-naming - - name: errorf - - name: exported - - name: indent-error-flow - - name: if-return - - name: increment-decrement - - name: var-naming - - name: var-declaration - - name: package-comments - - name: range - - name: receiver-naming - - name: time-naming - - name: unexported-return - - name: indent-error-flow - - name: errorf - - name: empty-block - - name: superfluous-else - - name: struct-tag - # Too many unusued parameters, skipping this check for now - #- name: unused-parameter - - name: unreachable-code - - name: redefines-builtin-id - misspell: - locale: US - ignore-words: - - cancelled - lll: - # Default is 120. '\t' is counted as 1 character. - # set our project to 500, as we are adding open api field description in the schema. - # also, for anyone using vscode, use the following configs: - # "rewrap.wrappingColumn": 500 ... requires the rewrap plugin - # "editor.rulers": [500] - line-length: 500 - nestif: - # minimal complexity of if statements to report, 5 by default - min-complexity: 7 - mnd: - checks: - - case - - operation - - return - funlen: - lines: 360 - statements: 120 +version: "2" +run: + modules-download-mode: readonly + tests: true linters: - disable-all: true + default: none enable: + - copyloopvar - dogsled - errcheck + - exhaustive - funlen - gocritic - - gofmt - - goimports - - revive - - mnd - goprintffuncname - gosec - - gosimple - govet - ineffassign - lll + - makezero - misspell + - mnd - nakedret + - noctx - nolintlint + - revive - rowserrcheck - - copyloopvar - staticcheck - - stylecheck - - typecheck - - unconvert - - unused - - whitespace - - thelper - testifylint - - exhaustive - - makezero - - noctx - testpackage + - thelper + - unconvert + - unused - usetesting -run: - timeout: 10m - tests: true - build-tags: - - integration - modules-download-mode: readonly + - whitespace + settings: + funlen: + lines: 360 + statements: 120 + gocritic: + enabled-tags: + - diagnostic + - experimental + - opinionated + - performance + - style + govet: + enable-all: true + misspell: + locale: US + mnd: + checks: + - case + - operation + - return + nestif: + min-complexity: 7 + revive: + severity: warning + rules: + - name: blank-imports + - name: context-as-argument + - name: context-keys-type + - name: dot-imports + - name: error-return + - name: error-strings + - name: error-naming + - name: errorf + - name: exported + - name: indent-error-flow + - name: if-return + - name: increment-decrement + - name: var-naming + - name: var-declaration + - name: package-comments + - name: range + - name: receiver-naming + - name: time-naming + - name: unexported-return + - name: indent-error-flow + - name: errorf + - name: empty-block + - name: superfluous-else + - name: struct-tag + - name: unreachable-code + - name: redefines-builtin-id + exclusions: + generated: lax + presets: + - comments + - common-false-positives + - legacy + - std-error-handling +formatters: + enable: + - gofmt + - goimports diff --git a/Makefile b/Makefile index 124838b..afdebdf 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ CLI_DESTINATION=./bin/$(CLI_BINARY_NAME) MANIFEST_FILE?=./bin/manifest.yml WIN_MANIFEST_FILE?=./bin/manifest.windows.yml -GOLANGCI_VERSION=v1.64.7 # Also update golangci-lint GH action in code-health.yml when updating this version +GOLANGCI_VERSION=v2.0.2 # Also update golangci-lint GH action in code-health.yml when updating this version .PHONY: build build: ## Generate the binary in ./bin diff --git a/internal/cli/clu2adv/clu2adv.go b/internal/cli/clu2adv/clu2adv.go index 691a5d3..68bbb9d 100644 --- a/internal/cli/clu2adv/clu2adv.go +++ b/internal/cli/clu2adv/clu2adv.go @@ -9,9 +9,10 @@ import ( func Builder() *cobra.Command { o := &opts{fs: afero.NewOsFs()} cmd := &cobra.Command{ - Use: "clusterToAdvancedCluster", - Short: "Convert cluster to advanced_cluster preview provider 2.0.0", - Long: "Convert a Terraform configuration from mongodbatlas_cluster to mongodbatlas_advanced_cluster preview provider 2.0.0", + Use: "clusterToAdvancedCluster", + Short: "Convert cluster to advanced_cluster preview provider 2.0.0", + Long: "Convert a Terraform configuration from mongodbatlas_cluster to " + + "mongodbatlas_advanced_cluster preview provider 2.0.0", Aliases: []string{"clu2adv"}, RunE: func(_ *cobra.Command, _ []string) error { if err := o.PreRun(); err != nil { @@ -24,8 +25,11 @@ func Builder() *cobra.Command { _ = cmd.MarkFlagRequired(flag.File) cmd.Flags().StringVarP(&o.output, flag.Output, flag.OutputShort, "", "output file") _ = cmd.MarkFlagRequired(flag.Output) - cmd.Flags().BoolVarP(&o.replaceOutput, flag.ReplaceOutput, flag.ReplaceOutputShort, false, "replace output file if exists") - cmd.Flags().BoolVarP(&o.watch, flag.Watch, flag.WatchShort, false, "keeps the plugin running and watches the input file for changes") - cmd.Flags().BoolVarP(&o.includeMoved, flag.IncludeMoved, flag.IncludeMovedShort, false, "include moved blocks in the output file") + cmd.Flags().BoolVarP(&o.replaceOutput, flag.ReplaceOutput, flag.ReplaceOutputShort, false, + "replace output file if exists") + cmd.Flags().BoolVarP(&o.watch, flag.Watch, flag.WatchShort, false, + "keeps the plugin running and watches the input file for changes") + cmd.Flags().BoolVarP(&o.includeMoved, flag.IncludeMoved, flag.IncludeMovedShort, false, + "include moved blocks in the output file") return cmd } diff --git a/internal/convert/convert.go b/internal/convert/convert.go index 23b2d32..ca76441 100644 --- a/internal/convert/convert.go +++ b/internal/convert/convert.go @@ -48,7 +48,8 @@ type attrVals struct { // ClusterToAdvancedCluster transforms all mongodbatlas_cluster definitions in a // Terraform configuration file into mongodbatlas_advanced_cluster schema 2.0.0. // All other resources and data sources are left untouched. -// Note: hclwrite.Tokens are used instead of cty.Value so expressions with interpolations like var.region can be preserved. +// Note: hclwrite.Tokens are used instead of cty.Value so expressions with +// interpolations like var.region can be preserved. // cty.Value only supports literal expressions. func ClusterToAdvancedCluster(config []byte, includeMoved bool) ([]byte, error) { var moveLabels []string @@ -216,7 +217,7 @@ func fillReplicationSpecs(resourceb *hclwrite.Body, root attrVals) error { break } specbSrc := specSrc.Body() - d, err := fillReplicationSpecsWithDynamicRegionConfigs(specbSrc, root, false) + d, err := fillWithDynamicRegionConfigs(specbSrc, root, false) if err != nil { return err } @@ -333,7 +334,7 @@ func fillReplicationSpecsWithDynamicBlock(resourceb *hclwrite.Body, root attrVal return dynamicBlock{}, err } transformDynamicBlockReferences(dSpec.content.Body(), nRepSpecs, nSpec) - dConfig, err := fillReplicationSpecsWithDynamicRegionConfigs(dSpec.content.Body(), root, true) + dConfig, err := fillWithDynamicRegionConfigs(dSpec.content.Body(), root, true) if err != nil { return dynamicBlock{}, err } @@ -344,8 +345,8 @@ func fillReplicationSpecsWithDynamicBlock(resourceb *hclwrite.Body, root attrVal return dSpec, nil } -// fillReplicationSpecsWithDynamicRegionConfigs is used for dynamic blocks in region_configs -func fillReplicationSpecsWithDynamicRegionConfigs(specbSrc *hclwrite.Body, root attrVals, transformRegionReferences bool) (dynamicBlock, error) { +// fillWithDynamicRegionConfigs is used for dynamic blocks in region_configs +func fillWithDynamicRegionConfigs(specbSrc *hclwrite.Body, root attrVals, changeReferences bool) (dynamicBlock, error) { d, err := getDynamicBlock(specbSrc, nConfigSrc) if err != nil || !d.IsPresent() { return dynamicBlock{}, err @@ -356,15 +357,16 @@ func fillReplicationSpecsWithDynamicRegionConfigs(specbSrc *hclwrite.Body, root repSpecb.SetAttributeRaw(nZoneName, hcl.TokensFromExpr(zoneName)) } forEach := hcl.GetAttrExpr(d.forEach) - if transformRegionReferences { + if changeReferences { forEach = replaceDynamicBlockReferences(forEach, nRepSpecs, nSpec) } - regionFor, err := getDynamicBlockRegionConfigsRegionArray(forEach, d.content, root) + regionFor, err := getDynamicBlockRegionArray(forEach, d.content, root) if err != nil { return dynamicBlock{}, err } + priorityForStr := fmt.Sprintf("for %s in range(%d, %d, -1) : ", nPriority, valMaxPriority, valMinPriority) priorityFor := hcl.TokensComment(commentPriorityFor) - priorityFor = append(priorityFor, hcl.TokensFromExpr(fmt.Sprintf("for %s in range(%d, %d, -1) : ", nPriority, valMaxPriority, valMinPriority))...) + priorityFor = append(priorityFor, hcl.TokensFromExpr(priorityForStr)...) priorityFor = append(priorityFor, regionFor...) repSpecb.SetAttributeRaw(nConfig, hcl.TokensFuncFlatten(priorityFor)) @@ -410,13 +412,13 @@ func getRegionConfig(configSrc *hclwrite.Block, root attrVals, isDynamicBlock bo if err := hcl.MoveAttr(configSrc.Body(), fileb, nPriority, nPriority, errRepSpecs); err != nil { return nil, err } - if electable, _ := getSpecs(configSrc, nElectableNodes, root, isDynamicBlock); electable != nil { + if electable, _ := getSpec(configSrc, nElectableNodes, root, isDynamicBlock); electable != nil { fileb.SetAttributeRaw(nElectableSpecs, electable) } - if readOnly, _ := getSpecs(configSrc, nReadOnlyNodes, root, isDynamicBlock); readOnly != nil { + if readOnly, _ := getSpec(configSrc, nReadOnlyNodes, root, isDynamicBlock); readOnly != nil { fileb.SetAttributeRaw(nReadOnlySpecs, readOnly) } - if analytics, _ := getSpecs(configSrc, nAnalyticsNodes, root, isDynamicBlock); analytics != nil { + if analytics, _ := getSpec(configSrc, nAnalyticsNodes, root, isDynamicBlock); analytics != nil { fileb.SetAttributeRaw(nAnalyticsSpecs, analytics) } if autoScaling := getAutoScalingOpt(root.opt); autoScaling != nil { @@ -425,7 +427,7 @@ func getRegionConfig(configSrc *hclwrite.Block, root attrVals, isDynamicBlock bo return file, nil } -func getSpecs(configSrc *hclwrite.Block, countName string, root attrVals, isDynamicBlock bool) (hclwrite.Tokens, error) { +func getSpec(configSrc *hclwrite.Block, countName string, root attrVals, isDynamicBlock bool) (hclwrite.Tokens, error) { var ( file = hclwrite.NewEmptyFile() fileb = file.Body() @@ -556,9 +558,9 @@ func replaceDynamicBlockExpr(attr *hclwrite.Attribute, blockName, attrName strin return strings.ReplaceAll(expr, fmt.Sprintf("%s.%s", blockName, attrName), attrName) } -// getDynamicBlockRegionConfigsRegionArray returns the region array for a dynamic block in replication_specs. +// getDynamicBlockRegionArray returns the region array for a dynamic block in replication_specs. // e.g. [ for region in var.replication_specs.regions_config : { ... } if priority == region.priority ] -func getDynamicBlockRegionConfigsRegionArray(forEach string, configSrc *hclwrite.Block, root attrVals) (hclwrite.Tokens, error) { +func getDynamicBlockRegionArray(forEach string, configSrc *hclwrite.Block, root attrVals) (hclwrite.Tokens, error) { transformDynamicBlockReferences(configSrc.Body(), nConfigSrc, nRegion) priorityStr := hcl.GetAttrExpr(configSrc.Body().GetAttribute(nPriority)) if priorityStr == "" { @@ -581,7 +583,8 @@ func transformDynamicBlockReferences(configSrcb *hclwrite.Body, blockName, varNa } } -// replaceDynamicBlockReferences changes value references, e.g. regions_config.value.electable_nodes to region.electable_nodes +// replaceDynamicBlockReferences changes value references, +// e.g. regions_config.value.electable_nodes to region.electable_nodes func replaceDynamicBlockReferences(expr, blockName, varName string) string { return strings.ReplaceAll(expr, fmt.Sprintf("%s.%s.", blockName, nValue), @@ -606,7 +609,8 @@ func setKeyValue(body *hclwrite.Body, key, value *hclwrite.Attribute) { keyStr, err := hcl.GetAttrString(key, "") if err == nil { if !hclsyntax.ValidIdentifier(keyStr) { - keyStr = strconv.Quote(keyStr) // wrap in quotes so invalid identifiers (e.g. with blanks) can be used as attribute names + // wrap in quotes so invalid identifiers (e.g. with blanks) can be used as attribute names + keyStr = strconv.Quote(keyStr) } } else { keyStr = strings.TrimSpace(string(key.Expr().BuildTokens(nil).Bytes()))