2026-01-28 18:33:11 +00:00
|
|
|
// Package release provides release automation with changelog generation and publishing.
|
|
|
|
|
package release
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"os"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
|
docs(audit): add dependency security audit report (#248)
* feat(devops): migrate filesystem operations to io.Local abstraction
Migrate config.go:
- os.ReadFile → io.Local.Read
Migrate devops.go:
- os.Stat → io.Local.IsFile
Migrate images.go:
- os.MkdirAll → io.Local.EnsureDir
- os.Stat → io.Local.IsFile
- os.ReadFile → io.Local.Read
- os.WriteFile → io.Local.Write
Migrate test.go:
- os.ReadFile → io.Local.Read
- os.Stat → io.Local.IsFile
Migrate claude.go:
- os.Stat → io.Local.IsDir
Updated tests to reflect improved behavior:
- Manifest.Save() now creates parent directories
- hasFile() correctly returns false for directories
Part of #101 (io.Medium migration tracking issue).
Closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate remaining packages to io.Local abstraction
Migrate filesystem operations to use the io.Local abstraction for
improved security, testability, and consistency:
- pkg/cache: Replace os.ReadFile, WriteFile, Remove, RemoveAll with
io.Local equivalents. io.Local.Write creates parent dirs automatically.
- pkg/agentic: Migrate config.go and context.go to use io.Local for
reading config files and gathering file context.
- pkg/repos: Use io.Local.Read, Exists, IsDir, List for registry
operations and git repo detection.
- pkg/release: Use io.Local for config loading, existence checks,
and artifact discovery.
- pkg/devops/sources: Use io.Local.EnsureDir for CDN download.
All paths are converted to absolute using filepath.Abs() before
calling io.Local methods to handle relative paths correctly.
Closes #104, closes #106, closes #108, closes #111
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate pkg/cli and pkg/container to io.Local abstraction
Continue io.Medium migration for the remaining packages:
- pkg/cli/daemon.go: PIDFile Acquire/Release now use io.Local.Read,
Delete, and Write for managing daemon PID files.
- pkg/container/state.go: LoadState and SaveState use io.Local for
JSON state persistence. EnsureLogsDir uses io.Local.EnsureDir.
- pkg/container/templates.go: Template loading and directory scanning
now use io.Local.IsFile, IsDir, Read, and List.
- pkg/container/linuxkit.go: Image validation uses io.Local.IsFile,
log file check uses io.Local.IsFile. Streaming log file creation
(os.Create) remains unchanged as io.Local doesn't support streaming.
Closes #105, closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(audit): add dependency security audit report
Complete security audit of all project dependencies:
- Run govulncheck: No vulnerabilities found
- Run go mod verify: All modules verified
- Document 15 direct dependencies and 161 indirect
- Assess supply chain risks: Low risk overall
- Verify lock files are committed with integrity hashes
- Provide CI integration recommendations
Closes #185
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): build core CLI from source instead of downloading release
The workflows were trying to download from a non-existent release URL.
Now builds the CLI directly using `go build` with version injection.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: trigger CI with updated workflow
* chore(ci): add workflow_dispatch trigger for manual runs
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 08:04:26 +00:00
|
|
|
"github.com/host-uk/core/pkg/io"
|
2026-01-28 18:33:11 +00:00
|
|
|
"gopkg.in/yaml.v3"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ConfigFileName is the name of the release configuration file.
|
|
|
|
|
const ConfigFileName = "release.yaml"
|
|
|
|
|
|
|
|
|
|
// ConfigDir is the directory where release configuration is stored.
|
|
|
|
|
const ConfigDir = ".core"
|
|
|
|
|
|
|
|
|
|
// Config holds the complete release configuration loaded from .core/release.yaml.
|
|
|
|
|
type Config struct {
|
|
|
|
|
// Version is the config file format version.
|
|
|
|
|
Version int `yaml:"version"`
|
|
|
|
|
// Project contains project metadata.
|
|
|
|
|
Project ProjectConfig `yaml:"project"`
|
|
|
|
|
// Build contains build settings for the release.
|
|
|
|
|
Build BuildConfig `yaml:"build"`
|
|
|
|
|
// Publishers defines where to publish the release.
|
|
|
|
|
Publishers []PublisherConfig `yaml:"publishers"`
|
|
|
|
|
// Changelog configures changelog generation.
|
|
|
|
|
Changelog ChangelogConfig `yaml:"changelog"`
|
2026-01-29 01:24:37 +00:00
|
|
|
// SDK configures SDK generation.
|
|
|
|
|
SDK *SDKConfig `yaml:"sdk,omitempty"`
|
2026-01-28 18:33:11 +00:00
|
|
|
|
|
|
|
|
// Internal fields (not serialized)
|
|
|
|
|
projectDir string // Set by LoadConfig
|
|
|
|
|
version string // Set by CLI flag
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ProjectConfig holds project metadata for releases.
|
|
|
|
|
type ProjectConfig struct {
|
|
|
|
|
// Name is the project name.
|
|
|
|
|
Name string `yaml:"name"`
|
|
|
|
|
// Repository is the GitHub repository in owner/repo format.
|
|
|
|
|
Repository string `yaml:"repository"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BuildConfig holds build settings for releases.
|
|
|
|
|
type BuildConfig struct {
|
|
|
|
|
// Targets defines the build targets.
|
|
|
|
|
Targets []TargetConfig `yaml:"targets"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TargetConfig defines a build target.
|
|
|
|
|
type TargetConfig struct {
|
|
|
|
|
// OS is the target operating system (e.g., "linux", "darwin", "windows").
|
|
|
|
|
OS string `yaml:"os"`
|
|
|
|
|
// Arch is the target architecture (e.g., "amd64", "arm64").
|
|
|
|
|
Arch string `yaml:"arch"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// PublisherConfig holds configuration for a publisher.
|
|
|
|
|
type PublisherConfig struct {
|
2026-01-28 18:42:04 +00:00
|
|
|
// Type is the publisher type (e.g., "github", "linuxkit", "docker").
|
2026-01-28 18:33:11 +00:00
|
|
|
Type string `yaml:"type"`
|
|
|
|
|
// Prerelease marks the release as a prerelease.
|
|
|
|
|
Prerelease bool `yaml:"prerelease"`
|
|
|
|
|
// Draft creates the release as a draft.
|
|
|
|
|
Draft bool `yaml:"draft"`
|
2026-01-28 18:42:04 +00:00
|
|
|
|
|
|
|
|
// LinuxKit-specific configuration
|
|
|
|
|
// Config is the path to the LinuxKit YAML configuration file.
|
|
|
|
|
Config string `yaml:"config,omitempty"`
|
|
|
|
|
// Formats are the output formats to build (iso, raw, qcow2, vmdk).
|
|
|
|
|
Formats []string `yaml:"formats,omitempty"`
|
|
|
|
|
// Platforms are the target platforms (linux/amd64, linux/arm64).
|
|
|
|
|
Platforms []string `yaml:"platforms,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Docker-specific configuration
|
|
|
|
|
// Registry is the container registry (default: ghcr.io).
|
|
|
|
|
Registry string `yaml:"registry,omitempty"`
|
|
|
|
|
// Image is the image name in owner/repo format.
|
|
|
|
|
Image string `yaml:"image,omitempty"`
|
|
|
|
|
// Dockerfile is the path to the Dockerfile (default: Dockerfile).
|
|
|
|
|
Dockerfile string `yaml:"dockerfile,omitempty"`
|
|
|
|
|
// Tags are the image tags to apply.
|
|
|
|
|
Tags []string `yaml:"tags,omitempty"`
|
|
|
|
|
// BuildArgs are additional Docker build arguments.
|
|
|
|
|
BuildArgs map[string]string `yaml:"build_args,omitempty"`
|
2026-01-29 00:32:04 +00:00
|
|
|
|
|
|
|
|
// npm-specific configuration
|
|
|
|
|
// Package is the npm package name (e.g., "@host-uk/core").
|
|
|
|
|
Package string `yaml:"package,omitempty"`
|
|
|
|
|
// Access is the npm access level: "public" or "restricted".
|
|
|
|
|
Access string `yaml:"access,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Homebrew-specific configuration
|
|
|
|
|
// Tap is the Homebrew tap repository (e.g., "host-uk/homebrew-tap").
|
|
|
|
|
Tap string `yaml:"tap,omitempty"`
|
|
|
|
|
// Formula is the formula name (defaults to project name).
|
|
|
|
|
Formula string `yaml:"formula,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Scoop-specific configuration
|
|
|
|
|
// Bucket is the Scoop bucket repository (e.g., "host-uk/scoop-bucket").
|
|
|
|
|
Bucket string `yaml:"bucket,omitempty"`
|
|
|
|
|
|
|
|
|
|
// AUR-specific configuration
|
|
|
|
|
// Maintainer is the AUR package maintainer (e.g., "Name <email>").
|
|
|
|
|
Maintainer string `yaml:"maintainer,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Chocolatey-specific configuration
|
|
|
|
|
// Push determines whether to push to Chocolatey (false = generate only).
|
|
|
|
|
Push bool `yaml:"push,omitempty"`
|
|
|
|
|
|
|
|
|
|
// Official repo configuration (for Homebrew, Scoop)
|
|
|
|
|
// When enabled, generates files for PR to official repos.
|
|
|
|
|
Official *OfficialConfig `yaml:"official,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// OfficialConfig holds configuration for generating files for official repo PRs.
|
|
|
|
|
type OfficialConfig struct {
|
|
|
|
|
// Enabled determines whether to generate files for official repos.
|
|
|
|
|
Enabled bool `yaml:"enabled"`
|
|
|
|
|
// Output is the directory to write generated files.
|
|
|
|
|
Output string `yaml:"output,omitempty"`
|
2026-01-28 18:33:11 +00:00
|
|
|
}
|
|
|
|
|
|
2026-01-29 01:24:37 +00:00
|
|
|
// SDKConfig holds SDK generation configuration.
|
|
|
|
|
type SDKConfig struct {
|
|
|
|
|
// Spec is the path to the OpenAPI spec file.
|
|
|
|
|
Spec string `yaml:"spec,omitempty"`
|
|
|
|
|
// Languages to generate.
|
|
|
|
|
Languages []string `yaml:"languages,omitempty"`
|
|
|
|
|
// Output directory (default: sdk/).
|
|
|
|
|
Output string `yaml:"output,omitempty"`
|
|
|
|
|
// Package naming.
|
|
|
|
|
Package SDKPackageConfig `yaml:"package,omitempty"`
|
|
|
|
|
// Diff configuration.
|
|
|
|
|
Diff SDKDiffConfig `yaml:"diff,omitempty"`
|
|
|
|
|
// Publish configuration.
|
|
|
|
|
Publish SDKPublishConfig `yaml:"publish,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SDKPackageConfig holds package naming configuration.
|
|
|
|
|
type SDKPackageConfig struct {
|
|
|
|
|
Name string `yaml:"name,omitempty"`
|
|
|
|
|
Version string `yaml:"version,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SDKDiffConfig holds diff configuration.
|
|
|
|
|
type SDKDiffConfig struct {
|
|
|
|
|
Enabled bool `yaml:"enabled,omitempty"`
|
|
|
|
|
FailOnBreaking bool `yaml:"fail_on_breaking,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SDKPublishConfig holds monorepo publish configuration.
|
|
|
|
|
type SDKPublishConfig struct {
|
|
|
|
|
Repo string `yaml:"repo,omitempty"`
|
|
|
|
|
Path string `yaml:"path,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-28 18:33:11 +00:00
|
|
|
// ChangelogConfig holds changelog generation settings.
|
|
|
|
|
type ChangelogConfig struct {
|
|
|
|
|
// Include specifies commit types to include in the changelog.
|
|
|
|
|
Include []string `yaml:"include"`
|
|
|
|
|
// Exclude specifies commit types to exclude from the changelog.
|
|
|
|
|
Exclude []string `yaml:"exclude"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// LoadConfig loads release configuration from the .core/release.yaml file in the given directory.
|
|
|
|
|
// If the config file does not exist, it returns DefaultConfig().
|
|
|
|
|
// Returns an error if the file exists but cannot be parsed.
|
Migrate pkg/release to io.Medium abstraction (#290)
* chore(io): migrate pkg/release to io.Medium abstraction
Migrated `pkg/release` and its subpackages to use the `io.Medium` abstraction for filesystem operations. This enables better testability and support for alternative storage backends.
Changes:
- Added `FS io.Medium` field to `release.Release` and `publishers.Release` structs.
- Updated `LoadConfig`, `ConfigExists`, and `WriteConfig` in `pkg/release/config.go` to accept `io.Medium`.
- Updated `Publish`, `Run`, `findArtifacts`, and `buildArtifacts` in `pkg/release/release.go` to use `io.Medium`.
- Migrated all publishers (`aur`, `chocolatey`, `docker`, `github`, `homebrew`, `linuxkit`, `npm`, `scoop`) to use `io.Medium` for file operations.
- Implemented custom template overrides in publishers by checking for templates in `.core/templates/<publisher>/` via `io.Medium`.
- Updated all relevant tests to provide `io.Medium`.
* chore(io): fix missing callers in pkg/release migration
Updated callers of `release` package functions that had their signatures changed during the `io.Medium` migration.
Fixed files:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These changes ensure the project compiles successfully by providing `io.Local` to `LoadConfig`, `WriteConfig`, and `ConfigExists`.
* chore(io): fix build errors in pkg/release migration
Fixed compilation errors by updating all callers of `release.LoadConfig`, `release.ConfigExists`, and `release.WriteConfig` to provide the required `io.Medium` argument.
Files updated:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These entry points now correctly pass `io.Local` to the `release` package functions.
2026-02-04 15:07:13 +00:00
|
|
|
func LoadConfig(m io.Medium, dir string) (*Config, error) {
|
2026-01-28 18:33:11 +00:00
|
|
|
configPath := filepath.Join(dir, ConfigDir, ConfigFileName)
|
docs(audit): add dependency security audit report (#248)
* feat(devops): migrate filesystem operations to io.Local abstraction
Migrate config.go:
- os.ReadFile → io.Local.Read
Migrate devops.go:
- os.Stat → io.Local.IsFile
Migrate images.go:
- os.MkdirAll → io.Local.EnsureDir
- os.Stat → io.Local.IsFile
- os.ReadFile → io.Local.Read
- os.WriteFile → io.Local.Write
Migrate test.go:
- os.ReadFile → io.Local.Read
- os.Stat → io.Local.IsFile
Migrate claude.go:
- os.Stat → io.Local.IsDir
Updated tests to reflect improved behavior:
- Manifest.Save() now creates parent directories
- hasFile() correctly returns false for directories
Part of #101 (io.Medium migration tracking issue).
Closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate remaining packages to io.Local abstraction
Migrate filesystem operations to use the io.Local abstraction for
improved security, testability, and consistency:
- pkg/cache: Replace os.ReadFile, WriteFile, Remove, RemoveAll with
io.Local equivalents. io.Local.Write creates parent dirs automatically.
- pkg/agentic: Migrate config.go and context.go to use io.Local for
reading config files and gathering file context.
- pkg/repos: Use io.Local.Read, Exists, IsDir, List for registry
operations and git repo detection.
- pkg/release: Use io.Local for config loading, existence checks,
and artifact discovery.
- pkg/devops/sources: Use io.Local.EnsureDir for CDN download.
All paths are converted to absolute using filepath.Abs() before
calling io.Local methods to handle relative paths correctly.
Closes #104, closes #106, closes #108, closes #111
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate pkg/cli and pkg/container to io.Local abstraction
Continue io.Medium migration for the remaining packages:
- pkg/cli/daemon.go: PIDFile Acquire/Release now use io.Local.Read,
Delete, and Write for managing daemon PID files.
- pkg/container/state.go: LoadState and SaveState use io.Local for
JSON state persistence. EnsureLogsDir uses io.Local.EnsureDir.
- pkg/container/templates.go: Template loading and directory scanning
now use io.Local.IsFile, IsDir, Read, and List.
- pkg/container/linuxkit.go: Image validation uses io.Local.IsFile,
log file check uses io.Local.IsFile. Streaming log file creation
(os.Create) remains unchanged as io.Local doesn't support streaming.
Closes #105, closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(audit): add dependency security audit report
Complete security audit of all project dependencies:
- Run govulncheck: No vulnerabilities found
- Run go mod verify: All modules verified
- Document 15 direct dependencies and 161 indirect
- Assess supply chain risks: Low risk overall
- Verify lock files are committed with integrity hashes
- Provide CI integration recommendations
Closes #185
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): build core CLI from source instead of downloading release
The workflows were trying to download from a non-existent release URL.
Now builds the CLI directly using `go build` with version injection.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: trigger CI with updated workflow
* chore(ci): add workflow_dispatch trigger for manual runs
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 08:04:26 +00:00
|
|
|
absPath, err := filepath.Abs(configPath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("release.LoadConfig: failed to resolve path: %w", err)
|
|
|
|
|
}
|
2026-01-28 18:33:11 +00:00
|
|
|
|
Migrate pkg/release to io.Medium abstraction (#290)
* chore(io): migrate pkg/release to io.Medium abstraction
Migrated `pkg/release` and its subpackages to use the `io.Medium` abstraction for filesystem operations. This enables better testability and support for alternative storage backends.
Changes:
- Added `FS io.Medium` field to `release.Release` and `publishers.Release` structs.
- Updated `LoadConfig`, `ConfigExists`, and `WriteConfig` in `pkg/release/config.go` to accept `io.Medium`.
- Updated `Publish`, `Run`, `findArtifacts`, and `buildArtifacts` in `pkg/release/release.go` to use `io.Medium`.
- Migrated all publishers (`aur`, `chocolatey`, `docker`, `github`, `homebrew`, `linuxkit`, `npm`, `scoop`) to use `io.Medium` for file operations.
- Implemented custom template overrides in publishers by checking for templates in `.core/templates/<publisher>/` via `io.Medium`.
- Updated all relevant tests to provide `io.Medium`.
* chore(io): fix missing callers in pkg/release migration
Updated callers of `release` package functions that had their signatures changed during the `io.Medium` migration.
Fixed files:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These changes ensure the project compiles successfully by providing `io.Local` to `LoadConfig`, `WriteConfig`, and `ConfigExists`.
* chore(io): fix build errors in pkg/release migration
Fixed compilation errors by updating all callers of `release.LoadConfig`, `release.ConfigExists`, and `release.WriteConfig` to provide the required `io.Medium` argument.
Files updated:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These entry points now correctly pass `io.Local` to the `release` package functions.
2026-02-04 15:07:13 +00:00
|
|
|
content, err := m.Read(absPath)
|
2026-01-28 18:33:11 +00:00
|
|
|
if err != nil {
|
|
|
|
|
if os.IsNotExist(err) {
|
|
|
|
|
cfg := DefaultConfig()
|
|
|
|
|
cfg.projectDir = dir
|
|
|
|
|
return cfg, nil
|
|
|
|
|
}
|
|
|
|
|
return nil, fmt.Errorf("release.LoadConfig: failed to read config file: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var cfg Config
|
docs(audit): add dependency security audit report (#248)
* feat(devops): migrate filesystem operations to io.Local abstraction
Migrate config.go:
- os.ReadFile → io.Local.Read
Migrate devops.go:
- os.Stat → io.Local.IsFile
Migrate images.go:
- os.MkdirAll → io.Local.EnsureDir
- os.Stat → io.Local.IsFile
- os.ReadFile → io.Local.Read
- os.WriteFile → io.Local.Write
Migrate test.go:
- os.ReadFile → io.Local.Read
- os.Stat → io.Local.IsFile
Migrate claude.go:
- os.Stat → io.Local.IsDir
Updated tests to reflect improved behavior:
- Manifest.Save() now creates parent directories
- hasFile() correctly returns false for directories
Part of #101 (io.Medium migration tracking issue).
Closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate remaining packages to io.Local abstraction
Migrate filesystem operations to use the io.Local abstraction for
improved security, testability, and consistency:
- pkg/cache: Replace os.ReadFile, WriteFile, Remove, RemoveAll with
io.Local equivalents. io.Local.Write creates parent dirs automatically.
- pkg/agentic: Migrate config.go and context.go to use io.Local for
reading config files and gathering file context.
- pkg/repos: Use io.Local.Read, Exists, IsDir, List for registry
operations and git repo detection.
- pkg/release: Use io.Local for config loading, existence checks,
and artifact discovery.
- pkg/devops/sources: Use io.Local.EnsureDir for CDN download.
All paths are converted to absolute using filepath.Abs() before
calling io.Local methods to handle relative paths correctly.
Closes #104, closes #106, closes #108, closes #111
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate pkg/cli and pkg/container to io.Local abstraction
Continue io.Medium migration for the remaining packages:
- pkg/cli/daemon.go: PIDFile Acquire/Release now use io.Local.Read,
Delete, and Write for managing daemon PID files.
- pkg/container/state.go: LoadState and SaveState use io.Local for
JSON state persistence. EnsureLogsDir uses io.Local.EnsureDir.
- pkg/container/templates.go: Template loading and directory scanning
now use io.Local.IsFile, IsDir, Read, and List.
- pkg/container/linuxkit.go: Image validation uses io.Local.IsFile,
log file check uses io.Local.IsFile. Streaming log file creation
(os.Create) remains unchanged as io.Local doesn't support streaming.
Closes #105, closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(audit): add dependency security audit report
Complete security audit of all project dependencies:
- Run govulncheck: No vulnerabilities found
- Run go mod verify: All modules verified
- Document 15 direct dependencies and 161 indirect
- Assess supply chain risks: Low risk overall
- Verify lock files are committed with integrity hashes
- Provide CI integration recommendations
Closes #185
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): build core CLI from source instead of downloading release
The workflows were trying to download from a non-existent release URL.
Now builds the CLI directly using `go build` with version injection.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: trigger CI with updated workflow
* chore(ci): add workflow_dispatch trigger for manual runs
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 08:04:26 +00:00
|
|
|
if err := yaml.Unmarshal([]byte(content), &cfg); err != nil {
|
2026-01-28 18:33:11 +00:00
|
|
|
return nil, fmt.Errorf("release.LoadConfig: failed to parse config file: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Apply defaults for any missing fields
|
|
|
|
|
applyDefaults(&cfg)
|
|
|
|
|
cfg.projectDir = dir
|
|
|
|
|
|
|
|
|
|
return &cfg, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultConfig returns sensible defaults for release configuration.
|
|
|
|
|
func DefaultConfig() *Config {
|
|
|
|
|
return &Config{
|
|
|
|
|
Version: 1,
|
|
|
|
|
Project: ProjectConfig{
|
|
|
|
|
Name: "",
|
|
|
|
|
Repository: "",
|
|
|
|
|
},
|
|
|
|
|
Build: BuildConfig{
|
|
|
|
|
Targets: []TargetConfig{
|
|
|
|
|
{OS: "linux", Arch: "amd64"},
|
|
|
|
|
{OS: "linux", Arch: "arm64"},
|
|
|
|
|
{OS: "darwin", Arch: "arm64"},
|
|
|
|
|
{OS: "windows", Arch: "amd64"},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Publishers: []PublisherConfig{
|
|
|
|
|
{
|
|
|
|
|
Type: "github",
|
|
|
|
|
Prerelease: false,
|
|
|
|
|
Draft: false,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
Changelog: ChangelogConfig{
|
|
|
|
|
Include: []string{"feat", "fix", "perf", "refactor"},
|
|
|
|
|
Exclude: []string{"chore", "docs", "style", "test", "ci"},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// applyDefaults fills in default values for any empty fields in the config.
|
|
|
|
|
func applyDefaults(cfg *Config) {
|
|
|
|
|
defaults := DefaultConfig()
|
|
|
|
|
|
|
|
|
|
if cfg.Version == 0 {
|
|
|
|
|
cfg.Version = defaults.Version
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(cfg.Build.Targets) == 0 {
|
|
|
|
|
cfg.Build.Targets = defaults.Build.Targets
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(cfg.Publishers) == 0 {
|
|
|
|
|
cfg.Publishers = defaults.Publishers
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(cfg.Changelog.Include) == 0 && len(cfg.Changelog.Exclude) == 0 {
|
|
|
|
|
cfg.Changelog.Include = defaults.Changelog.Include
|
|
|
|
|
cfg.Changelog.Exclude = defaults.Changelog.Exclude
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetProjectDir sets the project directory on the config.
|
|
|
|
|
func (c *Config) SetProjectDir(dir string) {
|
|
|
|
|
c.projectDir = dir
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// SetVersion sets the version override on the config.
|
|
|
|
|
func (c *Config) SetVersion(version string) {
|
|
|
|
|
c.version = version
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ConfigPath returns the path to the release config file for a given directory.
|
|
|
|
|
func ConfigPath(dir string) string {
|
|
|
|
|
return filepath.Join(dir, ConfigDir, ConfigFileName)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ConfigExists checks if a release config file exists in the given directory.
|
Migrate pkg/release to io.Medium abstraction (#290)
* chore(io): migrate pkg/release to io.Medium abstraction
Migrated `pkg/release` and its subpackages to use the `io.Medium` abstraction for filesystem operations. This enables better testability and support for alternative storage backends.
Changes:
- Added `FS io.Medium` field to `release.Release` and `publishers.Release` structs.
- Updated `LoadConfig`, `ConfigExists`, and `WriteConfig` in `pkg/release/config.go` to accept `io.Medium`.
- Updated `Publish`, `Run`, `findArtifacts`, and `buildArtifacts` in `pkg/release/release.go` to use `io.Medium`.
- Migrated all publishers (`aur`, `chocolatey`, `docker`, `github`, `homebrew`, `linuxkit`, `npm`, `scoop`) to use `io.Medium` for file operations.
- Implemented custom template overrides in publishers by checking for templates in `.core/templates/<publisher>/` via `io.Medium`.
- Updated all relevant tests to provide `io.Medium`.
* chore(io): fix missing callers in pkg/release migration
Updated callers of `release` package functions that had their signatures changed during the `io.Medium` migration.
Fixed files:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These changes ensure the project compiles successfully by providing `io.Local` to `LoadConfig`, `WriteConfig`, and `ConfigExists`.
* chore(io): fix build errors in pkg/release migration
Fixed compilation errors by updating all callers of `release.LoadConfig`, `release.ConfigExists`, and `release.WriteConfig` to provide the required `io.Medium` argument.
Files updated:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These entry points now correctly pass `io.Local` to the `release` package functions.
2026-02-04 15:07:13 +00:00
|
|
|
func ConfigExists(m io.Medium, dir string) bool {
|
docs(audit): add dependency security audit report (#248)
* feat(devops): migrate filesystem operations to io.Local abstraction
Migrate config.go:
- os.ReadFile → io.Local.Read
Migrate devops.go:
- os.Stat → io.Local.IsFile
Migrate images.go:
- os.MkdirAll → io.Local.EnsureDir
- os.Stat → io.Local.IsFile
- os.ReadFile → io.Local.Read
- os.WriteFile → io.Local.Write
Migrate test.go:
- os.ReadFile → io.Local.Read
- os.Stat → io.Local.IsFile
Migrate claude.go:
- os.Stat → io.Local.IsDir
Updated tests to reflect improved behavior:
- Manifest.Save() now creates parent directories
- hasFile() correctly returns false for directories
Part of #101 (io.Medium migration tracking issue).
Closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate remaining packages to io.Local abstraction
Migrate filesystem operations to use the io.Local abstraction for
improved security, testability, and consistency:
- pkg/cache: Replace os.ReadFile, WriteFile, Remove, RemoveAll with
io.Local equivalents. io.Local.Write creates parent dirs automatically.
- pkg/agentic: Migrate config.go and context.go to use io.Local for
reading config files and gathering file context.
- pkg/repos: Use io.Local.Read, Exists, IsDir, List for registry
operations and git repo detection.
- pkg/release: Use io.Local for config loading, existence checks,
and artifact discovery.
- pkg/devops/sources: Use io.Local.EnsureDir for CDN download.
All paths are converted to absolute using filepath.Abs() before
calling io.Local methods to handle relative paths correctly.
Closes #104, closes #106, closes #108, closes #111
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate pkg/cli and pkg/container to io.Local abstraction
Continue io.Medium migration for the remaining packages:
- pkg/cli/daemon.go: PIDFile Acquire/Release now use io.Local.Read,
Delete, and Write for managing daemon PID files.
- pkg/container/state.go: LoadState and SaveState use io.Local for
JSON state persistence. EnsureLogsDir uses io.Local.EnsureDir.
- pkg/container/templates.go: Template loading and directory scanning
now use io.Local.IsFile, IsDir, Read, and List.
- pkg/container/linuxkit.go: Image validation uses io.Local.IsFile,
log file check uses io.Local.IsFile. Streaming log file creation
(os.Create) remains unchanged as io.Local doesn't support streaming.
Closes #105, closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(audit): add dependency security audit report
Complete security audit of all project dependencies:
- Run govulncheck: No vulnerabilities found
- Run go mod verify: All modules verified
- Document 15 direct dependencies and 161 indirect
- Assess supply chain risks: Low risk overall
- Verify lock files are committed with integrity hashes
- Provide CI integration recommendations
Closes #185
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): build core CLI from source instead of downloading release
The workflows were trying to download from a non-existent release URL.
Now builds the CLI directly using `go build` with version injection.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: trigger CI with updated workflow
* chore(ci): add workflow_dispatch trigger for manual runs
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 08:04:26 +00:00
|
|
|
configPath := ConfigPath(dir)
|
|
|
|
|
absPath, err := filepath.Abs(configPath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return false
|
|
|
|
|
}
|
Migrate pkg/release to io.Medium abstraction (#290)
* chore(io): migrate pkg/release to io.Medium abstraction
Migrated `pkg/release` and its subpackages to use the `io.Medium` abstraction for filesystem operations. This enables better testability and support for alternative storage backends.
Changes:
- Added `FS io.Medium` field to `release.Release` and `publishers.Release` structs.
- Updated `LoadConfig`, `ConfigExists`, and `WriteConfig` in `pkg/release/config.go` to accept `io.Medium`.
- Updated `Publish`, `Run`, `findArtifacts`, and `buildArtifacts` in `pkg/release/release.go` to use `io.Medium`.
- Migrated all publishers (`aur`, `chocolatey`, `docker`, `github`, `homebrew`, `linuxkit`, `npm`, `scoop`) to use `io.Medium` for file operations.
- Implemented custom template overrides in publishers by checking for templates in `.core/templates/<publisher>/` via `io.Medium`.
- Updated all relevant tests to provide `io.Medium`.
* chore(io): fix missing callers in pkg/release migration
Updated callers of `release` package functions that had their signatures changed during the `io.Medium` migration.
Fixed files:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These changes ensure the project compiles successfully by providing `io.Local` to `LoadConfig`, `WriteConfig`, and `ConfigExists`.
* chore(io): fix build errors in pkg/release migration
Fixed compilation errors by updating all callers of `release.LoadConfig`, `release.ConfigExists`, and `release.WriteConfig` to provide the required `io.Medium` argument.
Files updated:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These entry points now correctly pass `io.Local` to the `release` package functions.
2026-02-04 15:07:13 +00:00
|
|
|
return m.IsFile(absPath)
|
2026-01-28 18:33:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetRepository returns the repository from the config.
|
|
|
|
|
func (c *Config) GetRepository() string {
|
|
|
|
|
return c.Project.Repository
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetProjectName returns the project name from the config.
|
|
|
|
|
func (c *Config) GetProjectName() string {
|
|
|
|
|
return c.Project.Name
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// WriteConfig writes the config to the .core/release.yaml file.
|
Migrate pkg/release to io.Medium abstraction (#290)
* chore(io): migrate pkg/release to io.Medium abstraction
Migrated `pkg/release` and its subpackages to use the `io.Medium` abstraction for filesystem operations. This enables better testability and support for alternative storage backends.
Changes:
- Added `FS io.Medium` field to `release.Release` and `publishers.Release` structs.
- Updated `LoadConfig`, `ConfigExists`, and `WriteConfig` in `pkg/release/config.go` to accept `io.Medium`.
- Updated `Publish`, `Run`, `findArtifacts`, and `buildArtifacts` in `pkg/release/release.go` to use `io.Medium`.
- Migrated all publishers (`aur`, `chocolatey`, `docker`, `github`, `homebrew`, `linuxkit`, `npm`, `scoop`) to use `io.Medium` for file operations.
- Implemented custom template overrides in publishers by checking for templates in `.core/templates/<publisher>/` via `io.Medium`.
- Updated all relevant tests to provide `io.Medium`.
* chore(io): fix missing callers in pkg/release migration
Updated callers of `release` package functions that had their signatures changed during the `io.Medium` migration.
Fixed files:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These changes ensure the project compiles successfully by providing `io.Local` to `LoadConfig`, `WriteConfig`, and `ConfigExists`.
* chore(io): fix build errors in pkg/release migration
Fixed compilation errors by updating all callers of `release.LoadConfig`, `release.ConfigExists`, and `release.WriteConfig` to provide the required `io.Medium` argument.
Files updated:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These entry points now correctly pass `io.Local` to the `release` package functions.
2026-02-04 15:07:13 +00:00
|
|
|
func WriteConfig(m io.Medium, cfg *Config, dir string) error {
|
2026-01-28 18:33:11 +00:00
|
|
|
configPath := ConfigPath(dir)
|
docs(audit): add dependency security audit report (#248)
* feat(devops): migrate filesystem operations to io.Local abstraction
Migrate config.go:
- os.ReadFile → io.Local.Read
Migrate devops.go:
- os.Stat → io.Local.IsFile
Migrate images.go:
- os.MkdirAll → io.Local.EnsureDir
- os.Stat → io.Local.IsFile
- os.ReadFile → io.Local.Read
- os.WriteFile → io.Local.Write
Migrate test.go:
- os.ReadFile → io.Local.Read
- os.Stat → io.Local.IsFile
Migrate claude.go:
- os.Stat → io.Local.IsDir
Updated tests to reflect improved behavior:
- Manifest.Save() now creates parent directories
- hasFile() correctly returns false for directories
Part of #101 (io.Medium migration tracking issue).
Closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate remaining packages to io.Local abstraction
Migrate filesystem operations to use the io.Local abstraction for
improved security, testability, and consistency:
- pkg/cache: Replace os.ReadFile, WriteFile, Remove, RemoveAll with
io.Local equivalents. io.Local.Write creates parent dirs automatically.
- pkg/agentic: Migrate config.go and context.go to use io.Local for
reading config files and gathering file context.
- pkg/repos: Use io.Local.Read, Exists, IsDir, List for registry
operations and git repo detection.
- pkg/release: Use io.Local for config loading, existence checks,
and artifact discovery.
- pkg/devops/sources: Use io.Local.EnsureDir for CDN download.
All paths are converted to absolute using filepath.Abs() before
calling io.Local methods to handle relative paths correctly.
Closes #104, closes #106, closes #108, closes #111
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore(io): migrate pkg/cli and pkg/container to io.Local abstraction
Continue io.Medium migration for the remaining packages:
- pkg/cli/daemon.go: PIDFile Acquire/Release now use io.Local.Read,
Delete, and Write for managing daemon PID files.
- pkg/container/state.go: LoadState and SaveState use io.Local for
JSON state persistence. EnsureLogsDir uses io.Local.EnsureDir.
- pkg/container/templates.go: Template loading and directory scanning
now use io.Local.IsFile, IsDir, Read, and List.
- pkg/container/linuxkit.go: Image validation uses io.Local.IsFile,
log file check uses io.Local.IsFile. Streaming log file creation
(os.Create) remains unchanged as io.Local doesn't support streaming.
Closes #105, closes #107
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* docs(audit): add dependency security audit report
Complete security audit of all project dependencies:
- Run govulncheck: No vulnerabilities found
- Run go mod verify: All modules verified
- Document 15 direct dependencies and 161 indirect
- Assess supply chain risks: Low risk overall
- Verify lock files are committed with integrity hashes
- Provide CI integration recommendations
Closes #185
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix(ci): build core CLI from source instead of downloading release
The workflows were trying to download from a non-existent release URL.
Now builds the CLI directly using `go build` with version injection.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* chore: trigger CI with updated workflow
* chore(ci): add workflow_dispatch trigger for manual runs
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-02 08:04:26 +00:00
|
|
|
absPath, err := filepath.Abs(configPath)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("release.WriteConfig: failed to resolve path: %w", err)
|
2026-01-28 18:33:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data, err := yaml.Marshal(cfg)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return fmt.Errorf("release.WriteConfig: failed to marshal config: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
Migrate pkg/release to io.Medium abstraction (#290)
* chore(io): migrate pkg/release to io.Medium abstraction
Migrated `pkg/release` and its subpackages to use the `io.Medium` abstraction for filesystem operations. This enables better testability and support for alternative storage backends.
Changes:
- Added `FS io.Medium` field to `release.Release` and `publishers.Release` structs.
- Updated `LoadConfig`, `ConfigExists`, and `WriteConfig` in `pkg/release/config.go` to accept `io.Medium`.
- Updated `Publish`, `Run`, `findArtifacts`, and `buildArtifacts` in `pkg/release/release.go` to use `io.Medium`.
- Migrated all publishers (`aur`, `chocolatey`, `docker`, `github`, `homebrew`, `linuxkit`, `npm`, `scoop`) to use `io.Medium` for file operations.
- Implemented custom template overrides in publishers by checking for templates in `.core/templates/<publisher>/` via `io.Medium`.
- Updated all relevant tests to provide `io.Medium`.
* chore(io): fix missing callers in pkg/release migration
Updated callers of `release` package functions that had their signatures changed during the `io.Medium` migration.
Fixed files:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These changes ensure the project compiles successfully by providing `io.Local` to `LoadConfig`, `WriteConfig`, and `ConfigExists`.
* chore(io): fix build errors in pkg/release migration
Fixed compilation errors by updating all callers of `release.LoadConfig`, `release.ConfigExists`, and `release.WriteConfig` to provide the required `io.Medium` argument.
Files updated:
- `internal/cmd/ci/cmd_init.go`
- `internal/cmd/ci/cmd_publish.go`
- `pkg/build/buildcmd/cmd_release.go`
These entry points now correctly pass `io.Local` to the `release` package functions.
2026-02-04 15:07:13 +00:00
|
|
|
// m.Write creates parent directories automatically
|
|
|
|
|
if err := m.Write(absPath, string(data)); err != nil {
|
2026-01-28 18:33:11 +00:00
|
|
|
return fmt.Errorf("release.WriteConfig: failed to write config file: %w", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nil
|
|
|
|
|
}
|