1
0
Fork 0
mirror of https://code.forgejo.org/forgejo/runner.git synced 2025-08-11 17:50:58 +00:00

feat: add option to bypass GHE for actions checkout (#1162)

* feat(#1161): add --through-action to assigned actions from GitHub

* docs(flags): add --through-action and --through-action-token flags description

* test(action, remote): add test case for ThroughAction

* refactor(command): rename command from --through-action to --actions-from-github

* refactor(command): rename command from --actions-from-github to --replace-ghe-action-with-github-com
This commit is contained in:
Neo Hsu 2022-06-21 21:52:21 +08:00 committed by GitHub
parent 734c956a07
commit 17228c4316
5 changed files with 248 additions and 91 deletions

View file

@ -25,35 +25,37 @@ type Runner interface {
// Config contains the config for a new runner // Config contains the config for a new runner
type Config struct { type Config struct {
Actor string // the user that triggered the event Actor string // the user that triggered the event
Workdir string // path to working directory Workdir string // path to working directory
BindWorkdir bool // bind the workdir to the job container BindWorkdir bool // bind the workdir to the job container
EventName string // name of event to run EventName string // name of event to run
EventPath string // path to JSON file to use for event.json in containers EventPath string // path to JSON file to use for event.json in containers
DefaultBranch string // name of the main branch for this repository DefaultBranch string // name of the main branch for this repository
ReuseContainers bool // reuse containers to maintain state ReuseContainers bool // reuse containers to maintain state
ForcePull bool // force pulling of the image, even if already present ForcePull bool // force pulling of the image, even if already present
ForceRebuild bool // force rebuilding local docker image action ForceRebuild bool // force rebuilding local docker image action
LogOutput bool // log the output from docker run LogOutput bool // log the output from docker run
JSONLogger bool // use json or text logger JSONLogger bool // use json or text logger
Env map[string]string // env for containers Env map[string]string // env for containers
Secrets map[string]string // list of secrets Secrets map[string]string // list of secrets
Token string // GitHub token Token string // GitHub token
InsecureSecrets bool // switch hiding output when printing to terminal InsecureSecrets bool // switch hiding output when printing to terminal
Platforms map[string]string // list of platforms Platforms map[string]string // list of platforms
Privileged bool // use privileged mode Privileged bool // use privileged mode
UsernsMode string // user namespace to use UsernsMode string // user namespace to use
ContainerArchitecture string // Desired OS/architecture platform for running containers ContainerArchitecture string // Desired OS/architecture platform for running containers
ContainerDaemonSocket string // Path to Docker daemon socket ContainerDaemonSocket string // Path to Docker daemon socket
UseGitIgnore bool // controls if paths in .gitignore should not be copied into container, default true UseGitIgnore bool // controls if paths in .gitignore should not be copied into container, default true
GitHubInstance string // GitHub instance to use, default "github.com" GitHubInstance string // GitHub instance to use, default "github.com"
ContainerCapAdd []string // list of kernel capabilities to add to the containers ContainerCapAdd []string // list of kernel capabilities to add to the containers
ContainerCapDrop []string // list of kernel capabilities to remove from the containers ContainerCapDrop []string // list of kernel capabilities to remove from the containers
AutoRemove bool // controls if the container is automatically removed upon workflow completion AutoRemove bool // controls if the container is automatically removed upon workflow completion
ArtifactServerPath string // the path where the artifact server stores uploads ArtifactServerPath string // the path where the artifact server stores uploads
ArtifactServerPort string // the port the artifact server binds to ArtifactServerPort string // the port the artifact server binds to
NoSkipCheckout bool // do not skip actions/checkout NoSkipCheckout bool // do not skip actions/checkout
RemoteName string // remote name in local git repo config RemoteName string // remote name in local git repo config
ReplaceGheActionWithGithubCom []string // Use actions from GitHub Enterprise instance to GitHub
ReplaceGheActionTokenWithGithubCom string // Token of private action repo on GitHub.
} }
// Resolves the equivalent host path inside the container // Resolves the equivalent host path inside the container

View file

@ -55,6 +55,14 @@ func (sar *stepActionRemote) prepareActionExecutor() common.Executor {
return nil return nil
} }
sar.remoteAction.URL = sar.RunContext.Config.GitHubInstance
for _, action := range sar.RunContext.Config.ReplaceGheActionWithGithubCom {
if strings.EqualFold(fmt.Sprintf("%s/%s", sar.remoteAction.Org, sar.remoteAction.Repo), action) {
sar.remoteAction.URL = "github.com"
github.Token = sar.RunContext.Config.ReplaceGheActionTokenWithGithubCom
}
}
actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), strings.ReplaceAll(sar.Step.Uses, "/", "-")) actionDir := fmt.Sprintf("%s/%s", sar.RunContext.ActionCacheDir(), strings.ReplaceAll(sar.Step.Uses, "/", "-"))
gitClone := stepActionRemoteNewCloneExecutor(git.NewGitCloneExecutorInput{ gitClone := stepActionRemoteNewCloneExecutor(git.NewGitCloneExecutorInput{
URL: sar.remoteAction.CloneURL(), URL: sar.remoteAction.CloneURL(),

View file

@ -256,6 +256,147 @@ func TestStepActionRemotePre(t *testing.T) {
} }
} }
func TestStepActionRemotePreThroughAction(t *testing.T) {
table := []struct {
name string
stepModel *model.Step
}{
{
name: "run-pre",
stepModel: &model.Step{
Uses: "org/repo/path@ref",
},
},
}
for _, tt := range table {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
clonedAction := false
sarm := &stepActionRemoteMocks{}
origStepAtionRemoteNewCloneExecutor := stepActionRemoteNewCloneExecutor
stepActionRemoteNewCloneExecutor = func(input git.NewGitCloneExecutorInput) common.Executor {
return func(ctx context.Context) error {
if input.URL == "https://github.com/org/repo" {
clonedAction = true
}
return nil
}
}
defer (func() {
stepActionRemoteNewCloneExecutor = origStepAtionRemoteNewCloneExecutor
})()
sar := &stepActionRemote{
Step: tt.stepModel,
RunContext: &RunContext{
Config: &Config{
GitHubInstance: "https://enterprise.github.com",
ReplaceGheActionWithGithubCom: []string{"org/repo"},
},
Run: &model.Run{
JobID: "1",
Workflow: &model.Workflow{
Jobs: map[string]*model.Job{
"1": {},
},
},
},
},
readAction: sarm.readAction,
}
suffixMatcher := func(suffix string) interface{} {
return mock.MatchedBy(func(actionDir string) bool {
return strings.HasSuffix(actionDir, suffix)
})
}
sarm.On("readAction", sar.Step, suffixMatcher("org-repo-path@ref"), "path", mock.Anything, mock.Anything).Return(&model.Action{}, nil)
err := sar.pre()(ctx)
assert.Nil(t, err)
assert.Equal(t, true, clonedAction)
sarm.AssertExpectations(t)
})
}
}
func TestStepActionRemotePreThroughActionToken(t *testing.T) {
table := []struct {
name string
stepModel *model.Step
}{
{
name: "run-pre",
stepModel: &model.Step{
Uses: "org/repo/path@ref",
},
},
}
for _, tt := range table {
t.Run(tt.name, func(t *testing.T) {
ctx := context.Background()
clonedAction := false
sarm := &stepActionRemoteMocks{}
origStepAtionRemoteNewCloneExecutor := stepActionRemoteNewCloneExecutor
stepActionRemoteNewCloneExecutor = func(input git.NewGitCloneExecutorInput) common.Executor {
return func(ctx context.Context) error {
if input.URL == "https://github.com/org/repo" && input.Token == "PRIVATE_ACTIONS_TOKEN_ON_GITHUB" {
clonedAction = true
}
return nil
}
}
defer (func() {
stepActionRemoteNewCloneExecutor = origStepAtionRemoteNewCloneExecutor
})()
sar := &stepActionRemote{
Step: tt.stepModel,
RunContext: &RunContext{
Config: &Config{
GitHubInstance: "https://enterprise.github.com",
ReplaceGheActionWithGithubCom: []string{"org/repo"},
ReplaceGheActionTokenWithGithubCom: "PRIVATE_ACTIONS_TOKEN_ON_GITHUB",
},
Run: &model.Run{
JobID: "1",
Workflow: &model.Workflow{
Jobs: map[string]*model.Job{
"1": {},
},
},
},
},
readAction: sarm.readAction,
}
suffixMatcher := func(suffix string) interface{} {
return mock.MatchedBy(func(actionDir string) bool {
return strings.HasSuffix(actionDir, suffix)
})
}
sarm.On("readAction", sar.Step, suffixMatcher("org-repo-path@ref"), "path", mock.Anything, mock.Anything).Return(&model.Action{}, nil)
err := sar.pre()(ctx)
assert.Nil(t, err)
assert.Equal(t, true, clonedAction)
sarm.AssertExpectations(t)
})
}
}
func TestStepActionRemotePost(t *testing.T) { func TestStepActionRemotePost(t *testing.T) {
table := []struct { table := []struct {
name string name string

View file

@ -8,39 +8,41 @@ import (
// Input contains the input for the root command // Input contains the input for the root command
type Input struct { type Input struct {
actor string actor string
workdir string workdir string
workflowsPath string workflowsPath string
autodetectEvent bool autodetectEvent bool
eventPath string eventPath string
reuseContainers bool reuseContainers bool
bindWorkdir bool bindWorkdir bool
secrets []string secrets []string
envs []string envs []string
platforms []string platforms []string
dryrun bool dryrun bool
forcePull bool forcePull bool
forceRebuild bool forceRebuild bool
noOutput bool noOutput bool
envfile string envfile string
secretfile string secretfile string
insecureSecrets bool insecureSecrets bool
defaultBranch string defaultBranch string
privileged bool privileged bool
usernsMode string usernsMode string
containerArchitecture string containerArchitecture string
containerDaemonSocket string containerDaemonSocket string
noWorkflowRecurse bool noWorkflowRecurse bool
useGitIgnore bool useGitIgnore bool
githubInstance string githubInstance string
containerCapAdd []string containerCapAdd []string
containerCapDrop []string containerCapDrop []string
autoRemove bool autoRemove bool
artifactServerPath string artifactServerPath string
artifactServerPort string artifactServerPort string
jsonLogger bool jsonLogger bool
noSkipCheckout bool noSkipCheckout bool
remoteName string remoteName string
replaceGheActionWithGithubCom []string
replaceGheActionTokenWithGithubCom string
} }
func (i *Input) resolve(path string) string { func (i *Input) resolve(path string) string {

View file

@ -61,6 +61,8 @@ func Execute(ctx context.Context, version string) {
rootCmd.Flags().StringArrayVarP(&input.containerCapAdd, "container-cap-add", "", []string{}, "kernel capabilities to add to the workflow containers (e.g. --container-cap-add SYS_PTRACE)") rootCmd.Flags().StringArrayVarP(&input.containerCapAdd, "container-cap-add", "", []string{}, "kernel capabilities to add to the workflow containers (e.g. --container-cap-add SYS_PTRACE)")
rootCmd.Flags().StringArrayVarP(&input.containerCapDrop, "container-cap-drop", "", []string{}, "kernel capabilities to remove from the workflow containers (e.g. --container-cap-drop SYS_PTRACE)") rootCmd.Flags().StringArrayVarP(&input.containerCapDrop, "container-cap-drop", "", []string{}, "kernel capabilities to remove from the workflow containers (e.g. --container-cap-drop SYS_PTRACE)")
rootCmd.Flags().BoolVar(&input.autoRemove, "rm", false, "automatically remove container(s)/volume(s) after a workflow(s) failure") rootCmd.Flags().BoolVar(&input.autoRemove, "rm", false, "automatically remove container(s)/volume(s) after a workflow(s) failure")
rootCmd.Flags().StringArrayVarP(&input.replaceGheActionWithGithubCom, "replace-ghe-action-with-github-com", "", []string{}, "If you are using GitHub Enterprise Server and allow specified actions from GitHub (github.com), you can set actions on this. (e.g. --replace-ghe-action-with-github-com =github/super-linter)")
rootCmd.Flags().StringVar(&input.replaceGheActionTokenWithGithubCom, "replace-ghe-action-token-with-github-com", "", "If you are using replace-ghe-action-with-github-com and you want to use private actions on GitHub, you have to set personal access token")
rootCmd.PersistentFlags().StringVarP(&input.actor, "actor", "a", "nektos/act", "user that triggered the event") rootCmd.PersistentFlags().StringVarP(&input.actor, "actor", "a", "nektos/act", "user that triggered the event")
rootCmd.PersistentFlags().StringVarP(&input.workflowsPath, "workflows", "W", "./.github/workflows/", "path to workflow file(s)") rootCmd.PersistentFlags().StringVarP(&input.workflowsPath, "workflows", "W", "./.github/workflows/", "path to workflow file(s)")
rootCmd.PersistentFlags().BoolVarP(&input.noWorkflowRecurse, "no-recurse", "", false, "Flag to disable running workflows from subdirectories of specified path in '--workflows'/'-W' flag") rootCmd.PersistentFlags().BoolVarP(&input.noWorkflowRecurse, "no-recurse", "", false, "Flag to disable running workflows from subdirectories of specified path in '--workflows'/'-W' flag")
@ -370,35 +372,37 @@ func newRunCommand(ctx context.Context, input *Input) func(*cobra.Command, []str
// run the plan // run the plan
config := &runner.Config{ config := &runner.Config{
Actor: input.actor, Actor: input.actor,
EventName: eventName, EventName: eventName,
EventPath: input.EventPath(), EventPath: input.EventPath(),
DefaultBranch: defaultbranch, DefaultBranch: defaultbranch,
ForcePull: input.forcePull, ForcePull: input.forcePull,
ForceRebuild: input.forceRebuild, ForceRebuild: input.forceRebuild,
ReuseContainers: input.reuseContainers, ReuseContainers: input.reuseContainers,
Workdir: input.Workdir(), Workdir: input.Workdir(),
BindWorkdir: input.bindWorkdir, BindWorkdir: input.bindWorkdir,
LogOutput: !input.noOutput, LogOutput: !input.noOutput,
JSONLogger: input.jsonLogger, JSONLogger: input.jsonLogger,
Env: envs, Env: envs,
Secrets: secrets, Secrets: secrets,
Token: secrets["GITHUB_TOKEN"], Token: secrets["GITHUB_TOKEN"],
InsecureSecrets: input.insecureSecrets, InsecureSecrets: input.insecureSecrets,
Platforms: input.newPlatforms(), Platforms: input.newPlatforms(),
Privileged: input.privileged, Privileged: input.privileged,
UsernsMode: input.usernsMode, UsernsMode: input.usernsMode,
ContainerArchitecture: input.containerArchitecture, ContainerArchitecture: input.containerArchitecture,
ContainerDaemonSocket: input.containerDaemonSocket, ContainerDaemonSocket: input.containerDaemonSocket,
UseGitIgnore: input.useGitIgnore, UseGitIgnore: input.useGitIgnore,
GitHubInstance: input.githubInstance, GitHubInstance: input.githubInstance,
ContainerCapAdd: input.containerCapAdd, ContainerCapAdd: input.containerCapAdd,
ContainerCapDrop: input.containerCapDrop, ContainerCapDrop: input.containerCapDrop,
AutoRemove: input.autoRemove, AutoRemove: input.autoRemove,
ArtifactServerPath: input.artifactServerPath, ArtifactServerPath: input.artifactServerPath,
ArtifactServerPort: input.artifactServerPort, ArtifactServerPort: input.artifactServerPort,
NoSkipCheckout: input.noSkipCheckout, NoSkipCheckout: input.noSkipCheckout,
RemoteName: input.remoteName, RemoteName: input.remoteName,
ReplaceGheActionWithGithubCom: input.replaceGheActionWithGithubCom,
ReplaceGheActionTokenWithGithubCom: input.replaceGheActionTokenWithGithubCom,
} }
r, err := runner.New(config) r, err := runner.New(config)
if err != nil { if err != nil {