Skip to content

Commit

Permalink
feat: complete the basic feature of converting
Browse files Browse the repository at this point in the history
  • Loading branch information
LinuxSuRen committed Dec 11, 2022
1 parent 2aa9a86 commit d33ac9c
Show file tree
Hide file tree
Showing 15 changed files with 431 additions and 1 deletion.
30 changes: 30 additions & 0 deletions .github/workflows/pull-request.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Pull Request Build

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
build:
name: Build
runs-on: ubuntu-20.04
steps:
- name: Set up Go 1.19
uses: actions/setup-go@v3
with:
go-version: 1.19
id: go
- name: Check out code into the Go module directory
uses: actions/[email protected]
- name: Test
run: |
go test ./... -coverprofile coverage.out
- name: Run GoReleaser
uses: goreleaser/[email protected]
with:
version: latest
args: release --skip-publish --rm-dist
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin/
.idea/
24 changes: 24 additions & 0 deletions .goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
archives:
- name_template: "{{ .Binary }}-{{ .Os }}-{{ .Arch }}"
format_overrides:
- goos: windows
format: zip
files:
- README.md
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
build:
go build -o bin/gaw .
copy: build
cp bin/gaw /usr/local/bin
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# github-action-workflow
GitHub Actions compitable workflows
GitHub Actions compatible workflows
56 changes: 56 additions & 0 deletions cmd/convert.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package cmd

import (
"github.com/linuxsuren/github-action-workflow/pkg"
"github.com/spf13/cobra"
"golang.org/x/exp/maps"
"gopkg.in/yaml.v2"
"os"
"strings"
)

func newConvertCmd() (c *cobra.Command) {
opt := &convertOption{}
c = &cobra.Command{
Use: "convert",
Example: "gaw convert .github/workflows/build.yaml",
Short: "Convert GitHub Actions workflow file to Argo Workflows",
Args: cobra.MinimumNArgs(1),
RunE: opt.runE,
}

flags := c.Flags()
flags.StringToStringVarP(&opt.env, "env", "e", nil,
"Environment variables for all steps")
return
}

func (o *convertOption) runE(cmd *cobra.Command, args []string) (err error) {
gh := &pkg.Workflow{}
var data []byte
if data, err = os.ReadFile(args[0]); err == nil {
if err = yaml.Unmarshal(data, gh); err != nil {
return
}
}

for i, job := range gh.Jobs {
for j, step := range job.Steps {
if step.Env == nil {
gh.Jobs[i].Steps[j].Env = o.env
} else {
maps.Copy(gh.Jobs[i].Steps[j].Env, o.env)
}
}
}

var result string
if result, err = gh.ConvertToArgoWorkflow(); err == nil {
cmd.Println(strings.TrimSpace(result))
}
return
}

type convertOption struct {
env map[string]string
}
17 changes: 17 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package cmd

import (
"github.com/spf13/cobra"
"os"
)

func NewRoot() (c *cobra.Command) {
c = &cobra.Command{
Use: "gaw",
Short: "GitHub Actions workflow compatible tool",
}

c.SetOut(os.Stdout)
c.AddCommand(newConvertCmd())
return
}
18 changes: 18 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
module github.com/linuxsuren/github-action-workflow

go 1.19

require (
github.com/spf13/cobra v1.6.1
github.com/stretchr/testify v1.8.1
golang.org/x/exp v0.0.0-20221211140036-ad323defaf05
gopkg.in/yaml.v2 v2.4.0
)

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/inconshreveable/mousetrap v1.0.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
29 changes: 29 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
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/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
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/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.6.1 h1:o94oiPyS4KD1mPy2fmcYYHHfCxLqYjJOhGsCHFZtEzA=
github.com/spf13/cobra v1.6.1/go.mod h1:IOw/AERYS7UzyrGinqmz6HLUo219MORXGxhbaJUqzrY=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
golang.org/x/exp v0.0.0-20221211140036-ad323defaf05 h1:T8EldfGCcveFMewH5xAYxxoX3PSQMrsechlUGVFlQBU=
golang.org/x/exp v0.0.0-20221211140036-ad323defaf05/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
12 changes: 12 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package main

import (
"github.com/linuxsuren/github-action-workflow/cmd"
"os"
)

func main() {
if err := cmd.NewRoot().Execute(); err != nil {
os.Exit(1)
}
}
111 changes: 111 additions & 0 deletions pkg/argo-workflow.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package pkg

import (
"bytes"
"fmt"
"html/template"
"strings"
)

func k8sStyleName(name string) (result string) {
result = strings.ToLower(name)
result = strings.ReplaceAll(result, " ", "-")
return
}

func (w *Workflow) ConvertToArgoWorkflow() (output string, err error) {
// pre-handle
defaultImage := "alpine"
w.Name = k8sStyleName(w.Name)
for i := range w.Jobs {
job := w.Jobs[i]
job.Name = k8sStyleName(job.Name)
for j := range w.Jobs[i].Steps {
w.Jobs[i].Steps[j].Name = k8sStyleName(w.Jobs[i].Steps[j].Name)

if strings.HasPrefix(w.Jobs[i].Steps[j].Uses, "actions/checkout") {
w.Jobs[i].Steps[j].Image = "alpine/git:v2.26.2"
w.Jobs[i].Steps[j].Run = "git clone https://gitee.com/LinuxSuRen/yaml-readme ."
} else if strings.HasPrefix(w.Jobs[i].Steps[j].Uses, "actions/setup-go") {
defaultImage = "golang:1.19"

if ver, ok := w.Jobs[i].Steps[j].With["go-version"]; ok {
defaultImage = fmt.Sprintf("golang:%s", ver)
}
} else if strings.HasPrefix(w.Jobs[i].Steps[j].Uses, "goreleaser/goreleaser-action") {
w.Jobs[i].Steps[j].Image = "goreleaser/goreleaser:v1.13.1"
w.Jobs[i].Steps[j].Run = "goreleaser " + w.Jobs[i].Steps[j].With["args"]
} else if w.Jobs[i].Steps[j].Uses != "" {
// TODO not support yet, do nothing
} else {
w.Jobs[i].Steps[j].Image = defaultImage
}
}

// TODO currently we can only handle one job
break
}

var t *template.Template
t, err = template.New("argo").Parse(argoworkflowTemplate)

data := bytes.NewBuffer([]byte{})
if err = t.Execute(data, w); err == nil {
output = data.String()
}
return
}

var argoworkflowTemplate = `
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: {{.Name}}
spec:
entrypoint: main
volumeClaimTemplates:
- metadata:
name: work
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 64Mi
templates:
- name: main
steps:
{{- range $key, $job := .Jobs}}
{{- range $i, $step := $job.Steps}}
{{if $step.Image}}
- - name: {{$step.Name}}
template: {{$step.Name}}
{{end}}
{{- end}}
{{end}}
{{- range $key, $job := .Jobs}}
{{- range $i, $step := $job.Steps}}
{{if $step.Image}}
- name: {{$step.Name}}
script:
image: {{$step.Image}}
command: [sh]
{{if $step.Env}}
env:
{{- range $k, $v := $step.Env}}
- name: {{$k}}
value: {{$v}}
{{end}}
{{end}}
source: |
{{$step.Run}}
volumeMounts:
- mountPath: /work
name: work
workingDir: /work
{{end}}
{{- end}}
{{end}}
`
43 changes: 43 additions & 0 deletions pkg/argo-workflow_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package pkg

import (
"github.com/stretchr/testify/assert"
"gopkg.in/yaml.v2"
"os"
"testing"
)

func TestWorkflow_ConvertToArgoWorkflow(t *testing.T) {
tests := []struct {
name string
githubActions string
argoWorkflows string
wantErr bool
}{{
name: "simple",
githubActions: "data/github-actions.yaml",
argoWorkflows: "data/argo-workflows.yaml",
}}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
w := &Workflow{}
data, err := os.ReadFile(tt.githubActions)
assert.Nil(t, err)
err = yaml.Unmarshal(data, w)
assert.Nil(t, err)

gotOutput, err := w.ConvertToArgoWorkflow()
if (err != nil) != tt.wantErr {
t.Errorf("ConvertToArgoWorkflow() error = %v, wantErr %v", err, tt.wantErr)
return
}

wantData, err := os.ReadFile(tt.argoWorkflows)
assert.Nil(t, err)

if gotOutput != string(wantData) {
t.Errorf("ConvertToArgoWorkflow() gotOutput = %v, want %v", gotOutput, string(wantData))
}
})
}
}
26 changes: 26 additions & 0 deletions pkg/data/argo-workflows.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
name: script
spec:
entrypoint: main
templates:
- name: main
steps:
- - name: shell
template: shell
- name: python
template: python
- name: shell
script:
image: alpine
command: [sh]
source: echo 1
- name: python
script:
image: python:alpine3.6
command: [python]
source: |
import random
i = random.randint(1, 100)
print(i)
Loading

0 comments on commit d33ac9c

Please sign in to comment.