Skip to content

Commit

Permalink
chore: refactorings and new features
Browse files Browse the repository at this point in the history
Signed-off-by: Thorsten Hans <[email protected]>
  • Loading branch information
ThorstenHans committed Nov 1, 2024
1 parent 8182b31 commit 3f596f2
Show file tree
Hide file tree
Showing 14 changed files with 542 additions and 242 deletions.
83 changes: 51 additions & 32 deletions cmd/gh/create_action.go
Original file line number Diff line number Diff line change
@@ -1,70 +1,89 @@
package gh

import (
"fmt"
"os"
"log"

"github.com/spf13/cobra"
"github.com/thorstenhans/spin-gh-plugin/internal/detective"
gh "github.com/thorstenhans/spin-gh-plugin/internal/github"
)

type CreateActionOptions struct {
Output string
Name string
ToolVersions gh.ToolVersions
TemplatePath string
Plugins []string
Overwrite bool
BranchName string
DryRun bool
gh.ActionTriggers
Name string
OperatingSystem string
Output string
Overwrite bool
Plugins []string
EnvironmentVariables []string
TemplatePath string
Tools gh.Tools
}

var options CreateActionOptions = CreateActionOptions{
ToolVersions: gh.DefaultToolVersions(),
Tools: gh.DefaultTools(),
}

var createActionCmd = &cobra.Command{
Use: "create-action",
Short: "Examines your Spin App and creates a working GitHub Action for CI",
Run: func(cmd *cobra.Command, args []string) {

apps := detective.FindAllSpinApps()
if len(apps) == 0 {
fmt.Println("Could not find Spin App(s) under the current directory")
os.Exit(1)
log.Fatal("Could not find Spin App(s) under the current directory")
}

envVars, err := gh.ParseEnvVars(options.EnvironmentVariables)
if err != nil {
log.Fatalf("Invalid Environment variable provided %v", err)
}

renderOptions := gh.RenderActionOptions{
SpinApps: apps,
Output: options.Output,
Overwrite: options.Overwrite,
Plugins: options.Plugins,
TargetBranch: options.BranchName,
CustomTemplatePath: options.TemplatePath,
Name: options.Name,
ToolVersions: options.ToolVersions,
CustomTemplatePath: options.TemplatePath,
DryRun: options.DryRun,
Name: options.Name,
OperatingSystem: options.OperatingSystem,
Output: options.Output,
Overwrite: options.Overwrite,
Plugins: options.Plugins,
SpinApps: apps,
ActionTriggers: options.ActionTriggers,
Tools: options.Tools,
EnvironmentVariables: envVars,
}
err := gh.RenderAction(renderOptions)
err = gh.RenderAction(renderOptions)
if err != nil {
fmt.Printf("Error while rendering template %v", err)
os.Exit(1)
log.Fatalf("Error while rendering template %v", err)
}
},
}

func init() {
defaultPlugins := []string{"js2wasm", "py2wasm", "kube"}

createActionCmd.Flags().StringVarP(&options.Output, "output", "o", ".github/workflows/ci.yaml", "Path where the GitHub Action will be created")

createActionCmd.Flags().StringVarP(&options.Name, "name", "n", "CI", "Name for the GitHub Action")
createActionCmd.Flags().BoolVarP(&options.ActionTriggers.ManualDispatch, "manual", "", false, "Trigger Action on workflow dispatch")
createActionCmd.Flags().StringVarP(&options.ActionTriggers.Schedule, "cron", "", "", "Trigger Action on cron schedule")
createActionCmd.Flags().StringVarP(&options.ActionTriggers.Push, "ci", "", "main", "Trigger Action for every push on the specified branch")
createActionCmd.Flags().StringVarP(&options.ActionTriggers.PullRequest, "pr", "", "", "Trigger Action for every PR targeting the specified branch")

createActionCmd.Flags().StringVarP(&options.ToolVersions.Rust, "rust-version", "", options.ToolVersions.Rust, "Set Rust version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.ToolVersions.Go, "go-version", "", options.ToolVersions.Go, "Set Go version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.ToolVersions.TinyGo, "tinygo-version", "", options.ToolVersions.TinyGo, "Set TinyGo version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.ToolVersions.Node, "node-version", "", options.ToolVersions.Node, "Set Node.js version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.ToolVersions.Python, "python-version", "", options.ToolVersions.Python, "Set Python version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.ToolVersions.Spin, "spin-version", "", "", "Set Spin version for GitHub Actions (default: current stable Spin release)")
createActionCmd.Flags().StringVarP(&options.Tools.Rust, "rust-version", "", options.Tools.Rust, "Set Rust version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.Tools.Go, "go-version", "", options.Tools.Go, "Set Go version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.Tools.TinyGo, "tinygo-version", "", options.Tools.TinyGo, "Set TinyGo version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.Tools.Node, "node-version", "", options.Tools.Node, "Set Node.js version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.Tools.Python, "python-version", "", options.Tools.Python, "Set Python version for GitHub Actions")
createActionCmd.Flags().StringVarP(&options.Tools.Spin, "spin-version", "", "", "Set Spin version for GitHub Actions (default: current stable Spin release)")

createActionCmd.Flags().BoolVarP(&options.Overwrite, "overwrite", "", false, "Overwrite existing output file")
createActionCmd.Flags().StringVarP(&options.TemplatePath, "template", "t", "", "Specify the path to a custom template for creating the GitHub Action")
createActionCmd.Flags().StringSliceVarP(&options.Plugins, "plugins", "p", defaultPlugins, "Specify required Spin plugins")
createActionCmd.Flags().StringVarP(&options.BranchName, "branch", "b", "main", "Specify the desired branch")
createActionCmd.Flags().StringSliceVarP(&options.EnvironmentVariables, "env", "", []string{}, "Specify Environment Variables (format key=value)")
createActionCmd.Flags().StringSliceVarP(&options.Plugins, "plugin", "p", []string{}, "Specify required Spin plugins")

createActionCmd.Flags().StringVarP(&options.OperatingSystem, "os", "", "ubuntu-latest", "Specify the desired operating system for the GitHub Action")
createActionCmd.Flags().BoolVarP(&options.DryRun, "dry-run", "", false, "Print GitHub Action to stdout instead of writing to a file")

rootCmd.AddCommand(createActionCmd)
}
9 changes: 5 additions & 4 deletions cmd/gh/eject.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gh

import (
"fmt"
"log"
"os"

"github.com/spf13/cobra"
Expand All @@ -18,17 +19,17 @@ var ejectCmd = &cobra.Command{
if output != "" {
if !overwrite {
if _, err := os.Stat(output); err == nil {
fmt.Printf("File %s already exists. Use --overwrite to overwrite it.\n", output)
log.Fatalf("File %s already exists. Use --overwrite to overwrite it.\n", output)
return
}
}
err := os.WriteFile(output, []byte(template), 0644)
if err != nil {
fmt.Printf("Failed to write to file %s: %v\n", output, err)
return
log.Fatalf("Failed to write to file %s: %v\n", output, err)
}
fmt.Printf("Template written to %s\n", output)
log.Printf("Template written to %s\n", output)
}
// output was empty -> print to STDOUT
fmt.Println(template)
},
}
Expand Down
Binary file removed gh
Binary file not shown.
77 changes: 69 additions & 8 deletions internal/detective/detective.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,40 @@ package detective

import (
"fmt"
"log"
"os"
"path/filepath"
"slices"
"strings"

"github.com/thorstenhans/spin-gh-plugin/internal/spinapp"
)

var ignoreFolders = []string{"node_modules", "target"}

func FindAllSpinApps() []*spinapp.App {
apps := make([]*spinapp.App, 0)
err := filepath.Walk(".", func(path string, info os.FileInfo, err error) error {
err := filepath.WalkDir(".", func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if !info.IsDir() && strings.EqualFold(info.Name(), spinapp.ManifestName) {
relativePath, err := filepath.Rel(".", filepath.Dir(path))
if d.IsDir() && slices.Contains(ignoreFolders, d.Name()) {
return filepath.SkipDir
}
if !d.IsDir() && strings.EqualFold(d.Name(), spinapp.ManifestName) {
relativePath, err := getRelativePath(filepath.Dir(path))
if err != nil {
return err
}

if relativePath != "." {
relativePath = fmt.Sprintf("./%s", relativePath)
}
app, err := spinapp.NewApp(relativePath)
if err != nil {
fmt.Printf("%v", err)
return err
}
fmt.Printf("Discovered Spin App %s\n", app.ToString())
log.Printf("Discovered Spin App: %s\n", app.ToString())
findAllAppComponents(app)
apps = append(apps, app)
return filepath.SkipDir
}
return nil
})
Expand All @@ -39,3 +44,59 @@ func FindAllSpinApps() []*spinapp.App {
}
return apps
}

func findAllAppComponents(app *spinapp.App) {
appFolder := app.GetLocation()
filepath.WalkDir(appFolder, func(path string, d os.DirEntry, err error) error {
if err != nil {
return err
}
if d.IsDir() && slices.Contains(ignoreFolders, d.Name()) {
return filepath.SkipDir
}
if !d.IsDir() {
var language string
switch strings.ToLower(d.Name()) {
case spinapp.Rust.Hint:
language = spinapp.Rust.Name
case spinapp.GoLang.Hint:
language = spinapp.GoLang.Name
case spinapp.JavaScript.Hint:
language = spinapp.JavaScript.Name
case spinapp.Python.Hint:
language = spinapp.Python.Name
default:
return nil
}

relativePath, err := getRelativePath(filepath.Dir(path))
if err != nil {
return err
}

component := spinapp.Component{
Language: language,
Location: relativePath,
}
app.AddComponent(component) // Assuming there's a method to add components to the app

return filepath.SkipDir
}
return nil
})

for _, c := range app.GetComponents() {
log.Printf(" - %s Component discovered at %s\n", c.Language, c.Location)
}
}

func getRelativePath(p string) (string, error) {
relativePath, err := filepath.Rel(".", p)
if err != nil {
return "", err
}
if relativePath != "." {
relativePath = fmt.Sprintf("./%s", relativePath)
}
return relativePath, nil
}
Original file line number Diff line number Diff line change
@@ -1,22 +1,39 @@
name: "{{ .ActionName }}"
on:
{{- if ne .ActionTriggers.Push "" }}
push:
branches:
- "{{ .TargetBranch }}"
- "{{ .ActionTriggers.Push }}"
{{- end }}
{{- if .ActionTriggers.ManualDispatch }}
workflow_dispatch:
{{- end }}
{{- if ne .ActionTriggers.Schedule "" }}
schedule:
- cron: "{{ .ActionTriggers.Schedule }}"
{{- end }}
{{- if ne .ActionTriggers.PullRequest "" }}
pull_request:
branches:
- "{{ .ActionTriggers.PullRequest }}"
{{- end }}
env:
RUST_VERSION: "{{ .ToolVersions.Rust }}"
GO_VERSION: "{{ .ToolVersions.Go}}"
TINYGO_VERSION: "{{ .ToolVersions.TinyGo }}"
NODE_VERSION: "{{ .ToolVersions.Node }}"
PYTHON_VERSION: "{{ .ToolVersions.Python}}"
SPIN_VERSION: "{{ .ToolVersions.Spin }}"
RUST_VERSION: "{{ .Tools.Rust }}"
GO_VERSION: "{{ .Tools.Go}}"
TINYGO_VERSION: "{{ .Tools.TinyGo }}"
NODE_VERSION: "{{ .Tools.Node }}"
PYTHON_VERSION: "{{ .Tools.Python}}"
SPIN_VERSION: "{{ .Tools.Spin }}"
{{- range .EnvironmentVariables }}
{{ .Key }}: "{{ .Value }}"
{{- end }}
jobs:
spin:
runs-on: "{{ .OperatingSystem }}"
name: Build Spin App
steps:
- uses: actions/checkout@v4
{{- if .Go}}
{{- if .Go }}
- name: Install Go
uses: actions/setup-go@v5
with:
Expand Down Expand Up @@ -44,16 +61,33 @@ jobs:
uses: actions/setup-python@v5
with:
python-version: "{{ `${{ env.PYTHON_VERSION }}` }}"
{{- end}}
{{- end }}
- name: Install Spin
uses: fermyon/actions/spin/setup@v1
with:
{{- if ne .ToolVersions.Spin "" }}
version: "{{ `${{ env.SPIN_VERSION }}` }}"
{{- end }}
plugins: {{ .SpinPlugins }}
{{- range .SpinApps}}
{{- range .SpinApps }}
{{- if ne .Setup "" }}
- name: Executing Setup Commands for {{ .Name }}
run: {{ .Setup }}
working-directory: {{ .Path }}
{{- end }}
{{- range .Components }}
{{- if ne .InstallDependenciesCommand "" }}
- name: Component Dependency Installation
run: {{ .InstallDependenciesCommand }}
working-directory: {{ .Path }}
{{- end }}
{{- end }}
- name: Build {{ .Name }}
run: spin build
working-directory: {{ .Path }}
{{- if ne .Teardown "" }}
- name: Executing Teardown Commands for {{ .Name }}
run: {{ .Teardown }}
working-directory: {{ .Path }}
{{- end }}
{{- end}}
Loading

0 comments on commit 3f596f2

Please sign in to comment.