-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
✨ new: Adds the basic functionality to update plugins (#1)
- Loading branch information
Showing
11 changed files
with
843 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
repos: | ||
- repo: https://github.com/pre-commit/pre-commit-hooks | ||
rev: 2c9f875913ee60ca25ce70243dc24d5b6415598c # frozen: v4.6.0 | ||
hooks: | ||
- id: check-added-large-files | ||
- id: check-case-conflict | ||
- id: check-executables-have-shebangs | ||
- id: check-json | ||
- id: check-toml | ||
- id: check-yaml | ||
- id: detect-aws-credentials | ||
- id: detect-private-key | ||
- id: end-of-file-fixer | ||
- id: trailing-whitespace | ||
|
||
- repo: https://github.com/gitleaks/gitleaks | ||
rev: 77c3c6a34b2577d71083442326c60b8fd58926ec # frozen: v8.18.4 | ||
hooks: | ||
- id: gitleaks | ||
|
||
- repo: https://github.com/executablebooks/mdformat | ||
rev: 08fba30538869a440b5059de90af03e3502e35fb # frozen: 0.7.17 | ||
hooks: | ||
- id: mdformat | ||
|
||
- repo: https://github.com/igorshubovych/markdownlint-cli | ||
rev: f295829140d25717bc79368d3f966fc1f67a824f # frozen: v0.41.0 | ||
hooks: | ||
- id: markdownlint-fix-docker | ||
|
||
- repo: https://github.com/golangci/golangci-lint | ||
rev: c2e095c022a97360f7fff5d49fbc11f273be929a # frozen: v1.60.3 | ||
hooks: | ||
- id: golangci-lint |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
package main | ||
|
||
import ( | ||
"os" | ||
"strings" | ||
|
||
"github.com/alecthomas/kong" | ||
"github.com/hashicorp/hcl/v2/hclwrite" | ||
"github.com/spf13/afero" | ||
|
||
"github.com/bendoerr-terraform-modules/tflint-plugin-version-update/pkg/github" | ||
"github.com/bendoerr-terraform-modules/tflint-plugin-version-update/pkg/tflint" | ||
) | ||
|
||
type Config struct { | ||
Freeze bool `name:"freeze"` | ||
Path string `name:"path" arg:"" type:"path"` | ||
} | ||
|
||
func main() { | ||
var err error | ||
var cfg Config | ||
|
||
_ = kong.Parse(&cfg) | ||
|
||
tflFile, err := tflint.OpenConfig(afero.Afero{Fs: afero.NewOsFs()}, cfg.Path) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
tflData, err := tflint.NewData(tflFile) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
tflHcl, err := tflData.ParseForRead() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
tflHclW, err := tflData.ParseForWrite() | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
plugins, err := tflint.FindPluginVersions(tflHcl) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
runUpdate(plugins, cfg, tflHclW) | ||
|
||
_, _ = tflHclW.WriteTo(os.Stdout) | ||
} | ||
|
||
func runUpdate(plugins []*tflint.PluginConfig, cfg Config, tflHclW *hclwrite.File) { | ||
for _, plugin := range plugins { | ||
latestVersion, err := github.LatestVersion(plugin.SourceOwner, plugin.SourceRepo) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
if cfg.Freeze { | ||
if plugin.Version == latestVersion.ReleaseSHA { | ||
continue | ||
} | ||
} else { | ||
if plugin.Version == latestVersion.ReleaseTag || "v"+plugin.Version == latestVersion.ReleaseTag { | ||
continue | ||
} | ||
} | ||
|
||
if cfg.Freeze { | ||
err = tflint.UpdatePluginVersion(plugin.Name, latestVersion.ReleaseSHA, latestVersion.ReleaseTag, tflHclW) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} else { | ||
// Stylistically tflint drops the 'v' in their documentation, | ||
// so we'll follow that as well. | ||
version := strings.TrimPrefix(latestVersion.ReleaseTag, "v") | ||
err = tflint.UpdatePluginVersion(plugin.Name, version, "", tflHclW) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
module github.com/bendoerr-terraform-modules/tflint-plugin-version-update | ||
|
||
go 1.23.0 | ||
|
||
require ( | ||
github.com/alecthomas/kong v0.9.0 | ||
github.com/hashicorp/hcl/v2 v2.22.0 | ||
github.com/kr/pretty v0.3.1 | ||
github.com/spf13/afero v1.11.0 | ||
) | ||
|
||
require ( | ||
github.com/agext/levenshtein v1.2.1 // indirect | ||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect | ||
github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect | ||
github.com/google/go-cmp v0.6.0 // indirect | ||
github.com/kr/text v0.2.0 // indirect | ||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 // indirect | ||
github.com/rogpeppe/go-internal v1.9.0 // indirect | ||
github.com/zclconf/go-cty v1.13.0 // indirect | ||
golang.org/x/mod v0.17.0 // indirect | ||
golang.org/x/sync v0.8.0 // indirect | ||
golang.org/x/text v0.17.0 // indirect | ||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
github.com/agext/levenshtein v1.2.1 h1:QmvMAjj2aEICytGiWzmxoE0x2KZvE0fvmqMOfy2tjT8= | ||
github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= | ||
github.com/alecthomas/assert/v2 v2.6.0 h1:o3WJwILtexrEUk3cUVal3oiQY2tfgr/FHWiz/v2n4FU= | ||
github.com/alecthomas/assert/v2 v2.6.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= | ||
github.com/alecthomas/kong v0.9.0 h1:G5diXxc85KvoV2f0ZRVuMsi45IrBgx9zDNGNj165aPA= | ||
github.com/alecthomas/kong v0.9.0/go.mod h1:Y47y5gKfHp1hDc7CH7OeXgLIpp+Q2m1Ni0L5s3bI8Os= | ||
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= | ||
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= | ||
github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= | ||
github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= | ||
github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew1u1fNQOlOtuGxQY= | ||
github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= | ||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= | ||
github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= | ||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= | ||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= | ||
github.com/hashicorp/hcl/v2 v2.22.0 h1:hkZ3nCtqeJsDhPRFz5EA9iwcG1hNWGePOTw6oyul12M= | ||
github.com/hashicorp/hcl/v2 v2.22.0/go.mod h1:62ZYHrXgPoX8xBnzl8QzbWq4dyDsDtfCRgIq1rbJEvA= | ||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= | ||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= | ||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | ||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= | ||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= | ||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= | ||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= | ||
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= | ||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= | ||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= | ||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= | ||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8= | ||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY= | ||
github.com/zclconf/go-cty v1.13.0 h1:It5dfKTTZHe9aeppbNOda3mN7Ag7sg6QkBNm6TkyFa0= | ||
github.com/zclconf/go-cty v1.13.0/go.mod h1:YKQzy/7pZ7iq2jNFzy5go57xdxdWoLLpaEp4u238AE0= | ||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940 h1:4r45xpDWB6ZMSMNJFMOjqrGHynW3DIBuR2H9j0ug+Mo= | ||
github.com/zclconf/go-cty-debug v0.0.0-20240509010212-0d6042c53940/go.mod h1:CmBdvvj3nqzfzJ6nTCIwDTPZ56aVGvDrmztiO5g3qrM= | ||
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= | ||
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= | ||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= | ||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= | ||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= | ||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= | ||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= | ||
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package github | ||
|
||
import ( | ||
"context" | ||
"encoding/json" | ||
"fmt" | ||
"net/http" | ||
"time" | ||
) | ||
|
||
type Latest struct { | ||
ReleaseTag string | ||
ReleaseSHA string | ||
ReleaseDescription string | ||
} | ||
|
||
type latestResponse struct { | ||
TagName string `json:"tag_name"` | ||
Description string `json:"body"` | ||
} | ||
|
||
type tagResponse struct { | ||
Object struct { | ||
SHA string `json:"sha"` | ||
} `json:"object"` | ||
} | ||
|
||
func get(owner, repo, path string) (*http.Response, error) { | ||
ctx, cancel := context.WithTimeout(context.Background(), time.Minute) | ||
defer cancel() | ||
|
||
url := fmt.Sprintf("https://api.github.com/repos/%s/%s/%s", owner, repo, path) | ||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed create request: %w", err) | ||
} | ||
|
||
resp, err := http.DefaultClient.Do(req) | ||
if err != nil { | ||
_ = resp.Body.Close() | ||
return nil, fmt.Errorf("failed request to Github API at URL='%s', %w", url, err) | ||
} | ||
|
||
if resp.StatusCode >= http.StatusMultipleChoices { | ||
_ = resp.Body.Close() | ||
return nil, fmt.Errorf("failed request to Github API at URL='%s' with StatusCode='%d'", url, resp.StatusCode) | ||
} | ||
|
||
return resp, nil | ||
} | ||
|
||
func getLatest(owner, repo string) (*latestResponse, error) { | ||
resp, err := get(owner, repo, "releases/latest") | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
result := &latestResponse{} | ||
err = json.NewDecoder(resp.Body).Decode(&result) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to decode latest releaes response: %w", err) | ||
} | ||
|
||
return result, nil | ||
} | ||
|
||
func getTag(owner, repo, tag string) (*tagResponse, error) { | ||
resp, err := get(owner, repo, "git/ref/tags/"+tag) | ||
if err != nil { | ||
return nil, err | ||
} | ||
defer resp.Body.Close() | ||
|
||
result := &tagResponse{} | ||
err = json.NewDecoder(resp.Body).Decode(&result) | ||
if err != nil { | ||
return nil, fmt.Errorf("failed to decode tag response: %w", err) | ||
} | ||
|
||
return result, nil | ||
} | ||
|
||
func LatestVersion(owner, repo string) (*Latest, error) { | ||
release, err := getLatest(owner, repo) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
tag, err := getTag(owner, repo, release.TagName) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &Latest{ | ||
ReleaseTag: release.TagName, | ||
ReleaseSHA: tag.Object.SHA, | ||
ReleaseDescription: release.Description, | ||
}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
package tflint | ||
|
||
import ( | ||
"github.com/hashicorp/hcl/v2" | ||
"github.com/hashicorp/hcl/v2/hclsyntax" | ||
"github.com/hashicorp/hcl/v2/hclwrite" | ||
"github.com/spf13/afero" | ||
) | ||
|
||
type Data struct { | ||
Bytes []byte | ||
Filename string | ||
} | ||
|
||
func NewData(file afero.File) (*Data, error) { | ||
d := &Data{} | ||
var err error | ||
d.Filename = file.Name() | ||
d.Bytes, err = afero.ReadAll(file) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return d, nil | ||
} | ||
|
||
func (d *Data) ParseForRead() (*hcl.File, error) { | ||
f, diag := hclsyntax.ParseConfig(d.Bytes, d.Filename, hcl.InitialPos) | ||
if diag.HasErrors() { | ||
return nil, diag | ||
} | ||
return f, nil | ||
} | ||
|
||
func (d *Data) ParseForWrite() (*hclwrite.File, error) { | ||
f, diag := hclwrite.ParseConfig(d.Bytes, d.Filename, hcl.InitialPos) | ||
if diag.HasErrors() { | ||
return nil, diag | ||
} | ||
return f, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package tflint | ||
|
||
import ( | ||
"github.com/hashicorp/hcl/v2" | ||
"github.com/hashicorp/hcl/v2/gohcl" | ||
) | ||
|
||
func FindPluginVersions(file *hcl.File) ([]*PluginConfig, error) { | ||
var plugins []*PluginConfig | ||
|
||
var configSchema = &hcl.BodySchema{ | ||
Blocks: []hcl.BlockHeaderSchema{ | ||
{ | ||
Type: "plugin", | ||
LabelNames: []string{"name"}, | ||
}, | ||
}, | ||
} | ||
|
||
content, diag := file.Body.Content(configSchema) | ||
if diag.HasErrors() { | ||
return nil, diag | ||
} | ||
|
||
for _, block := range content.Blocks { | ||
if block.Type == "plugin" { | ||
pluginConfig := &PluginConfig{Name: block.Labels[0]} | ||
if err := gohcl.DecodeBody(block.Body, nil, pluginConfig); err != nil { | ||
return nil, err | ||
} | ||
if err := pluginConfig.Validate(); err != nil { | ||
return nil, err | ||
} | ||
plugins = append(plugins, pluginConfig) | ||
} | ||
} | ||
|
||
return plugins, nil | ||
} |
Oops, something went wrong.