fix: reworked container architecture (#619)
- Don't set architecture, let Docker host decide it's own platform, remove `runtime` dependency and don't show default in `--help` - Remove most tests, we need to check only once if it works on different platform - Rename `DeleteImage` to `RemoveImage` to conform to existing function in `docker` cli, added options to specify `force` and `pruneChildren`
This commit is contained in:
parent
3e768cd916
commit
f32babb51d
8 changed files with 73 additions and 103 deletions
|
@ -88,7 +88,7 @@ It will save that information to `~/.actrc`, please refer to [Configuration](#co
|
||||||
```none
|
```none
|
||||||
-a, --actor string user that triggered the event (default "nektos/act")
|
-a, --actor string user that triggered the event (default "nektos/act")
|
||||||
-b, --bind bind working directory to container, rather than copy
|
-b, --bind bind working directory to container, rather than copy
|
||||||
--container-architecture string Architecture which should be used to run containers, e.g.: linux/amd64. Defaults to linux/<your machine architecture> [linux/amd64]. Requires Docker server API Version 1.41+. Ignored on earlier Docker server platforms.
|
--container-architecture string Architecture which should be used to run containers, e.g.: linux/amd64. If not specified, will use host default architecture. Requires Docker server API Version 1.41+. Ignored on earlier Docker server platforms.
|
||||||
--defaultbranch string the name of the main branch
|
--defaultbranch string the name of the main branch
|
||||||
--detect-event Use first event type from workflow as event that triggered the workflow
|
--detect-event Use first event type from workflow as event that triggered the workflow
|
||||||
-C, --directory string working directory (default ".")
|
-C, --directory string working directory (default ".")
|
||||||
|
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"regexp"
|
"regexp"
|
||||||
"runtime"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/nektos/act/pkg/common"
|
"github.com/nektos/act/pkg/common"
|
||||||
|
@ -59,7 +58,7 @@ func Execute(ctx context.Context, version string) {
|
||||||
rootCmd.PersistentFlags().StringVarP(&input.secretfile, "secret-file", "", ".secrets", "file with list of secrets to read from (e.g. --secret-file .secrets)")
|
rootCmd.PersistentFlags().StringVarP(&input.secretfile, "secret-file", "", ".secrets", "file with list of secrets to read from (e.g. --secret-file .secrets)")
|
||||||
rootCmd.PersistentFlags().BoolVarP(&input.insecureSecrets, "insecure-secrets", "", false, "NOT RECOMMENDED! Doesn't hide secrets while printing logs.")
|
rootCmd.PersistentFlags().BoolVarP(&input.insecureSecrets, "insecure-secrets", "", false, "NOT RECOMMENDED! Doesn't hide secrets while printing logs.")
|
||||||
rootCmd.PersistentFlags().StringVarP(&input.envfile, "env-file", "", ".env", "environment file to read and use as env in the containers")
|
rootCmd.PersistentFlags().StringVarP(&input.envfile, "env-file", "", ".env", "environment file to read and use as env in the containers")
|
||||||
rootCmd.PersistentFlags().StringVarP(&input.containerArchitecture, "container-architecture", "", "", "Architecture which should be used to run containers, e.g.: linux/amd64. Defaults to linux/<your machine architecture> [linux/"+runtime.GOARCH+"]. Requires Docker server API Version 1.41+. Ignored on earlier Docker server platforms.")
|
rootCmd.PersistentFlags().StringVarP(&input.containerArchitecture, "container-architecture", "", "", "Architecture which should be used to run containers, e.g.: linux/amd64. If not specified, will use host default architecture. Requires Docker server API Version 1.41+. Ignored on earlier Docker server platforms.")
|
||||||
rootCmd.SetArgs(args())
|
rootCmd.SetArgs(args())
|
||||||
|
|
||||||
if err := rootCmd.Execute(); err != nil {
|
if err := rootCmd.Execute(); err != nil {
|
||||||
|
|
|
@ -29,7 +29,7 @@ func ImageExistsLocally(ctx context.Context, imageName string, platform string)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(images) > 0 {
|
if len(images) > 0 {
|
||||||
if platform == "any" {
|
if platform == "any" || platform == "" {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
for _, v := range images {
|
for _, v := range images {
|
||||||
|
@ -48,9 +48,9 @@ func ImageExistsLocally(ctx context.Context, imageName string, platform string)
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeleteImage removes image from local store, the function is used to run different
|
// RemoveImage removes image from local store, the function is used to run different
|
||||||
// container image architectures
|
// container image architectures
|
||||||
func DeleteImage(ctx context.Context, imageName string) (bool, error) {
|
func RemoveImage(ctx context.Context, imageName string, force bool, pruneChildren bool) (bool, error) {
|
||||||
if exists, err := ImageExistsLocally(ctx, imageName, "any"); !exists {
|
if exists, err := ImageExistsLocally(ctx, imageName, "any"); !exists {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
@ -75,8 +75,8 @@ func DeleteImage(ctx context.Context, imageName string) (bool, error) {
|
||||||
if len(images) > 0 {
|
if len(images) > 0 {
|
||||||
for _, v := range images {
|
for _, v := range images {
|
||||||
if _, err = cli.ImageRemove(ctx, v.ID, types.ImageRemoveOptions{
|
if _, err = cli.ImageRemove(ctx, v.ID, types.ImageRemoveOptions{
|
||||||
Force: true,
|
Force: force,
|
||||||
PruneChildren: true,
|
PruneChildren: pruneChildren,
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,7 +293,7 @@ func (cr *containerReference) create() common.Executor {
|
||||||
}
|
}
|
||||||
|
|
||||||
var platSpecs *specs.Platform
|
var platSpecs *specs.Platform
|
||||||
if supportsContainerImagePlatform(cr.cli) {
|
if supportsContainerImagePlatform(cr.cli) && cr.input.Platform != "" {
|
||||||
desiredPlatform := strings.SplitN(cr.input.Platform, `/`, 2)
|
desiredPlatform := strings.SplitN(cr.input.Platform, `/`, 2)
|
||||||
|
|
||||||
if len(desiredPlatform) != 2 {
|
if len(desiredPlatform) != 2 {
|
||||||
|
|
|
@ -96,10 +96,6 @@ func (rc *RunContext) startJobContainer() common.Executor {
|
||||||
binds = append(binds, fmt.Sprintf("%s:%s%s", rc.Config.Workdir, rc.Config.Workdir, bindModifiers))
|
binds = append(binds, fmt.Sprintf("%s:%s%s", rc.Config.Workdir, rc.Config.Workdir, bindModifiers))
|
||||||
}
|
}
|
||||||
|
|
||||||
if rc.Config.ContainerArchitecture == "" {
|
|
||||||
rc.Config.ContainerArchitecture = fmt.Sprintf("%s/%s", "linux", runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
rc.JobContainer = container.NewContainer(&container.NewContainerInput{
|
rc.JobContainer = container.NewContainer(&container.NewContainerInput{
|
||||||
Cmd: nil,
|
Cmd: nil,
|
||||||
Entrypoint: []string{"/usr/bin/tail", "-f", "/dev/null"},
|
Entrypoint: []string{"/usr/bin/tail", "-f", "/dev/null"},
|
||||||
|
|
|
@ -79,45 +79,28 @@ func TestRunEvent(t *testing.T) {
|
||||||
"ubuntu-latest": "node:12.20.1-buster-slim",
|
"ubuntu-latest": "node:12.20.1-buster-slim",
|
||||||
}
|
}
|
||||||
tables := []TestJobFileInfo{
|
tables := []TestJobFileInfo{
|
||||||
// {"testdata", "powershell", "push", "", platforms}, // Powershell is not available on default act test runner (yet) but preserving here for posterity
|
{"testdata", "basic", "push", "", platforms, ""},
|
||||||
{"testdata", "basic", "push", "", platforms, "linux/amd64"},
|
{"testdata", "fail", "push", "exit with `FAILURE`: 1", platforms, ""},
|
||||||
{"testdata", "fail", "push", "exit with `FAILURE`: 1", platforms, "linux/amd64"},
|
{"testdata", "runs-on", "push", "", platforms, ""},
|
||||||
{"testdata", "runs-on", "push", "", platforms, "linux/amd64"},
|
{"testdata", "job-container", "push", "", platforms, ""},
|
||||||
{"testdata", "job-container", "push", "", platforms, "linux/amd64"},
|
{"testdata", "job-container-non-root", "push", "", platforms, ""},
|
||||||
{"testdata", "job-container-non-root", "push", "", platforms, "linux/amd64"},
|
{"testdata", "uses-docker-url", "push", "", platforms, ""},
|
||||||
{"testdata", "uses-docker-url", "push", "", platforms, "linux/amd64"},
|
{"testdata", "remote-action-docker", "push", "", platforms, ""},
|
||||||
{"testdata", "remote-action-docker", "push", "", platforms, "linux/amd64"},
|
{"testdata", "remote-action-js", "push", "", platforms, ""},
|
||||||
{"testdata", "remote-action-js", "push", "", platforms, "linux/amd64"},
|
{"testdata", "local-action-docker-url", "push", "", platforms, ""},
|
||||||
{"testdata", "local-action-docker-url", "push", "", platforms, "linux/amd64"},
|
{"testdata", "local-action-dockerfile", "push", "", platforms, ""},
|
||||||
{"testdata", "local-action-dockerfile", "push", "", platforms, "linux/amd64"},
|
{"testdata", "local-action-js", "push", "", platforms, ""},
|
||||||
{"testdata", "local-action-js", "push", "", platforms, "linux/amd64"},
|
{"testdata", "matrix", "push", "", platforms, ""},
|
||||||
{"testdata", "matrix", "push", "", platforms, "linux/amd64"},
|
{"testdata", "matrix-include-exclude", "push", "", platforms, ""},
|
||||||
{"testdata", "matrix-include-exclude", "push", "", platforms, "linux/amd64"},
|
{"testdata", "commands", "push", "", platforms, ""},
|
||||||
{"testdata", "commands", "push", "", platforms, "linux/amd64"},
|
{"testdata", "workdir", "push", "", platforms, ""},
|
||||||
{"testdata", "workdir", "push", "", platforms, "linux/amd64"},
|
{"testdata", "defaults-run", "push", "", platforms, ""},
|
||||||
// {"testdata", "issue-228", "push", "", platforms, "linux/amd64"}, // TODO [igni]: Remove this once everything passes
|
{"testdata", "uses-composite", "push", "", platforms, ""},
|
||||||
{"testdata", "defaults-run", "push", "", platforms, "linux/amd64"},
|
// {"testdata", "powershell", "push", "", platforms, ""}, // Powershell is not available on default act test runner (yet) but preserving here for posterity
|
||||||
{"testdata", "uses-composite", "push", "", platforms, "linux/amd64"},
|
// {"testdata", "issue-228", "push", "", platforms, ""}, // TODO [igni]: Remove this once everything passes
|
||||||
|
|
||||||
// linux/arm64
|
// single test for different architecture: linux/arm64
|
||||||
{"testdata", "basic", "push", "", platforms, "linux/arm64"},
|
{"testdata", "basic", "push", "", platforms, "linux/arm64"},
|
||||||
{"testdata", "fail", "push", "exit with `FAILURE`: 1", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "runs-on", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "job-container", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "job-container-non-root", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "uses-docker-url", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "remote-action-docker", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "remote-action-js", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "local-action-docker-url", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "local-action-dockerfile", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "local-action-js", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "matrix", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "matrix-include-exclude", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "commands", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "workdir", "push", "", platforms, "linux/arm64"},
|
|
||||||
// {"testdata", "issue-228", "push", "", platforms, "linux/arm64"}, // TODO [igni]: Remove this once everything passes
|
|
||||||
{"testdata", "defaults-run", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "uses-composite", "push", "", platforms, "linux/arm64"},
|
|
||||||
}
|
}
|
||||||
log.SetLevel(log.DebugLevel)
|
log.SetLevel(log.DebugLevel)
|
||||||
|
|
||||||
|
|
|
@ -252,10 +252,6 @@ func (sc *StepContext) newStepContainer(ctx context.Context, image string, cmd [
|
||||||
binds = append(binds, fmt.Sprintf("%s:%s%s", rc.Config.Workdir, rc.Config.Workdir, bindModifiers))
|
binds = append(binds, fmt.Sprintf("%s:%s%s", rc.Config.Workdir, rc.Config.Workdir, bindModifiers))
|
||||||
}
|
}
|
||||||
|
|
||||||
if rc.Config.ContainerArchitecture == "" {
|
|
||||||
rc.Config.ContainerArchitecture = fmt.Sprintf("%s/%s", "linux", runtime.GOARCH)
|
|
||||||
}
|
|
||||||
|
|
||||||
stepContainer := container.NewContainer(&container.NewContainerInput{
|
stepContainer := container.NewContainer(&container.NewContainerInput{
|
||||||
Cmd: cmd,
|
Cmd: cmd,
|
||||||
Entrypoint: entrypoint,
|
Entrypoint: entrypoint,
|
||||||
|
@ -438,33 +434,35 @@ func (sc *StepContext) runAction(actionDir string, actionPath string) common.Exe
|
||||||
image = strings.ToLower(image)
|
image = strings.ToLower(image)
|
||||||
contextDir := filepath.Join(actionDir, actionPath, action.Runs.Main)
|
contextDir := filepath.Join(actionDir, actionPath, action.Runs.Main)
|
||||||
|
|
||||||
exists, err := container.ImageExistsLocally(ctx, image, "any")
|
anyArchExists, err := container.ImageExistsLocally(ctx, image, "any")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if exists {
|
correctArchExists, err := container.ImageExistsLocally(ctx, image, rc.Config.ContainerArchitecture)
|
||||||
wasRemoved, err := container.DeleteImage(ctx, image)
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if anyArchExists && !correctArchExists {
|
||||||
|
wasRemoved, err := container.RemoveImage(ctx, image, true, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !wasRemoved {
|
if !wasRemoved {
|
||||||
return fmt.Errorf("failed to delete image '%s'", image)
|
return fmt.Errorf("failed to remove image '%s'", image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !correctArchExists {
|
||||||
|
log.Debugf("image '%s' for architecture '%s' will be built from context '%s", image, rc.Config.ContainerArchitecture, contextDir)
|
||||||
prepImage = container.NewDockerBuildExecutor(container.NewDockerBuildExecutorInput{
|
prepImage = container.NewDockerBuildExecutor(container.NewDockerBuildExecutorInput{
|
||||||
ContextDir: contextDir,
|
ContextDir: contextDir,
|
||||||
ImageTag: image,
|
ImageTag: image,
|
||||||
Platform: rc.Config.ContainerArchitecture,
|
Platform: rc.Config.ContainerArchitecture,
|
||||||
})
|
})
|
||||||
exists, err = container.ImageExistsLocally(ctx, image, rc.Config.ContainerArchitecture)
|
} else {
|
||||||
if err != nil {
|
log.Debugf("image '%s' for architecture '%s' already exists", image, rc.Config.ContainerArchitecture)
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,17 +12,11 @@ func TestStepContextExecutor(t *testing.T) {
|
||||||
"ubuntu-latest": "node:12.20.1-buster-slim",
|
"ubuntu-latest": "node:12.20.1-buster-slim",
|
||||||
}
|
}
|
||||||
tables := []TestJobFileInfo{
|
tables := []TestJobFileInfo{
|
||||||
{"testdata", "uses-and-run-in-one-step", "push", "Invalid run/uses syntax for job:test step:Test", platforms, "linux/amd64"},
|
{"testdata", "uses-and-run-in-one-step", "push", "Invalid run/uses syntax for job:test step:Test", platforms, ""},
|
||||||
{"testdata", "uses-github-empty", "push", "Expected format {org}/{repo}[/path]@ref", platforms, "linux/amd64"},
|
{"testdata", "uses-github-empty", "push", "Expected format {org}/{repo}[/path]@ref", platforms, ""},
|
||||||
{"testdata", "uses-github-noref", "push", "Expected format {org}/{repo}[/path]@ref", platforms, "linux/amd64"},
|
{"testdata", "uses-github-noref", "push", "Expected format {org}/{repo}[/path]@ref", platforms, ""},
|
||||||
{"testdata", "uses-github-root", "push", "", platforms, "linux/amd64"},
|
{"testdata", "uses-github-root", "push", "", platforms, ""},
|
||||||
{"testdata", "uses-github-path", "push", "", platforms, "linux/amd64"},
|
{"testdata", "uses-github-path", "push", "", platforms, ""},
|
||||||
|
|
||||||
{"testdata", "uses-and-run-in-one-step", "push", "Invalid run/uses syntax for job:test step:Test", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "uses-github-empty", "push", "Expected format {org}/{repo}[/path]@ref", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "uses-github-noref", "push", "Expected format {org}/{repo}[/path]@ref", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "uses-github-root", "push", "", platforms, "linux/arm64"},
|
|
||||||
{"testdata", "uses-github-path", "push", "", platforms, "linux/arm64"},
|
|
||||||
}
|
}
|
||||||
// These tests are sufficient to only check syntax.
|
// These tests are sufficient to only check syntax.
|
||||||
ctx := common.WithDryrun(context.Background(), true)
|
ctx := common.WithDryrun(context.Background(), true)
|
||||||
|
|
Loading…
Reference in a new issue