Skip to content

Commit

Permalink
main: support generate declarative workflows (#333)
Browse files Browse the repository at this point in the history
Co-authored-by: Giau. Tran Minh <[email protected]>
Co-authored-by: Ariel Mashraki <[email protected]>
  • Loading branch information
3 people authored Sep 30, 2024
1 parent 6ce8f34 commit 73a3917
Show file tree
Hide file tree
Showing 26 changed files with 1,424 additions and 457 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci-go.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,13 @@ jobs:
gh extension install .
- name: Run GitHub atlas extension
run: |
gh atlas init-action -R ${{ secrets.TEST_REPO }} --token=${{ secrets.TEST_ATLAS_TOKEN }} --dir-name="sync-action-integration-test" --driver="sqlite" "sqlite_dir" \
gh atlas init-action -R ${{ secrets.TEST_REPO }} --token=${{ secrets.TEST_ATLAS_TOKEN }} --dir-name="sync-action-integration-test" "sqlite_dir" \
--config-path="atlas.hcl" --config-env="local"
- name: Run GitHub atlas extension with invalid dir
id: invalid_dir
continue-on-error: true
run: |
gh atlas init-action -R ${{ secrets.TEST_REPO }} --token=${{ secrets.TEST_ATLAS_TOKEN }} --dir-name="invalid" --driver="sqlite" "sqlite_dir" \
gh atlas init-action -R ${{ secrets.TEST_REPO }} --token=${{ secrets.TEST_ATLAS_TOKEN }} --dir-name="invalid" "sqlite_dir" \
--config-path="atlas.hcl" --config-env="local"
- name: Check invalid dir error
if : steps.invalid_dir.outcome == 'success'
Expand Down
48 changes: 35 additions & 13 deletions cloudapi/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,36 @@ func (r *roundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
return http.DefaultTransport.RoundTrip(req)
}

// Client is a client for the Atlas Cloud API.
type Client struct {
client *http.Client
endpoint string
token string
}
type (
// API defines how to interact with the Atlas Cloud API.
API interface {
ValidateToken(ctx context.Context) error
Repos(ctx context.Context) ([]Repo, error)
}
// Client is a client for the Atlas Cloud API.
Client struct {
client *http.Client
endpoint string
token string
}
// RepoType represents the type of an Atlas Cloud repository.
RepoType string
// Repo represents a project in the Atlas Cloud API.
Repo struct {
URL string
Title string
Slug string
Type RepoType
Driver string
}
)

var _ API = (*Client)(nil)

const (
SchemaType RepoType = "SCHEMA"
DirectoryType RepoType = "MIGRATION_DIRECTORY"
)

// New creates a new Client for the Atlas Cloud API.
func New(endpoint, token string) *Client {
Expand Down Expand Up @@ -113,18 +137,16 @@ func (c *Client) ValidateToken(ctx context.Context) error {
return c.post(ctx, query, vars, &payload)
}

// DirNames fetches the names of all migration directories from the Atlas Cloud API.
func (c *Client) DirNames(ctx context.Context) ([]string, error) {
// Repos fetches data of all repositories from the Atlas Cloud.
func (c *Client) Repos(ctx context.Context) ([]Repo, error) {
var (
payload struct {
DirSlugs []string `json:"dirSlugs"`
Repos []Repo `json:"repos"`
}
query = `query {
dirSlugs
}`
query = `query { repos { title slug url type driver } }`
)
if err := c.post(ctx, query, nil, &payload); err != nil {
return nil, err
}
return payload.DirSlugs, nil
return payload.Repos, nil
}
57 changes: 11 additions & 46 deletions gen/atlas.tmpl
Original file line number Diff line number Diff line change
@@ -1,61 +1,26 @@
{{- define "header" -}}
name: Atlas
on:
push:
branches:
- {{ .DefaultBranch }}
paths:
- .github/workflows/ci-atlas.yaml
- '{{ .Path }}/*'
pull_request:
paths:
- '{{ .Path }}/*'
{{- end }}

{{- define "permissions" }}
# Permissions to write comments on the pull request.
permissions:
contents: read
pull-requests: write
jobs:
atlas:
{{- if .CreateDevURL }}
{{- end }}

{{- define "job-setup" }}
{{- if not .Env.HasDevURL }}
{{- template "services" . }}
{{- end }}
runs-on: ubuntu-latest
env:
GITHUB_TOKEN: {{`${{ github.token }}`}}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: ariga/setup-atlas@v0
with:
cloud-token: {{`${{ secrets.`}}{{ .SecretName }}{{` }}`}}
- uses: ariga/atlas-action/migrate/lint@v1
with:
dir: 'file://{{ .Path }}'
{{- with .DirName }}
dir-name: '{{ . }}'
{{- end }}
{{- if .CreateDevURL }}
{{ template "UseServices" . }}
{{- end }}
{{- with .ConfigPath }}
config: 'file://{{ . }}'
{{- end }}
{{- with .Env }}
env: '{{ . }}'
{{- end }}
env:
GITHUB_TOKEN: {{`${{ github.token }}`}}
- uses: ariga/atlas-action/migrate/push@v1
if: github.ref == 'refs/heads/{{ .DefaultBranch }}'
with:
dir: 'file://{{ .Path }}'
{{- with .DirName }}
dir-name: '{{ . }}'
{{- end }}
{{- if .CreateDevURL }}
{{ template "UseServices" . }}
{{- end }}
{{- with .ConfigPath }}
config: 'file://{{ . }}'
{{- end }}
{{- with .Env }}
env: '{{ . }}'
{{- end }}
{{- end }}
116 changes: 116 additions & 0 deletions gen/declarative.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
{{ template "header" . }}
on:
push:
branches: [ {{ .DefaultBranch }} ]
pull_request:
branches: [ {{ .DefaultBranch }} ]
workflow_dispatch:
{{- template "permissions" . }}
jobs:
plan:
if: {{`${{ github.event_name == 'pull_request' }}`}}
{{- if not .Env.HasDevURL }}
{{- template "job-setup" . }}
{{- end }}
- uses: ariga/atlas-action/schema/plan@v1
with:
{{- if .From }}
from: {{ .From }}
{{- end }}
{{- if not .Env.HasSchemaSrc }}
{{- if .To }}
to: {{ .To }}
{{- end }}
{{- end }}
{{- if not .Env.HasRepoName }}
{{- with .CloudRepo }}
schema-name: {{ . }}
{{- end }}
{{- end }}
{{- if not .Env.HasDevURL }}
{{ template "UseServices" . }}
{{- end }}
{{- with .Env.Path }}
config: 'file://{{ . }}'
{{- end }}
{{- with .Env.Name }}
env: '{{ . }}'
{{- end }}
apply:
if: {{`${{ github.event_name == 'push' && github.ref == 'refs/heads/`}}{{ .DefaultBranch }}{{`' }}`}}
{{- if not .Env.HasDevURL }}
{{- template "job-setup" . }}
{{- end }}
- uses: ariga/atlas-action/schema/plan/approve@v1
id: plan-approve
with:
{{- if not .Env.HasURL }}
{{- if .From }}
from: {{ .From }}
{{- end }}
{{- end }}
{{- if not .Env.HasSchemaSrc }}
{{- if .To }}
to: {{ .To }}
{{- end }}
{{- end }}
{{- if not .Env.HasDevURL }}
{{ template "UseServices" . }}
{{- end }}
{{- if not .Env.HasRepoName }}
{{- with .CloudRepo }}
schema-name: {{ . }}
{{- end }}
{{- end }}
{{- with .Env.Path }}
config: 'file://{{ . }}'
{{- end }}
{{- with .Env.Name }}
env: '{{ . }}'
{{- end }}
- uses: ariga/atlas-action/schema/push@v1
with:
{{- if not .Env.HasDevURL }}
{{ template "UseServices" . }}
{{- end }}
{{- if not .Env.HasSchemaSrc }}
{{- if .To }}
url: {{ .To }}
{{- end }}
{{- end }}
{{- if not .Env.HasRepoName }}
{{- with .CloudRepo }}
schema-name: {{ . }}
{{- end }}
{{- end }}
{{- with .Env.Path }}
config: 'file://{{ . }}'
{{- end }}
{{- with .Env.Name }}
env: '{{ . }}'
{{- end }}
{{- if .SetupSchemaApply }}
- uses: ariga/atlas-action/schema/apply@v1
if: {{`${{ steps.plan-approve.outputs.status == 'APPROVED' }}`}}
with:
{{- if not .Env.HasURL }}
{{- if .From }}
url: {{ .From }}
{{- end }}
{{- end }}
{{- if not .Env.HasSchemaSrc }}
{{- if .To }}
to: {{ .To }}
{{- end }}
{{- end }}
{{- if not .Env.HasDevURL }}
{{ template "UseServices" . }}
{{- end }}
{{- with .Env.Path }}
config: 'file://{{ . }}'
{{- end }}
{{- with .Env.Name }}
env: '{{ . }}'
{{- end }}
plan: {{`${{ steps.plan-approve.outputs.plan }}`}}
{{- end }}
66 changes: 36 additions & 30 deletions gen/gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,60 @@ package gen
import (
"bytes"
"embed"
_ "embed"
"fmt"
"slices"
"text/template"
)

type (
Driver string
Env struct {
Name string
// HasDevURL is true if the env block has dev attribute
HasDevURL bool
// HasURL is true if the env block has url attribute
HasURL bool
// Path is the path of the file containing the env block
Path string
// HasSchemaSrc is true if the env block has schema.src attribute
HasSchemaSrc bool
// HasRepoName is true if the schema block has repo.name attribute
HasRepoName bool
}
// Config passed to template parser
Config struct {
Path string
DirName string
SecretName string
DefaultBranch string
Driver string
ConfigPath string
Env string
CreateDevURL bool
SchemaScope bool
Flow string
From string
To string
Path string
DirName string
SecretName string
DefaultBranch string
Driver string
Env Env
SchemaScope bool
CloudRepo string
SetupSchemaApply bool
}
)

var Drivers = []string{"mysql", "postgres", "postgis", "mariadb", "sqlite", "mssql", "clickhouse"}

func validateDriver(s string) error {
if !slices.Contains(Drivers, s) {
return fmt.Errorf("unknown driver %q", s)
}
return nil
}

var (
Drivers = []string{"MYSQL", "POSTGRESQL", "MARIADB", "SQLITE", "SQLSERVER", "CLICKHOUSE"}
//go:embed *.tmpl
files embed.FS

tmpl = template.Must(template.New("atlas-sync-action").
tmpl = template.Must(template.New("atlas-sync-action").
ParseFS(files, "*.tmpl"))
)

// Generate the content of the atlas ci lint yaml.
func Generate(cfg *Config) ([]byte, error) {
if err := validateDriver(cfg.Driver); err != nil {
return nil, err
}
b := bytes.NewBuffer(nil)

if err := tmpl.ExecuteTemplate(b, "atlas.tmpl", cfg); err != nil {
return nil, err
switch cfg.Flow {
case "versioned":
if err := tmpl.ExecuteTemplate(b, "versioned.tmpl", cfg); err != nil {
return nil, err
}
case "declarative":
if err := tmpl.ExecuteTemplate(b, "declarative.tmpl", cfg); err != nil {
return nil, err
}
}
return b.Bytes(), nil
}
Loading

0 comments on commit 73a3917

Please sign in to comment.