From 9ce0875cae41ec0ed8eca00cbaad1eb2c679f296 Mon Sep 17 00:00:00 2001 From: "Giau. Tran Minh" Date: Tue, 24 Dec 2024 02:23:16 +0700 Subject: [PATCH] chore: codegen for doc Co-authored-by: Rotem Tamir --- atlasaction/action.go | 17 ++- atlasaction/bitbucket.go | 2 +- atlasaction/circleci_action.go | 4 +- atlasaction/gen/actions.go | 112 ++++++++++++++ atlasaction/gen/templates.go | 132 +++++++++++++++++ atlasaction/gitlab_ci.go | 2 +- tools/gen/go.mod | 33 +++++ tools/gen/go.sum | 89 +++++++++++ tools/gen/main.go | 31 ++++ tools/gen/template/bitbucket.md | 254 ++++++++++++++++++++++++++++++++ tools/gen/template/github.md | 19 +++ 11 files changed, 685 insertions(+), 10 deletions(-) create mode 100644 atlasaction/gen/actions.go create mode 100644 atlasaction/gen/templates.go create mode 100644 tools/gen/go.mod create mode 100644 tools/gen/go.sum create mode 100644 tools/gen/main.go create mode 100644 tools/gen/template/bitbucket.md create mode 100644 tools/gen/template/github.md diff --git a/atlasaction/action.go b/atlasaction/action.go index 873eff9..ed0ed84 100644 --- a/atlasaction/action.go +++ b/atlasaction/action.go @@ -1240,23 +1240,28 @@ func RenderTemplate(name string, data any) (string, error) { return buf.String(), nil } -// toEnvName converts the given string to an environment variable name. -func toEnvName(s string) string { +// ToEnvName converts the given string to an environment variable name. +func ToEnvName(s string) string { return strings.ToUpper(strings.NewReplacer( " ", "_", "-", "_", "/", "_", ).Replace(s)) } -// toInputVarName converts the given string to an input variable name. -func toInputVarName(input string) string { - return fmt.Sprintf("ATLAS_INPUT_%s", toEnvName(input)) +// ToInputVarName converts the given string to an input variable name. +func ToInputVarName(input string) string { + return "ATLAS_INPUT_" + ToEnvName(input) +} + +// ToInputVarName converts the given string to an input variable name. +func ToOutputVarName(action, output string) string { + return "ATLAS_OUTPUT_" + ToEnvName(action+"_"+output) } // toOutputVar converts the given values to an output variable. // The action and output are used to create the output variable name with the format: // ATLAS_OUTPUT__="" func toOutputVar(action, output, value string) string { - return fmt.Sprintf("ATLAS_OUTPUT_%s=%q", toEnvName(action+"_"+output), value) + return fmt.Sprintf("%s=%q", ToOutputVarName(action, output), value) } // fprintln writes the given values to the file using fmt.Fprintln. diff --git a/atlasaction/bitbucket.go b/atlasaction/bitbucket.go index d2add49..3fe7618 100644 --- a/atlasaction/bitbucket.go +++ b/atlasaction/bitbucket.go @@ -80,7 +80,7 @@ func (a *bbPipe) GetTriggerContext(context.Context) (*TriggerContext, error) { // GetInput implements the Action interface. func (a *bbPipe) GetInput(name string) string { - return strings.TrimSpace(a.getenv(toInputVarName(name))) + return strings.TrimSpace(a.getenv(ToInputVarName(name))) } // SetOutput implements Action. diff --git a/atlasaction/circleci_action.go b/atlasaction/circleci_action.go index 38f4dab..0d1b019 100644 --- a/atlasaction/circleci_action.go +++ b/atlasaction/circleci_action.go @@ -38,10 +38,10 @@ func (a *circleCIOrb) Getenv(key string) string { // GetInput implements the Action interface. func (a *circleCIOrb) GetInput(name string) string { - v := a.getenv(toInputVarName(name)) + v := a.getenv(ToInputVarName(name)) if v == "" { // TODO: Remove this fallback once all the actions are updated. - v = a.getenv(toEnvName("INPUT_" + name)) + v = a.getenv(ToEnvName("INPUT_" + name)) } return strings.TrimSpace(v) } diff --git a/atlasaction/gen/actions.go b/atlasaction/gen/actions.go new file mode 100644 index 0000000..f98daab --- /dev/null +++ b/atlasaction/gen/actions.go @@ -0,0 +1,112 @@ +package gen + +import ( + "cmp" + "errors" + "io/fs" + "iter" + "maps" + "slices" + "strings" + + "gopkg.in/yaml.v3" +) + +type ( + // Actions represents a list of actions. + Actions struct { + Actions []ActionSpec + } + ActionSpec struct { + ID string `yaml:"id"` + Description string `yaml:"description"` + Name string `yaml:"name"` + Inputs map[string]ActionInput `yaml:"inputs,omitempty"` + Outputs map[string]ActionOutput `yaml:"outputs,omitempty"` + } + ActionInput struct { + Description string `yaml:"description,omitempty"` + Default string `yaml:"default,omitempty"` + Required bool `yaml:"required"` + } + ActionOutput struct { + Description string `yaml:"description"` + } +) + +// ParseFS parses the actions from the given file system. +func ParseFS(fsys fs.FS) (*Actions, error) { + level1, err := fs.Glob(fsys, "**/*/action.yml") + if err != nil { + return nil, err + } + level2, err := fs.Glob(fsys, "**/*/*/action.yml") + if err != nil { + return nil, err + } + files := append(level1, level2...) + actions := make([]ActionSpec, len(files)) + for i, f := range files { + if err := actions[i].fromPath(fsys, f); err != nil { + return nil, err + } + } + slices.SortFunc(actions, func(i, j ActionSpec) int { + return cmp.Compare(i.ID, j.ID) + }) + return &Actions{Actions: actions}, nil +} + +func (a *ActionSpec) fromPath(fsys fs.FS, path string) error { + f, err := fsys.Open(path) + if err != nil { + return err + } + defer f.Close() + if err = yaml.NewDecoder(f).Decode(a); err != nil { + return err + } + if id, ok := strings.CutSuffix(path, "/action.yml"); ok { + a.ID = strings.Trim(id, "/") + return nil + } + return errors.New("gen: invalid action.yml path") +} + +func (a *ActionSpec) SortedInputs() iter.Seq2[string, ActionInput] { + orders := []string{"working-directory", "config", "env", "vars", "dev-url"} + return func(yield func(string, ActionInput) bool) { + keys := slices.SortedFunc(maps.Keys(a.Inputs), ComparePriority(orders)) + for _, k := range keys { + if !yield(k, a.Inputs[k]) { + return + } + } + } +} + +func (a *ActionSpec) SortedOutputs() iter.Seq2[string, ActionOutput] { + return func(yield func(string, ActionOutput) bool) { + keys := slices.Sorted(maps.Keys(a.Outputs)) + for _, k := range keys { + if !yield(k, a.Outputs[k]) { + return + } + } + } +} + +func ComparePriority[T cmp.Ordered](ordered []T) func(T, T) int { + return func(x, y T) int { + switch xi, yi := slices.Index(ordered, x), slices.Index(ordered, y); { + case xi != -1 && yi != -1: + return cmp.Compare(xi, yi) + case yi != -1: + return -1 + case xi != -1: + return +1 + } + // fallback to default comparison + return cmp.Compare(x, y) + } +} diff --git a/atlasaction/gen/templates.go b/atlasaction/gen/templates.go new file mode 100644 index 0000000..fca92d7 --- /dev/null +++ b/atlasaction/gen/templates.go @@ -0,0 +1,132 @@ +package gen + +import ( + "bytes" + "io/fs" + "strings" + "text/template" + + "ariga.io/atlas-action/atlasaction" +) + +var ( + // templates holds the Go templates for the code generation. + templates *Template + // Funcs are the predefined template + // functions used by the codegen. + Funcs = template.FuncMap{ + "xtemplate": xtemplate, + "hasTemplate": hasTemplate, + "trimnl": func(s string) string { + return strings.Trim(s, "\n") + }, + "nl2sp": func(s string) string { + return strings.ReplaceAll(s, "\n", " ") + }, + "env": atlasaction.ToEnvName, + "inputvar": atlasaction.ToInputVarName, + "outputvar": atlasaction.ToOutputVarName, + "dockers": func() []DockerURL { + return []DockerURL{ + {Label: "MySQL", Driver: "mysql"}, + {Label: "Postgres", Driver: "postgres"}, + {Label: "MariaDB", Driver: "mariadb"}, + {Label: "SQL Server", Driver: "sqlserver"}, + {Label: "ClickHouse", Driver: "clickhouse"}, + {Label: "SQLite", Driver: "sqlite"}, + } + }, + } +) + +// LoadTemplates loads the templates from the given file system. +func LoadTemplates(fsys fs.FS, patterns ...string) *Template { + templates = MustParse(NewTemplate("templates"). + ParseFS(fsys, patterns...)) + return templates +} + +type DockerURL struct { + Label string + Driver string +} + +func (d DockerURL) DevURL() string { + switch d.Driver { + case "mysql": + return "docker://mysql/8/dev" + case "postgres": + return "docker://postgres/15/dev?search_path=public" + case "mariadb": + return "docker://maria/latest/schema" + case "sqlserver": + return "docker://sqlserver/2022-latest?mode=schema" + case "clickhouse": + return "docker://clickhouse/23.11/dev" + case "sqlite": + return "sqlite://db?mode=memory" + } + return "" +} + +type Template struct { + *template.Template + FuncMap template.FuncMap +} + +// MustParse is a helper that wraps a call to a function returning (*Template, error) +// and panics if the error is non-nil. +func MustParse(t *Template, err error) *Template { + if err != nil { + panic(err) + } + return t +} + +// NewTemplate creates an empty template with the standard codegen functions. +func NewTemplate(name string) *Template { + t := &Template{Template: template.New(name)} + return t.Funcs(Funcs) +} + +// ParseFS is like ParseFiles or ParseGlob but reads from the file system fsys +// instead of the host operating system's file system. +func (t *Template) ParseFS(fsys fs.FS, patterns ...string) (*Template, error) { + if _, err := t.Template.ParseFS(fsys, patterns...); err != nil { + return nil, err + } + return t, nil +} + +// Funcs merges the given funcMap with the template functions. +func (t *Template) Funcs(funcMap template.FuncMap) *Template { + t.Template.Funcs(funcMap) + if t.FuncMap == nil { + t.FuncMap = template.FuncMap{} + } + for name, f := range funcMap { + if _, ok := t.FuncMap[name]; !ok { + t.FuncMap[name] = f + } + } + return t +} + +// xtemplate dynamically executes templates by their names. +func xtemplate(name string, v any) (string, error) { + buf := bytes.NewBuffer(nil) + if err := templates.ExecuteTemplate(buf, name, v); err != nil { + return "", err + } + return buf.String(), nil +} + +// hasTemplate checks whether a template exists in the loaded templates. +func hasTemplate(name string) bool { + for _, t := range templates.Templates() { + if t.Name() == name { + return true + } + } + return false +} diff --git a/atlasaction/gitlab_ci.go b/atlasaction/gitlab_ci.go index d490cd9..62d22c5 100644 --- a/atlasaction/gitlab_ci.go +++ b/atlasaction/gitlab_ci.go @@ -39,7 +39,7 @@ func (a *gitlabCI) Getenv(key string) string { // GetInput implements the Action interface. func (a *gitlabCI) GetInput(name string) string { - return strings.TrimSpace(a.getenv(toInputVarName(name))) + return strings.TrimSpace(a.getenv(ToInputVarName(name))) } // SetOutput implements the Action interface. diff --git a/tools/gen/go.mod b/tools/gen/go.mod new file mode 100644 index 0000000..b4bc788 --- /dev/null +++ b/tools/gen/go.mod @@ -0,0 +1,33 @@ +module atlas-action-gen + +go 1.24rc1 + +replace ariga.io/atlas-action => ../../ + +require ( + ariga.io/atlas-action v0.0.0-00010101000000-000000000000 + gopkg.in/yaml.v3 v3.0.1 +) + +require ( + ariga.io/atlas v0.21.2-0.20240418081819-02b3f6239b04 // indirect + ariga.io/atlas-go-sdk v0.6.5 // indirect + github.com/agext/levenshtein v1.2.3 // indirect + github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect + github.com/fatih/color v1.17.0 // indirect + github.com/go-openapi/inflect v0.19.0 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-retryablehttp v0.7.7 // indirect + github.com/hashicorp/hcl/v2 v2.18.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/mapstructure v1.1.2 // indirect + github.com/sethvargo/go-githubactions v1.3.0 // indirect + github.com/vektah/gqlparser v1.3.1 // indirect + github.com/zclconf/go-cty v1.14.1 // indirect + golang.org/x/oauth2 v0.22.0 // indirect + golang.org/x/sys v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect +) diff --git a/tools/gen/go.sum b/tools/gen/go.sum new file mode 100644 index 0000000..d72110e --- /dev/null +++ b/tools/gen/go.sum @@ -0,0 +1,89 @@ +ariga.io/atlas v0.21.2-0.20240418081819-02b3f6239b04 h1:YF3qiqtnhn+y4tfhZKTfZKfizpjqHYt7rWPUb+eA4ZA= +ariga.io/atlas v0.21.2-0.20240418081819-02b3f6239b04/go.mod h1:VPlcXdd4w2KqKnH54yEZcry79UAhpaWaxEsmn5JRNoE= +ariga.io/atlas-go-sdk v0.6.5 h1:tl0L3ObGtHjitP9N/56njjDHUrj5jJTQBjftMNwJBcM= +ariga.io/atlas-go-sdk v0.6.5/go.mod h1:9Q+/04PVyJHUse1lEE9Kp6E18xj/6mIzaUTcWYSjSnQ= +github.com/DATA-DOG/go-sqlmock v1.5.0 h1:Shsta01QNfFxHCfpW6YH2STWB0MudeXXEWMr20OEh60= +github.com/DATA-DOG/go-sqlmock v1.5.0/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo= +github.com/agext/levenshtein v1.2.3/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558= +github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= +github.com/alecthomas/kong v0.8.0 h1:ryDCzutfIqJPnNn0omnrgHLbAggDQM2VWHikE1xqK7s= +github.com/alecthomas/kong v0.8.0/go.mod h1:n1iCIO2xS46oE8ZfYCNDqdR0b0wZNrXAIAqro/2132U= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +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/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/go-openapi/inflect v0.19.0 h1:9jCH9scKIbHeV9m12SmPilScz6krDxKRasNNSNPXu/4= +github.com/go-openapi/inflect v0.19.0/go.mod h1:lHpZVlpIQqLyKwJ4N+YSc9hchQy/i12fJykb83CRBH4= +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/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= +github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-hclog v1.6.3 h1:Qr2kF+eVWjTiYmU7Y31tYlP1h0q/X3Nl3tPGdaB11/k= +github.com/hashicorp/go-hclog v1.6.3/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M= +github.com/hashicorp/go-retryablehttp v0.7.7 h1:C8hUCYzor8PIfXHa4UrZkU4VvK8o9ISHxT2Q8+VepXU= +github.com/hashicorp/go-retryablehttp v0.7.7/go.mod h1:pkQpWZeYWskR+D1tR2O5OcBFOxfA7DoAO6xtkuQnHTk= +github.com/hashicorp/hcl/v2 v2.18.1 h1:6nxnOJFku1EuSawSD81fuviYUV8DxFr3fp2dUi3ZYSo= +github.com/hashicorp/hcl/v2 v2.18.1/go.mod h1:ThLC89FV4p9MPW804KVbe/cEXoQ8NZEh+JtMeeGErHE= +github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM= +github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= +github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= +github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= +github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.12.1-0.20240709150035-ccf4b4329d21 h1:igWZJluD8KtEtAgRyF4x6lqcxDry1ULztksMJh2mnQE= +github.com/rogpeppe/go-internal v1.12.1-0.20240709150035-ccf4b4329d21/go.mod h1:RMRJLmBOqWacUkmJHRMiPKh1S1m3PA7Zh4W80/kWPpg= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sethvargo/go-githubactions v1.3.0 h1:Kg633LIUV2IrJsqy2MfveiED/Ouo+H2P0itWS0eLh8A= +github.com/sethvargo/go-githubactions v1.3.0/go.mod h1:7/4WeHgYfSz9U5vwuToCK9KPnELVHAhGtRwLREOQV80= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/vektah/gqlparser v1.3.1 h1:8b0IcD3qZKWJQHSzynbDlrtP3IxVydZ2DZepCGofqfU= +github.com/vektah/gqlparser v1.3.1/go.mod h1:bkVf0FX+Stjg/MHnm8mEyubuaArhNEqfQhF+OTiAL74= +github.com/zclconf/go-cty v1.14.1 h1:t9fyA35fwjjUMcmL5hLER+e/rEPqrbCK1/OSE4SI9KA= +github.com/zclconf/go-cty v1.14.1/go.mod h1:VvMs5i0vgZdhYawQNq5kePSpLAoz8u1xvZgrPIxfnZE= +golang.org/x/oauth2 v0.22.0 h1:BzDx2FehcG7jJwgWLELCdmLuxk2i+x9UDpSiss2u0ZA= +golang.org/x/oauth2 v0.22.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/tools v0.0.0-20190125232054-d66bd3c5d5a6/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.22.0 h1:gqSGLZqv+AI9lIQzniJ0nZDRG5GBPsSi+DRNHWNz6yA= +golang.org/x/tools v0.22.0/go.mod h1:aCwcsjqvq7Yqt6TNyX7QMU2enbQ/Gt0bo6krSeEri+c= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/tools/gen/main.go b/tools/gen/main.go new file mode 100644 index 0000000..0f990cf --- /dev/null +++ b/tools/gen/main.go @@ -0,0 +1,31 @@ +package main + +import ( + "embed" + "io" + "os" + + "ariga.io/atlas-action/atlasaction/gen" +) + +//go:embed template/* +var templateDir embed.FS + +func main() { + if len(os.Args) != 2 { + panic("gen: invalid arguments") + } + acts, err := gen.ParseFS(os.DirFS(os.Args[1])) + if err != nil { + panic(err) + } + err = readmeMarkdown(os.Stdout, acts.Actions) + if err != nil { + panic(err) + } +} + +func readmeMarkdown(w io.Writer, actions []gen.ActionSpec) error { + return gen.LoadTemplates(templateDir, "template/*.md"). + ExecuteTemplate(w, "bitbucket.md", actions) +} diff --git a/tools/gen/template/bitbucket.md b/tools/gen/template/bitbucket.md new file mode 100644 index 0000000..db04ce5 --- /dev/null +++ b/tools/gen/template/bitbucket.md @@ -0,0 +1,254 @@ +--- +title: Bitbucket Pipes +id: bitbucket-pipes +slug: /integrations/bitbucket-pipes +--- + +import Tabs from '@theme/Tabs' +import TabItem from '@theme/TabItem' + +# Bitbucket Pipes + +Atlas-Action provides seamless integration with Bitbucket, allowing you to manage and apply database migrations directly from your Bitbucket repository. +By leveraging Bitbucket Pipelines, you can automate the deployment of migration directories to your target databases, ensuring that your database schema is always up-to-date with your application code. + +This guide will walk you through the steps to set up and use Atlas-Action with Bitbucket Pipelines, enabling you to deploy migration directories from your git repository effortlessly. +{{ range . }} +## `{{ .ID }}` + +{{ .Description }} + +{{ $tmpl := printf "usage/bitbucket/%s" .ID -}} +{{- if hasTemplate $tmpl -}} +### Usage + +Add `bitbucket-pipelines.yml` to your repo with the following contents: +{{ xtemplate $tmpl . -}} +{{- end -}} +{{- if .Inputs }} +### Inputs + +* `ATLAS_ACTION` - (Required) always is `{{ .ID }}`. +* `ATLAS_TOKEN` - (Optional) to authenticate with Atlas Cloud. +* `BITBUCKET_ACTION_TOKEN` - (Optional) Bitbucket access token to post comment on the PR. +{{- range $name, $item := .SortedInputs }} +* `{{ $name | inputvar }}` - {{ if not $item.Required }}(Optional) {{end}}{{ $item.Description | trimnl | nl2sp }} +{{- end }} +{{ end -}} +{{ if .Outputs }} +### Outputs + +The outputs are written into the `.atlas-action/outputs.sh`, we can load it for the next step using the `source` command. +{{ $action := . -}} +{{- range $name, $item := .SortedOutputs }} +* `{{ $name | outputvar $action.ID }}` - {{ $item.Description | trimnl | nl2sp }} +{{- end -}} +{{- end }} +{{ end }} +{{- define "usage/bitbucket/migrate/apply" }} +**Deploy a directory from the git repository** +```yaml +image: atlassian/default-image:3 +pipelines: + branches: + master: + - step: + name: "{{ .Description }}" + script: + - name: "{{ .Name }}" + pipe: docker://arigaio/atlas-action:master + variables: + ATLAS_ACTION: "{{ .ID }}" # Required + {{ inputvar "url" }}: ${DATABASE_URL} + {{ inputvar "dir" }}: "file://migrations" + - source .atlas-action/outputs.sh +``` + +**Deploy a directory from the cloud** +```yaml +image: atlassian/default-image:3 +pipelines: + branches: + master: + - step: + name: "{{ .Description }}" + script: + - name: "{{ .Name }}" + pipe: docker://arigaio/atlas-action:master + variables: + ATLAS_ACTION: "{{ .ID }}" # Required + ATLAS_TOKEN: ${ATLAS_TOKEN} + {{ inputvar "url" }}: ${DATABASE_URL} + {{ inputvar "dir" }}: "atlas://my-project" + - source .atlas-action/outputs.sh +``` + +{{ end -}} + +{{- define "usage/bitbucket/migrate/push" }} + + +{{- $action := . -}} +{{- range $item := dockers }} + + +```yaml +image: atlassian/default-image:3 +pipelines: + branches: + master: + - step: + name: "{{ $action.Description }}" + script: + - name: "{{ $action.Name }}" + pipe: docker://arigaio/atlas-action:master + variables: + ATLAS_ACTION: "{{ $action.ID }}" # Required + ATLAS_TOKEN: ${ATLAS_TOKEN} + BITBUCKET_ACCESS_TOKEN: ${BITBUCKET_ACCESS_TOKEN} + {{ inputvar "dir-name" }}: "my-project" + {{ inputvar "dev-url" }}: "{{ $item.DevURL }}" + - source .atlas-action/outputs.sh +``` + + +{{- end }} + +{{ end -}} + +{{- define "usage/bitbucket/migrate/lint" }} + + +{{- $action := . -}} +{{- range $item := dockers }} + + +```yaml +image: atlassian/default-image:3 +pipelines: + branches: + master: + - step: + name: "{{ $action.Description }}" + script: + - name: "{{ $action.Name }}" + pipe: docker://arigaio/atlas-action:master + variables: + ATLAS_ACTION: "{{ $action.ID }}" # Required + ATLAS_TOKEN: ${ATLAS_TOKEN} + BITBUCKET_ACCESS_TOKEN: ${BITBUCKET_ACCESS_TOKEN} + {{ inputvar "dir-name" }}: "my-project" + {{ inputvar "dev-url" }}: "{{ $item.DevURL }}" + - source .atlas-action/outputs.sh +``` + + +{{- end }} + +{{ end -}} + +{{- define "usage/bitbucket/schema/plan" }} + + +{{- $action := . -}} +{{- range $item := dockers }} + + +```yaml +image: atlassian/default-image:3 +pipelines: + branches: + master: + - step: + name: "{{ $action.Description }}" + script: + - name: "{{ $action.Name }}" + pipe: docker://arigaio/atlas-action:master + variables: + ATLAS_ACTION: "{{ $action.ID }}" # Required + ATLAS_TOKEN: ${ATLAS_TOKEN} + BITBUCKET_ACCESS_TOKEN: ${BITBUCKET_ACCESS_TOKEN} + {{ inputvar "dev-url" }}: "{{ $item.DevURL }}" + - source .atlas-action/outputs.sh +``` + + +{{- end }} + +{{ end -}} + +{{- define "usage/bitbucket/schema/plan/approve" }} +```yaml +image: atlassian/default-image:3 +pipelines: + branches: + master: + - step: + name: "{{ .Description }}" + script: + - name: "{{ .Name }}" + pipe: docker://arigaio/atlas-action:master + variables: + ATLAS_ACTION: "{{ .ID }}" # Required + ATLAS_TOKEN: ${ATLAS_TOKEN} + {{ inputvar "env" }}: "ci" + - source .atlas-action/outputs.sh +``` + +{{ end -}} +{{- define "usage/bitbucket/schema/push" }} +```yaml +image: atlassian/default-image:3 +pipelines: + branches: + master: + - step: + name: "{{ .Description }}" + script: + - name: "{{ .Name }}" + pipe: docker://arigaio/atlas-action:master + variables: + ATLAS_ACTION: "{{ .ID }}" # Required + ATLAS_TOKEN: ${ATLAS_TOKEN} + {{ inputvar "env" }}: "ci" + {{ inputvar "latest" }}: "true" + - source .atlas-action/outputs.sh +``` + +{{ end -}} +{{- define "usage/bitbucket/schema/apply" }} +```yaml +image: atlassian/default-image:3 +pipelines: + branches: + master: + - step: + name: "{{ .Description }}" + script: + - name: "{{ .Name }}" + pipe: docker://arigaio/atlas-action:master + variables: + ATLAS_ACTION: "{{ .ID }}" # Required + ATLAS_TOKEN: ${ATLAS_TOKEN} # Needed only for deploying a schema from Atlas Cloud. + - source .atlas-action/outputs.sh +``` + +{{ end -}} \ No newline at end of file diff --git a/tools/gen/template/github.md b/tools/gen/template/github.md new file mode 100644 index 0000000..e21b882 --- /dev/null +++ b/tools/gen/template/github.md @@ -0,0 +1,19 @@ +{{ range . }} +### `ariga/atlas-action/{{ .ID }}` + +{{ .Description }} +{{ if .Inputs }} +#### Inputs + +All inputs are optional as they may be specified in the Atlas configuration file. +{{ range $name, $item := .SortedInputs }} +* `{{ $name }}` - {{ if not $item.Required }}(Optional) {{end}}{{ $item.Description | trimnl | nl2sp }} +{{- end }} +{{ end -}} +{{ if .Outputs }} +#### Outputs +{{ range $name, $item := .SortedOutputs }} +* `{{ $name }}` - {{ $item.Description | trimnl | nl2sp }} +{{- end }} +{{ end }} +{{ end }}