mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-05 22:26:41 +00:00
Merge pull request #139 from Infisical/cli-multi-command
Cli multi command support
This commit is contained in:
+83
-14
@@ -8,6 +8,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
|
"runtime"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
@@ -19,12 +20,38 @@ import (
|
|||||||
|
|
||||||
// runCmd represents the run command
|
// runCmd represents the run command
|
||||||
var runCmd = &cobra.Command{
|
var runCmd = &cobra.Command{
|
||||||
|
Example: `
|
||||||
|
infisical run --env=dev -- npm run dev
|
||||||
|
infisical run --command "first-command && second-command; more-commands..."
|
||||||
|
`,
|
||||||
Use: "run [any infisical run command flags] -- [your application start command]",
|
Use: "run [any infisical run command flags] -- [your application start command]",
|
||||||
Short: "Used to inject environments variables into your application process",
|
Short: "Used to inject environments variables into your application process",
|
||||||
DisableFlagsInUseLine: true,
|
DisableFlagsInUseLine: true,
|
||||||
Example: "infisical run --env=prod -- npm run dev",
|
|
||||||
Args: cobra.MinimumNArgs(1),
|
|
||||||
PreRun: toggleDebug,
|
PreRun: toggleDebug,
|
||||||
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
|
// Check if the --command flag has been set
|
||||||
|
commandFlagSet := cmd.Flags().Changed("command")
|
||||||
|
|
||||||
|
// If the --command flag has been set, check if a value was provided
|
||||||
|
if commandFlagSet {
|
||||||
|
command := cmd.Flag("command").Value.String()
|
||||||
|
if command == "" {
|
||||||
|
return fmt.Errorf("you need to provide a command after the flag --command")
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the --command flag has been set, args should not be provided
|
||||||
|
if len(args) > 0 {
|
||||||
|
return fmt.Errorf("you cannot set any arguments after --command flag. --command only takes a string command")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// If the --command flag has not been set, at least one arg should be provided
|
||||||
|
if len(args) == 0 {
|
||||||
|
return fmt.Errorf("at least one argument is required after the run command, received %d", len(args))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
},
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
envName, err := cmd.Flags().GetString("env")
|
envName, err := cmd.Flags().GetString("env")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -54,10 +81,23 @@ var runCmd = &cobra.Command{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if shouldExpandSecrets {
|
if shouldExpandSecrets {
|
||||||
secretsWithSubstitutions := util.SubstituteSecrets(secrets)
|
secrets = util.SubstituteSecrets(secrets)
|
||||||
execCmd(args[0], args[1:], secretsWithSubstitutions)
|
}
|
||||||
|
|
||||||
|
if cmd.Flags().Changed("command") {
|
||||||
|
command := cmd.Flag("command").Value.String()
|
||||||
|
err = executeMultipleCommandWithEnvs(command, secrets)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Something went wrong when executing your command [error=%s]", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
execCmd(args[0], args[1:], secrets)
|
err = executeSingleCommandWithEnvs(args, secrets)
|
||||||
|
if err != nil {
|
||||||
|
log.Errorf("Something went wrong when executing your command [error=%s]", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
@@ -68,22 +108,51 @@ func init() {
|
|||||||
runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from")
|
runCmd.Flags().StringP("env", "e", "dev", "Set the environment (dev, prod, etc.) from which your secrets should be pulled from")
|
||||||
runCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from")
|
runCmd.Flags().String("projectId", "", "The project ID from which your secrets should be pulled from")
|
||||||
runCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
|
runCmd.Flags().Bool("expand", true, "Parse shell parameter expansions in your secrets")
|
||||||
|
runCmd.Flags().StringP("command", "c", "", "chained commands to execute (e.g. \"npm install && npm run dev; echo ...\")")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Credit: inspired by AWS Valut
|
// Will execute a single command and pass in the given secrets into the process
|
||||||
func execCmd(command string, args []string, envs []models.SingleEnvironmentVariable) error {
|
func executeSingleCommandWithEnvs(args []string, secrets []models.SingleEnvironmentVariable) error {
|
||||||
numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(envs))
|
command := args[0]
|
||||||
|
argsForCommand := args[1:]
|
||||||
|
numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets))
|
||||||
log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected)
|
log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected)
|
||||||
log.Debugf("executing command: %s %s \n", command, strings.Join(args, " "))
|
log.Debugf("executing command: %s %s \n", command, strings.Join(argsForCommand, " "))
|
||||||
log.Debugln("Secrets injected:", envs)
|
log.Debugln("Secrets injected:", secrets)
|
||||||
|
|
||||||
cmd := exec.Command(command, args...)
|
cmd := exec.Command(command, argsForCommand...)
|
||||||
cmd.Stdin = os.Stdin
|
cmd.Stdin = os.Stdin
|
||||||
cmd.Stdout = os.Stdout
|
cmd.Stdout = os.Stdout
|
||||||
cmd.Stderr = os.Stderr
|
cmd.Stderr = os.Stderr
|
||||||
cmd.Env = getAllEnvs(envs)
|
cmd.Env = getAllEnvs(secrets)
|
||||||
|
|
||||||
|
return execCmd(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeMultipleCommandWithEnvs(fullCommand string, secrets []models.SingleEnvironmentVariable) error {
|
||||||
|
shell := [2]string{"sh", "-c"}
|
||||||
|
if runtime.GOOS == "windows" {
|
||||||
|
shell = [2]string{"cmd", "/C"}
|
||||||
|
} else {
|
||||||
|
shell[0] = os.Getenv("SHELL")
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command(shell[0], shell[1], fullCommand)
|
||||||
|
cmd.Stdin = os.Stdin
|
||||||
|
cmd.Stdout = os.Stdout
|
||||||
|
cmd.Stderr = os.Stderr
|
||||||
|
cmd.Env = getAllEnvs(secrets)
|
||||||
|
|
||||||
|
numberOfSecretsInjected := fmt.Sprintf("\u2713 Injected %v Infisical secrets into your application process successfully", len(secrets))
|
||||||
|
log.Infof("\x1b[%dm%s\x1b[0m", 32, numberOfSecretsInjected)
|
||||||
|
log.Debugf("executing command: %s %s %s \n", shell[0], shell[1], fullCommand)
|
||||||
|
log.Debugln("Secrets injected:", secrets)
|
||||||
|
|
||||||
|
return execCmd(cmd)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Credit: inspired by AWS Valut
|
||||||
|
func execCmd(cmd *exec.Cmd) error {
|
||||||
sigChannel := make(chan os.Signal, 1)
|
sigChannel := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigChannel)
|
signal.Notify(sigChannel)
|
||||||
|
|
||||||
@@ -100,7 +169,7 @@ func execCmd(command string, args []string, envs []models.SingleEnvironmentVaria
|
|||||||
|
|
||||||
if err := cmd.Wait(); err != nil {
|
if err := cmd.Wait(); err != nil {
|
||||||
_ = cmd.Process.Signal(os.Kill)
|
_ = cmd.Process.Signal(os.Kill)
|
||||||
return fmt.Errorf("Failed to wait for command termination: %v", err)
|
return fmt.Errorf("failed to wait for command termination: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
waitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus)
|
waitStatus := cmd.ProcessState.Sys().(syscall.WaitStatus)
|
||||||
|
|||||||
@@ -2,9 +2,25 @@
|
|||||||
title: "infisical run"
|
title: "infisical run"
|
||||||
---
|
---
|
||||||
|
|
||||||
```bash
|
<Tabs>
|
||||||
infisical run [options] -- [your application start command]
|
<Tab title="Single command">
|
||||||
```
|
```bash
|
||||||
|
infisical run [options] -- [your application start command]
|
||||||
|
|
||||||
|
# Example
|
||||||
|
infisical run [options] -- npm run dev
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
|
||||||
|
<Tab title="Chained commands">
|
||||||
|
```bash
|
||||||
|
infisical run [options] --command [string command]
|
||||||
|
|
||||||
|
# Example
|
||||||
|
infisical run [options] --command "npm run bootstrap && npm run dev start; other-bash-command"
|
||||||
|
```
|
||||||
|
</Tab>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
|
|
||||||
@@ -15,5 +31,6 @@ Inject environment variables from the platform into an application process.
|
|||||||
| Option | Description | Default value |
|
| Option | Description | Default value |
|
||||||
| -------------- | ----------------------------------------------------------------------------------------------------------- | ------------- |
|
| -------------- | ----------------------------------------------------------------------------------------------------------- | ------------- |
|
||||||
| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` |
|
| `--env` | Used to set the environment that secrets are pulled from. Accepted values: `dev`, `staging`, `test`, `prod` | `dev` |
|
||||||
| `--projectId` | Used to link a local project to the platform (required only if injecting via the service token method) | `None` |
|
| `--projectId` | Used to link a local project to the platform (required only if injecting via the service token method) | None |
|
||||||
| `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` |
|
| `--expand` | Parse shell parameter expansions in your secrets (e.g., `${DOMAIN}`) | `true` |
|
||||||
|
| `--command` | Pass secrets into chained commands (e.g., `"first-command && second-command; more-commands..."`) | None |
|
||||||
|
|||||||
Reference in New Issue
Block a user