summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/actions/check/Dockerfile8
-rw-r--r--.github/actions/check/entrypoint.sh8
-rw-r--r--.github/main.workflow14
-rw-r--r--.golangci.yml1
-rw-r--r--Makefile18
-rw-r--r--README.md3
-rw-r--r--actions/api.go13
-rw-r--r--actions/runner_exec.go29
-rw-r--r--cmd/root.go1
-rw-r--r--container/docker_run.go79
-rw-r--r--go.sum1
11 files changed, 105 insertions, 70 deletions
diff --git a/.github/actions/check/Dockerfile b/.github/actions/check/Dockerfile
index 4f299fa..12f9d8d 100644
--- a/.github/actions/check/Dockerfile
+++ b/.github/actions/check/Dockerfile
@@ -1,10 +1,6 @@
-FROM golang:1.11.4-stretch
-
-RUN go get -u honnef.co/go/tools/cmd/staticcheck
-RUN go get -u golang.org/x/lint/golint
-RUN go get -u github.com/fzipp/gocyclo
+FROM golangci/golangci-lint:v1.12.5
COPY "entrypoint.sh" "/entrypoint.sh"
RUN chmod +x /entrypoint.sh
-ENTRYPOINT ["/entrypoint.sh"]
+ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file
diff --git a/.github/actions/check/entrypoint.sh b/.github/actions/check/entrypoint.sh
index 2489661..be59dc9 100644
--- a/.github/actions/check/entrypoint.sh
+++ b/.github/actions/check/entrypoint.sh
@@ -1,10 +1,4 @@
#!/bin/sh
-#GOPATH=/go
-#PATH=${GOPATH}/bin:/usr/local/go/bin:${PATH}
-
-go vet ./...
-golint -set_exit_status ./...
-staticcheck ./...
-gocyclo -over 10 .
+golangci-lint run
go test -cover ./... \ No newline at end of file
diff --git a/.github/main.workflow b/.github/main.workflow
index b6d13a9..afc96ae 100644
--- a/.github/main.workflow
+++ b/.github/main.workflow
@@ -7,15 +7,21 @@ action "check" {
uses = "./.github/actions/check"
}
- action "branch-filter" {
+action "branch-filter" {
needs = ["check"]
uses = "actions/bin/filter@master"
args = "tag v*"
- }
+}
- action "release" {
+action "release" {
needs = ["branch-filter"]
uses = "docker://goreleaser/goreleaser:v0.97"
args = "release"
secrets = ["GITHUB_TOKEN"]
- } \ No newline at end of file
+}
+
+action "build" {
+ uses = "docker://goreleaser/goreleaser:v0.97"
+ args = "--snapshot --rm-dist"
+ secrets = ["SNAPSHOT_VERSION"]
+} \ No newline at end of file
diff --git a/.golangci.yml b/.golangci.yml
index 085539b..8b00dd9 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -15,7 +15,6 @@ linters:
- gosec
- unconvert
- dupl
- - maligned
- nakedret
- prealloc
- scopelint
diff --git a/Makefile b/Makefile
index 310ff96..ad6cf6d 100644
--- a/Makefile
+++ b/Makefile
@@ -12,20 +12,19 @@ endif
IS_SNAPSHOT = $(if $(findstring -, $(VERSION)),true,false)
TAG_VERSION = v$(VERSION)
-default: check
-
-deps:
- curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $$(go env GOPATH)/bin v1.12.5
+ACT ?= go run main.go
+default: check
check:
- golangci-lint run
- go test -cover ./...
+ $(ACT) -ra check
-build: deps check
- @GO111MODULE=off go get github.com/goreleaser/goreleaser
+build: check
$(eval export SNAPSHOT_VERSION=$(VERSION))
- @goreleaser --snapshot --rm-dist
+ $(ACT) -ra build
+
+release:
+ $(ACT) -ra release
install: build
@cp dist/$(shell go env GOOS)_$(shell go env GOARCH)/act /usr/local/bin/act
@@ -36,7 +35,6 @@ installer:
@GO111MODULE=off go get github.com/goreleaser/godownloader
godownloader -r nektos/act -o install.sh
-
promote:
@echo "VERSION:$(VERSION) IS_SNAPSHOT:$(IS_SNAPSHOT) LATEST_VERSION:$(LATEST_VERSION)"
ifeq (false,$(IS_SNAPSHOT))
diff --git a/README.md b/README.md
index 9dafe18..b9e3f2e 100644
--- a/README.md
+++ b/README.md
@@ -41,6 +41,9 @@ act -a test
# Run in dry-run mode:
act -n
+
+# Run in reuse mode to save state:
+act -r
```
# Support
diff --git a/actions/api.go b/actions/api.go
index 0680165..6836596 100644
--- a/actions/api.go
+++ b/actions/api.go
@@ -36,12 +36,13 @@ type ActionRunner interface {
// RunnerConfig contains the config for a new runner
type RunnerConfig struct {
- Ctx context.Context // context to use for the run
- Dryrun bool // don't start any of the containers
- WorkingDir string // base directory to use
- WorkflowPath string // path to load main.workflow file, relative to WorkingDir
- EventName string // name of event to run
- EventPath string // path to JSON file to use for event.json in containers, relative to WorkingDir
+ Ctx context.Context // context to use for the run
+ Dryrun bool // don't start any of the containers
+ WorkingDir string // base directory to use
+ WorkflowPath string // path to load main.workflow file, relative to WorkingDir
+ EventName string // name of event to run
+ EventPath string // path to JSON file to use for event.json in containers, relative to WorkingDir
+ ReuseContainers bool // reuse containers to maintain state
}
type environmentApplier interface {
diff --git a/actions/runner_exec.go b/actions/runner_exec.go
index 2e5e2d4..b6be9a3 100644
--- a/actions/runner_exec.go
+++ b/actions/runner_exec.go
@@ -5,7 +5,6 @@ import (
"bytes"
"fmt"
"io"
- "math/rand"
"os"
"path/filepath"
"regexp"
@@ -78,11 +77,6 @@ func (runner *runnerImpl) newActionExecutor(actionName string) common.Executor {
if err != nil {
return common.NewErrorExecutor(err)
}
- randSuffix := randString(6)
- containerName := regexp.MustCompile("[^a-zA-Z0-9]").ReplaceAllString(actionName, "-")
- if len(containerName)+len(randSuffix)+1 > 30 {
- containerName = containerName[:(30 - (len(randSuffix) + 1))]
- }
envList := make([]string, 0)
for k, v := range env {
@@ -95,13 +89,14 @@ func (runner *runnerImpl) newActionExecutor(actionName string) common.Executor {
Image: image,
WorkingDir: "/github/workspace",
Env: envList,
- Name: fmt.Sprintf("%s-%s", containerName, randSuffix),
+ Name: runner.createContainerName(actionName),
Binds: []string{
fmt.Sprintf("%s:%s", runner.config.WorkingDir, "/github/workspace"),
fmt.Sprintf("%s:%s", runner.tempDir, "/github/home"),
fmt.Sprintf("%s:%s", "/var/run/docker.sock", "/var/run/docker.sock"),
},
- Content: map[string]io.Reader{"/github": ghReader},
+ Content: map[string]io.Reader{"/github": ghReader},
+ ReuseContainers: runner.config.ReuseContainers,
}))
return common.NewPipelineExecutor(executors...)
@@ -174,12 +169,18 @@ func (runner *runnerImpl) createGithubTarball() (io.Reader, error) {
}
-const letterBytes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+func (runner *runnerImpl) createContainerName(actionName string) string {
+ containerName := regexp.MustCompile("[^a-zA-Z0-9]").ReplaceAllString(actionName, "-")
+
+ prefix := fmt.Sprintf("%s-", trimToLen(filepath.Base(runner.config.WorkingDir), 10))
+ suffix := ""
+ containerName = trimToLen(containerName, 30-(len(prefix)+len(suffix)))
+ return fmt.Sprintf("%s%s%s", prefix, containerName, suffix)
+}
-func randString(slen int) string {
- b := make([]byte, slen)
- for i := range b {
- b[i] = letterBytes[rand.Int63()%int64(len(letterBytes))]
+func trimToLen(s string, l int) string {
+ if len(s) > l {
+ return s[:l]
}
- return string(b)
+ return s
}
diff --git a/cmd/root.go b/cmd/root.go
index 932689f..7bfe13d 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -25,6 +25,7 @@ func Execute(ctx context.Context, version string) {
}
rootCmd.Flags().BoolP("list", "l", false, "list actions")
rootCmd.Flags().StringP("action", "a", "", "run action")
+ rootCmd.Flags().BoolVarP(&runnerConfig.ReuseContainers, "reuse", "r", false, "reuse action containers to maintain state")
rootCmd.Flags().StringVarP(&runnerConfig.EventPath, "event", "e", "", "path to event JSON file")
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "verbose output")
rootCmd.PersistentFlags().BoolVarP(&runnerConfig.Dryrun, "dryrun", "n", false, "dryrun mode")
diff --git a/container/docker_run.go b/container/docker_run.go
index 18cda31..b078d60 100644
--- a/container/docker_run.go
+++ b/container/docker_run.go
@@ -16,15 +16,16 @@ import (
// NewDockerRunExecutorInput the input for the NewDockerRunExecutor function
type NewDockerRunExecutorInput struct {
DockerExecutorInput
- Image string
- Entrypoint []string
- Cmd []string
- WorkingDir string
- Env []string
- Binds []string
- Content map[string]io.Reader
- Volumes []string
- Name string
+ Image string
+ Entrypoint []string
+ Cmd []string
+ WorkingDir string
+ Env []string
+ Binds []string
+ Content map[string]io.Reader
+ Volumes []string
+ Name string
+ ReuseContainers bool
}
// NewDockerRunExecutor function to create a run executor for the container
@@ -41,29 +42,44 @@ func NewDockerRunExecutor(input NewDockerRunExecutorInput) common.Executor {
return err
}
- containerID, err := createContainer(input, cli)
+ // check if container exists
+ containerID, err := findContainer(input, cli, input.Name)
if err != nil {
return err
}
- defer removeContainer(input, cli, containerID)
- err = copyContentToContainer(input, cli, containerID)
- if err != nil {
- return err
+ // if we have an old container and we aren't reusing, remove it!
+ if !input.ReuseContainers && containerID != "" {
+ input.Logger.Debugf("Found existing container for %s...removing", input.Name)
+ removeContainer(input, cli, containerID)
+ containerID = ""
}
- err = attachContainer(input, cli, containerID)
- if err != nil {
- return err
+ // create a new container if we don't have one to reuse
+ if containerID == "" {
+ containerID, err = createContainer(input, cli)
+ if err != nil {
+ return err
+ }
}
- err = startContainer(input, cli, containerID)
- if err != nil {
- return err
+ // be sure to cleanup container if we aren't reusing
+ if !input.ReuseContainers {
+ defer removeContainer(input, cli, containerID)
}
- return waitContainer(input, cli, containerID)
-
+ executor := common.NewPipelineExecutor(
+ func() error {
+ return copyContentToContainer(input, cli, containerID)
+ }, func() error {
+ return attachContainer(input, cli, containerID)
+ }, func() error {
+ return startContainer(input, cli, containerID)
+ }, func() error {
+ return waitContainer(input, cli, containerID)
+ },
+ )
+ return executor()
}
}
@@ -99,6 +115,25 @@ func createContainer(input NewDockerRunExecutorInput, cli *client.Client) (strin
return resp.ID, nil
}
+func findContainer(input NewDockerRunExecutorInput, cli *client.Client, containerName string) (string, error) {
+ containers, err := cli.ContainerList(input.Ctx, types.ContainerListOptions{
+ All: true,
+ })
+ if err != nil {
+ return "", err
+ }
+
+ for _, container := range containers {
+ for _, name := range container.Names {
+ if name[1:] == containerName {
+ return container.ID, nil
+ }
+ }
+ }
+
+ return "", nil
+}
+
func removeContainer(input NewDockerRunExecutorInput, cli *client.Client, containerID string) {
err := cli.ContainerRemove(context.Background(), containerID, types.ContainerRemoveOptions{
RemoveVolumes: true,
diff --git a/go.sum b/go.sum
index dc2ceae..2b495e3 100644
--- a/go.sum
+++ b/go.sum
@@ -19,6 +19,7 @@ github.com/docker/distribution v2.7.0+incompatible h1:neUDAlf3wX6Ml4HdqTrbcOHXtf
github.com/docker/distribution v2.7.0+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v1.13.1 h1:IkZjBSIc8hBjLpqeAbeE5mca5mNgeatLHBy3GO78BWo=
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/engine v0.0.0-20181106193140-f5749085e9cb h1:PyjxRdW1mqCmSoxy/6uP01P7CGbsD+woX+oOWbaUPwQ=
github.com/docker/engine v0.0.0-20181106193140-f5749085e9cb/go.mod h1:3CPr2caMgTHxxIAZgEMd3uLYPDlRvPqCpyeRf6ncPcY=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=