Skip to content

Commit

Permalink
feat: add build args
Browse files Browse the repository at this point in the history
  • Loading branch information
bjarneo committed Nov 12, 2024
1 parent 0a46bde commit 258abe6
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 24 deletions.
35 changes: 26 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@

A simple yet powerful Go-based CLI tool for automating Docker container deployments to remote servers. This tool handles the entire deployment process including building Docker images, transferring them to remote hosts, and managing container lifecycle.


https://github.com/user-attachments/assets/1859f611-799e-4a6a-976e-f12ae59c232e

<https://github.com/user-attachments/assets/8dd2cd3b-3e1c-4168-908c-b755418e0ae0>

## Prerequisites

Expand Down Expand Up @@ -72,16 +70,17 @@ go build -o copepod

| Option | Environment Variable | Default | Description |
|-----------------|---------------------|------------------|--------------------------------|
| --host | COPEPOD_HOST | | Remote host to deploy to |
| --user | COPEPOD_USER | | SSH user for remote host |
| --image | COPEPOD_IMAGE | app | Docker image name |
| --tag | COPEPOD_TAG | latest | Docker image tag |
| --platform | COPEPOD_PLATFORM | linux/amd64 | Docker platform |
| --host | DEPLOY_HOST | | Remote host to deploy to |
| --user | DEPLOY_USER | | SSH user for remote host |
| --image | DEPLOY_IMAGE | app | Docker image name |
| --tag | DEPLOY_TAG | latest | Docker image tag |
| --platform | DEPLOY_PLATFORM | linux/amd64 | Docker platform |
| --ssh-key | SSH_KEY_PATH | | Path to SSH key |
| --container-name| CONTAINER_NAME | app | Name for the container |
| --container-port| CONTAINER_PORT | 3000 | Container port |
| --host-port | HOST_PORT | 3000 | Host port |
| --env-file | ENV_FILE | .env.production | Environment file |
| --build-arg | BUILD_ARGS | | Build arguments (KEY=VALUE) |

### Example Commands

Expand All @@ -103,6 +102,23 @@ Using environment file:
./copepod --env-file .env.production
```

Using build arguments:

```bash
# Single build argument
./copepod --host example.com --user deploy --build-arg VERSION=1.0.0

# Multiple build arguments
./copepod --host example.com --user deploy --build-arg VERSION=1.0.0 --build-arg ENV=prod

# Using environment variable
export BUILD_ARGS="VERSION=1.0.0,ENV=prod"
./copepod --host example.com --user deploy

# Using git commit hash
./copepod --host example.com --user deploy --build-arg GIT_HASH=$(git rev-parse HEAD)
```

## Directory Structure

Your project directory should look like this:
Expand All @@ -118,7 +134,7 @@ Your project directory should look like this:

1. Validates configuration and checks prerequisites
2. Verifies Docker installation and SSH connectivity
3. Builds Docker image locally
3. Builds Docker image locally with any provided build arguments
4. Transfers image to remote host
5. Copies environment file (if specified)
6. Stops and removes existing container
Expand Down Expand Up @@ -148,6 +164,7 @@ The tool includes error handling for common scenarios:
- Uses SSH key-based authentication
- Supports custom SSH key paths
- Environment variables can be passed securely via env file
- Build arguments can be used for sensitive build-time variables
- No sensitive information is logged

## Known Limitations
Expand Down
Binary file modified demo.mp4
Binary file not shown.
75 changes: 60 additions & 15 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,17 @@ import (

// Config holds the deployment configuration
type Config struct {
Host string `json:"host"`
User string `json:"user"`
Image string `json:"image"`
Tag string `json:"tag"`
Platform string `json:"platform"`
SSHKey string `json:"sshKey"`
ContainerName string `json:"containerName"`
ContainerPort string `json:"containerPort"`
HostPort string `json:"hostPort"`
EnvFile string `json:"envFile"`
Host string `json:"host"`
User string `json:"user"`
Image string `json:"image"`
Tag string `json:"tag"`
Platform string `json:"platform"`
SSHKey string `json:"sshKey"`
ContainerName string `json:"containerName"`
ContainerPort string `json:"containerPort"`
HostPort string `json:"hostPort"`
EnvFile string `json:"envFile"`
BuildArgs map[string]string `json:"buildArgs"`
}

// Logger handles logging to both console and file
Expand Down Expand Up @@ -61,6 +62,7 @@ Options:
--container-port Container port (default: 3000)
--host-port Host port (default: 3000)
--env-file Environment file (default: .env.production)
--build-arg Build arguments (can be specified multiple times, format: KEY=VALUE)
--help Show this help message
Environment Variables:
Expand All @@ -74,11 +76,12 @@ Environment Variables:
CONTAINER_PORT Container port
HOST_PORT Host port
ENV_FILE Environment file
BUILD_ARGS Build arguments (comma-separated KEY=VALUE pairs)
Examples:
copepod --host example.com --user deploy
copepod --host example.com --user deploy --container-name myapp --container-port 8080
copepod --env-file .env.production
copepod --host example.com --user deploy --build-arg VERSION=1.0.0 --build-arg ENV=prod
copepod --env-file .env.production --build-arg GIT_HASH=$(git rev-parse HEAD)
`

// NewLogger creates a new logger instance
Expand Down Expand Up @@ -120,10 +123,26 @@ func (l *Logger) Close() error {
return l.file.Close()
}

// arrayFlags allows for multiple flag values
type arrayFlags []string

func (i *arrayFlags) String() string {
return strings.Join(*i, ",")
}

func (i *arrayFlags) Set(value string) error {
*i = append(*i, value)
return nil
}

// LoadConfig loads configuration from command line flags and environment variables
func LoadConfig() Config {
var config Config
var showHelp bool
var buildArgs arrayFlags

// Initialize BuildArgs map
config.BuildArgs = make(map[string]string)

// Define command line flags
flag.StringVar(&config.Host, "host", getEnv("DEPLOY_HOST", ""), "Remote host to deploy to")
Expand All @@ -136,6 +155,7 @@ func LoadConfig() Config {
flag.StringVar(&config.ContainerPort, "container-port", getEnv("CONTAINER_PORT", "3000"), "Container port")
flag.StringVar(&config.HostPort, "host-port", getEnv("HOST_PORT", "3000"), "Host port")
flag.StringVar(&config.EnvFile, "env-file", getEnv("ENV_FILE", ".env.production"), "Environment file")
flag.Var(&buildArgs, "build-arg", "Build argument in KEY=VALUE format (can be specified multiple times)")
flag.BoolVar(&showHelp, "help", false, "Show help message")

// Custom usage message
Expand All @@ -152,6 +172,24 @@ func LoadConfig() Config {
os.Exit(0)
}

// Process build arguments from command line
for _, arg := range buildArgs {
parts := strings.SplitN(arg, "=", 2)
if len(parts) == 2 {
config.BuildArgs[parts[0]] = parts[1]
}
}

// Process build arguments from environment variable
if envBuildArgs := os.Getenv("BUILD_ARGS"); envBuildArgs != "" {
for _, arg := range strings.Split(envBuildArgs, ",") {
parts := strings.SplitN(arg, "=", 2)
if len(parts) == 2 {
config.BuildArgs[parts[0]] = parts[1]
}
}
}

// Expand home directory in SSH key path
if strings.HasPrefix(config.SSHKey, "~/") {
home, err := os.UserHomeDir()
Expand Down Expand Up @@ -268,9 +306,16 @@ func Deploy(config *Config, logger *Logger) error {
return fmt.Errorf("Dockerfile not found in current directory")
}

// Build Docker image
buildCmd := fmt.Sprintf("docker build --platform %s -t %s:%s .",
config.Platform, config.Image, config.Tag)
// Build Docker image with build arguments
buildCmd := fmt.Sprintf("docker build --platform %s", config.Platform)

// Add build arguments to the command
for key, value := range config.BuildArgs {
buildCmd += fmt.Sprintf(" --build-arg %s=%s", key, value)
}

buildCmd += fmt.Sprintf(" -t %s:%s .", config.Image, config.Tag)

if _, err := ExecuteCommand(logger, buildCmd, "Building Docker image"); err != nil {
return err
}
Expand Down

0 comments on commit 258abe6

Please sign in to comment.