Skip to content

Commit

Permalink
uncommmit later
Browse files Browse the repository at this point in the history
  • Loading branch information
aweris committed Jul 24, 2023
1 parent 79df86c commit 8e3bccf
Show file tree
Hide file tree
Showing 6 changed files with 197 additions and 7 deletions.
8 changes: 8 additions & 0 deletions pkg/gale/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,13 @@ func (e *Env) WithContainerFunc(container *dagger.Container) *dagger.Container {

e.artifacts = artifactService // save for later access

// runner context

rc := model.NewRunnerContextFromEnv()

for k, v := range rc.ToEnv() {
container = container.WithEnvVariable(k, v)
}

return container
}
2 changes: 2 additions & 0 deletions pkg/gale/gale.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ func NewFromContainer(cfg *config.Config, client *dagger.Client, base *dagger.Co
return nil, fmt.Errorf("failed to get initial github context: %w", err)
}

gale.github = github

// adds the default modifier functions to the gale instance
gale.init()
gale.loadCurrentRepository()
Expand Down
27 changes: 20 additions & 7 deletions pkg/gale/job.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,22 +65,35 @@ func (j *Job) Load(ctx context.Context, workflow, job string) (*Job, error) {
}

func (j *Job) WithContainerFunc(container *dagger.Container) *dagger.Container {
data, err := json.Marshal(j.config)
if err != nil {
fail(container, err)
}

// TODO: look better way to generate run id, uuid is unique but not readable

runID := uuid.New().String()

// unique path for the job
path := filepath.Join(containerRunnerPath, "runs", runID)

// marshal event to json
event, err := json.Marshal(j.config.GithubContext.Event)
if err != nil {
fail(container, err)
}

// update event path to point to the event.json file
j.config.GithubContext.EventPath = filepath.Join(path, "event.json")

// marshal config to json
config, err := json.Marshal(j.config)
if err != nil {
fail(container, err)
}

// create initial directory for the job and mount it to the container
dir := j.client.Directory().WithNewFile("config.json", string(data))
dir := j.client.Directory().
WithNewFile("config.json", string(config)).
WithNewFile("event.json", string(event))

container = container.WithMountedDirectory(path, dir)
container = container.WithMountedDirectory(path, dir) // mount job directory to the container
container = container.WithDirectory(j.config.GithubContext.Workspace, j.client.Host().Directory(".")) // mount workspace to the container
container = container.WithExec([]string{"ghx", "run", runID})

// load final directory for the job
Expand Down
45 changes: 45 additions & 0 deletions test/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package main

import (
"context"
"fmt"
"os"

"dagger.io/dagger"
"github.com/aweris/gale/internal/dagger/images"
"github.com/aweris/gale/pkg/config"
"github.com/aweris/gale/pkg/gale"
)

func main() {
ctx := context.Background()

client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stdout))
if err != nil {
fmt.Printf("Error connecting to dagger: %v\n", err)
os.Exit(1)
}
defer client.Close()

container := images.RunnerBase(client)

g, err := gale.New(&config.Config{}, client)
if err != nil {
fmt.Printf("Error creating gale: %v\n", err)
os.Exit(1)

Check failure on line 29 in test/main.go

View workflow job for this annotation

GitHub Actions / golangci-lint

exitAfterDefer: os.Exit will exit, and `defer client.Close()` will not run (gocritic)
}

job, err := g.Job().Load(ctx, "example-golangci-lint", "golangci-lint")
if err != nil {
fmt.Printf("Error loading job: %v\n", err)
os.Exit(1)
}

env := g.Env()

_, err = container.With(gale.Load(env)).With(gale.Load(job)).Sync(ctx)
if err != nil {
fmt.Printf("Error syncing container: %v\n", err)
os.Exit(1)
}
}
119 changes: 119 additions & 0 deletions tools/ghx/runner/cmd_executor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package runner

import (
"context"
"fmt"
"github.com/aweris/gale/tools/ghx/actions"
"os"
"os/exec"
"path/filepath"
"strings"
)

type CmdExecutor struct {
command string // command to execute
args []string // args to pass to the command
env map[string]string // env to pass to the command as environment variables
ac *actions.Context // ac is the action context
ef map[string]*actions.EnvironmentFile // ef is the list of environment files
}

func NewCmdExecutorFromStepAction(sa *StepAction, entrypoint string) *CmdExecutor {
ce := &CmdExecutor{env: make(map[string]string), ef: make(map[string]*actions.EnvironmentFile)}

ce.command = "node"
ce.args = append(ce.args, fmt.Sprintf("%s/%s", sa.Action.Path, entrypoint))
ce.ac = sa.ac

// env
for k, v := range sa.ac.Github.ToEnv() {
ce.env[k] = v
}

for k, v := range sa.ac.Env.Env() {
ce.env[k] = v
}

for k, v := range sa.Step.With {
ce.env[fmt.Sprintf("INPUT_%s", strings.ToUpper(k))] = v
}

// add default values for inputs that are not defined in the step config
for k, v := range sa.Action.Meta.Inputs {
if _, ok := sa.Step.With[k]; ok {
continue
}

if v.Default == "" {
continue
}

ce.env[fmt.Sprintf("INPUT_%s", strings.ToUpper(k))] = v.Default
}

// TODO add step state to the environment

return ce
}

func (c *CmdExecutor) Execute(_ context.Context) error {

cmd := exec.Command(c.command, c.args...)

cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr

// load env files before setting the environment variables to the command. This is because the env files
// are loaded from the environment variables and loadEnvFile function will override the environment variable
// with the path of the file

// TODO: replace this temp dir with a a step specific temp dir under runs/run-id/job-id/step-id
dir := os.TempDir()

if err := c.loadEnvFile(actions.EnvFileNameGithubEnv, filepath.Join(dir, "env")); err != nil {
return err
}

if err := c.loadEnvFile(actions.EnvFileNameGithubPath, filepath.Join(dir, "path")); err != nil {
return err
}

if err := c.loadEnvFile(actions.EnvFileNameGithubStepSummary, filepath.Join(dir, "step_summary")); err != nil {
return err
}

if err := c.loadEnvFile(actions.EnvFileNameGithubActionOutput, filepath.Join(dir, "github_action_output")); err != nil {
return err
}

env := os.Environ()

for k, v := range c.env {
// convert value to Evaluable String type
str := actions.NewString(v)

// evaluate the expression
res, err := str.Eval(c.ac)
if err != nil {
return fmt.Errorf("failed to evaluate default value for input %s: %v", k, err)
}

env = append(env, fmt.Sprintf("%s=%s", k, res))
}

cmd.Env = env

return cmd.Run()
}

func (c *CmdExecutor) loadEnvFile(env, path string) error {
ef, err := actions.NewEnvironmentFile(path)
if err != nil {
return err
}

c.ef[env] = ef // add file to a map to process after the command execution
c.env[env] = ef.Path // set the environment variable to the path of the file

return nil
}
3 changes: 3 additions & 0 deletions tools/ghx/runner/runner_step.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ func (s *StepAction) mainCondition() TaskConditionalFn {

func (s *StepAction) main() TaskExecutorFn {
return func(ctx context.Context) (model.Conclusion, error) {

NewCmdExecutorFromStepAction(s, s.Action.Meta.Runs.Main).Execute(ctx)

return model.ConclusionFailure, fmt.Errorf("main run is not implemented yet")
}
}
Expand Down

0 comments on commit 8e3bccf

Please sign in to comment.