Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24"
go-version: "1.25"

- name: Run tests
run: go test -v ./...
Expand All @@ -35,7 +35,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.24"
go-version: "1.25"

- name: Build binaries for all platforms
run: |
Expand All @@ -57,6 +57,10 @@ jobs:
echo "Building Linux amd64..."
GOOS=linux GOARCH=amd64 go build -ldflags="${LDFLAGS}" -o dist/devenv-linux-amd64 ./cmd/devenv
# Linux arm64
echo "Building Linux arm64..."
GOOS=linux GOARCH=arm64 go build -ldflags="${LDFLAGS}" -o dist/devenv-linux-arm64 ./cmd/devenv
# macOS amd64 (Intel)
echo "Building macOS amd64..."
GOOS=darwin GOARCH=amd64 go build -ldflags="${LDFLAGS}" -o dist/devenv-darwin-amd64 ./cmd/devenv
Expand All @@ -72,14 +76,21 @@ jobs:
echo "✅ All binaries built successfully"
ls -lh dist/
- name: Generate checksums
run: |
cd dist
sha256sum * > checksums.txt
- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: |
dist/devenv-linux-amd64
dist/devenv-linux-arm64
dist/devenv-darwin-amd64
dist/devenv-darwin-arm64
dist/devenv-windows-amd64.exe
dist/checksums.txt
generate_release_notes: true
draft: false
prerelease: false
14 changes: 14 additions & 0 deletions internal/config/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ type BaseConfig struct {
// Package management
Packages PackageConfig `yaml:"packages,omitempty"`

// Git repos to be cloned
GitRepos []GitRepo `yaml:"gitRepos,omitempty" validate:"dive"`

// Storage configuration
Volumes []VolumeMount `yaml:"volumes,omitempty" validate:"dive"`

Expand Down Expand Up @@ -68,9 +71,18 @@ type GitConfig struct {
type PackageConfig struct {
Python []string `yaml:"python,omitempty" validate:"dive,min=1"`
APT []string `yaml:"apt,omitempty" validate:"dive,min=1"`
Brew []string `yaml:"brew,omitempty" validate:"dive,min=1"`
// Consider adding other package managers such as NPM, Yarn, etc.
}

type GitRepo struct {
URL string `yaml:"url" validate:"required,min=1,url"`
Branch string `yaml:"branch,omitempty" validate:"omitempty,min=1"`
Tag string `yaml:"tag,omitempty" validate:"omitempty,min=1"`
CommitHash string `yaml:"commitHash,omitempty" validate:"omitempty,min=1"`
Directory string `yaml:"directory,omitempty" validate:"omitempty,min=1,filepath"`
}

// ResourceConfig represents resource allocation
type ResourceConfig struct {
CPU any `yaml:"cpu,omitempty" validate:"omitempty,k8s_cpu"`
Expand Down Expand Up @@ -112,7 +124,9 @@ func NewBaseConfigWithDefaults() BaseConfig {
Packages: PackageConfig{
Python: []string{}, // Empty slice - no default packages
APT: []string{}, // Empty slice - no default packages
Brew: []string{}, // Empty slice - no default packages
},
GitRepos: []GitRepo{}, // Empty slice - no default git repositories
Volumes: []VolumeMount{}, // Empty slice - no default volumes
Namespace: "devenv", // Default namespace
EnvironmentName: "development", // Default environment name
Expand Down
30 changes: 30 additions & 0 deletions internal/config/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ func init() {
if err := validate.RegisterValidation("k8s_memory", validateKubernetesMemory); err != nil {
panic(fmt.Errorf("register validator k8s_memory: %w", err))
}
validate.RegisterStructValidation(validateGitRepo, GitRepo{})
}

// validateSSHKeys implements the "ssh_keys" tag.
Expand All @@ -79,6 +80,35 @@ func validateSSHKeys(fl validator.FieldLevel) bool {
return true
}

// validateGitRepo implements the "git_repo" tag.
// Ensures that if both Branch and CommitHash are specified, an error is raised.
func validateGitRepo(sl validator.StructLevel) {
repo := sl.Current().Interface().(GitRepo)
// Both Ref and CommitHash cannot be specified simultaneously.
targets := []string{}
if repo.Branch != "" {
targets = append(targets, repo.Branch)
}
if repo.Tag != "" {
targets = append(targets, repo.Tag)
}
if repo.CommitHash != "" {
targets = append(targets, repo.CommitHash)
}

if len(targets) > 1 {
if repo.Branch != "" {
sl.ReportError(repo.Branch, "branch", "Branch", "too many target specifications", "")
}
if repo.Tag != "" {
sl.ReportError(repo.Tag, "tag", "Tag", "too many target specifications", "")
}
if repo.CommitHash != "" {
sl.ReportError(repo.CommitHash, "commitHash", "CommitHash", "too many target specifications", "")
}
}
}

// validateKubernetesCPU implements the "k8s_cpu" tag for *raw* CPU fields.
// Accepts:
// - Strings: "", "unlimited", plain number ("2", "2.5"), or millicores ("500m")
Expand Down
46 changes: 46 additions & 0 deletions internal/templates/template_files/dev/scripts/templated/startup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,11 @@ echo "Installing Python packages: {{range $i, $pkg := .Packages.Python}}{{if gt
/bin/bash /scripts/run_with_git.sh ${DEV_USERNAME} ${PYTHON_PATH} -m pip install --no-user --no-cache-dir{{range .Packages.Python}} {{.}}{{end}}
{{- end}}

{{- if gt (len .Packages.Brew) 0}}
echo "Installing Homebrew packages: {{range $i, $pkg := .Packages.Brew}}{{if gt $i 0}} {{end}}{{$pkg}}{{end}}"
sudo -u ${DEV_USERNAME} brew install{{range .Packages.Brew}} {{.}}{{end}}
{{- end}}

echo "Section 6: Package installation complete"

# === USER ENVIRONMENT SETUP ===
Expand Down Expand Up @@ -181,6 +186,47 @@ chown -R ${DEV_USERNAME}:${DEV_USERNAME} /home/${DEV_USERNAME}/.vscode-server

echo "Section 8: VSCode configuration complete"

# === GIT REPO CLONING ===
{{- if gt (len .GitRepos) 0}}
echo "Cloning Git repositories"
{{- range .GitRepos}}
echo "Cloning repository: {{.URL}}"

{{- /* Determine target directory */ -}}
{{- $targetDir := "" -}}
{{- if .Directory -}}
{{- $targetDir = .Directory -}}
{{- else -}}
{{- $targetDir = printf "/home/%s" $.Name -}}
{{- end }}

# Clone the complete repository
git clone {{.URL}} {{$targetDir}}
cd {{$targetDir}}

{{- /* Checkout specific reference */ -}}
{{- if .Tag}}
echo "Checking out tag: {{.Tag}}"
git checkout tags/{{.Tag}}
{{- else if .CommitHash}}
echo "Checking out commit: {{.CommitHash}}"
git checkout {{.CommitHash}}
{{- else if .Branch}}
echo "Checking out branch: {{.Branch}}"
git checkout {{.Branch}}
{{- else}}
echo "Staying on default branch"
{{- end}}

echo "Repository cloned successfully to: {{$targetDir}}"
echo "Current commit: $(git rev-parse --short HEAD)"
echo "Current branch/ref: $(git branch --show-current 2>/dev/null || git describe --tags --exact-match 2>/dev/null || echo 'detached HEAD')"

{{- end}}
{{- else}}
echo "No Git repositories to clone"
{{- end}}

# === SSH SERVER LAUNCH ===
echo "Starting SSH server"
/usr/sbin/sshd -D
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@ apiVersion: v1
kind: Namespace
metadata:
name: {{.Namespace}}
environment: {{.EnvironmentName}}
annotations:
description: "Namespace for DevENV resources"
description: "Namespace for DevENV resources"
environment: {{.EnvironmentName}}
3 changes: 3 additions & 0 deletions internal/templates/testdata/golden/startup-scripts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ data:

echo "Section 8: VSCode configuration complete"

# === GIT REPO CLONING ===
echo "No Git repositories to clone"

# === SSH SERVER LAUNCH ===
echo "Starting SSH server"
/usr/sbin/sshd -D
Expand Down
Loading