feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
// Package release provides release automation with changelog generation and publishing.
|
|
|
|
|
// It orchestrates the build system, changelog generation, and publishing to targets
|
|
|
|
|
// like GitHub Releases.
|
|
|
|
|
package release
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"context"
|
|
|
|
|
"fmt"
|
|
|
|
|
"path/filepath"
|
|
|
|
|
"strings"
|
|
|
|
|
|
2026-03-13 09:30:02 +00:00
|
|
|
"forge.lthn.ai/core/go-build/pkg/build"
|
|
|
|
|
"forge.lthn.ai/core/go-build/pkg/build/builders"
|
|
|
|
|
"forge.lthn.ai/core/go-build/pkg/release/publishers"
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
"forge.lthn.ai/core/go-io"
|
2026-03-16 21:03:21 +00:00
|
|
|
coreerr "forge.lthn.ai/core/go-log"
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// Release represents a release with its version, artifacts, and changelog.
|
|
|
|
|
type Release struct {
|
|
|
|
|
// Version is the semantic version string (e.g., "v1.2.3").
|
|
|
|
|
Version string
|
|
|
|
|
// Artifacts are the built release artifacts (archives with checksums).
|
|
|
|
|
Artifacts []build.Artifact
|
|
|
|
|
// Changelog is the generated markdown changelog.
|
|
|
|
|
Changelog string
|
|
|
|
|
// ProjectDir is the root directory of the project.
|
|
|
|
|
ProjectDir string
|
|
|
|
|
// FS is the medium for file operations.
|
|
|
|
|
FS io.Medium
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Publish publishes pre-built artifacts from dist/ to configured targets.
|
|
|
|
|
// Use this after `core build` to separate build and publish concerns.
|
|
|
|
|
// If dryRun is true, it will show what would be done without actually publishing.
|
|
|
|
|
func Publish(ctx context.Context, cfg *Config, dryRun bool) (*Release, error) {
|
|
|
|
|
if cfg == nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.Publish", "config is nil", nil)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m := io.Local
|
|
|
|
|
|
|
|
|
|
projectDir := cfg.projectDir
|
|
|
|
|
if projectDir == "" {
|
|
|
|
|
projectDir = "."
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Resolve to absolute path
|
|
|
|
|
absProjectDir, err := filepath.Abs(projectDir)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.Publish", "failed to resolve project directory", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 1: Determine version
|
|
|
|
|
version := cfg.version
|
|
|
|
|
if version == "" {
|
|
|
|
|
version, err = DetermineVersion(absProjectDir)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.Publish", "failed to determine version", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 2: Find pre-built artifacts in dist/
|
|
|
|
|
distDir := filepath.Join(absProjectDir, "dist")
|
|
|
|
|
artifacts, err := findArtifacts(m, distDir)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.Publish", "failed to find artifacts", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if len(artifacts) == 0 {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.Publish", "no artifacts found in dist/\nRun 'core build' first to create artifacts", nil)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 3: Generate changelog
|
|
|
|
|
changelog, err := Generate(absProjectDir, "", version)
|
|
|
|
|
if err != nil {
|
|
|
|
|
// Non-fatal: continue with empty changelog
|
|
|
|
|
changelog = fmt.Sprintf("Release %s", version)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
release := &Release{
|
|
|
|
|
Version: version,
|
|
|
|
|
Artifacts: artifacts,
|
|
|
|
|
Changelog: changelog,
|
|
|
|
|
ProjectDir: absProjectDir,
|
|
|
|
|
FS: m,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 4: Publish to configured targets
|
|
|
|
|
if len(cfg.Publishers) > 0 {
|
|
|
|
|
pubRelease := publishers.NewRelease(release.Version, release.Artifacts, release.Changelog, release.ProjectDir, release.FS)
|
|
|
|
|
|
|
|
|
|
for _, pubCfg := range cfg.Publishers {
|
|
|
|
|
publisher, err := getPublisher(pubCfg.Type)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return release, coreerr.E("release.Publish", "unsupported publisher", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extendedCfg := buildExtendedConfig(pubCfg)
|
|
|
|
|
publisherCfg := publishers.NewPublisherConfig(pubCfg.Type, pubCfg.Prerelease, pubCfg.Draft, extendedCfg)
|
|
|
|
|
if err := publisher.Publish(ctx, pubRelease, publisherCfg, cfg, dryRun); err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return release, coreerr.E("release.Publish", "publish to "+pubCfg.Type+" failed", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return release, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// findArtifacts discovers pre-built artifacts in the dist directory.
|
|
|
|
|
func findArtifacts(m io.Medium, distDir string) ([]build.Artifact, error) {
|
|
|
|
|
if !m.IsDir(distDir) {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.findArtifacts", "dist/ directory not found", nil)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var artifacts []build.Artifact
|
|
|
|
|
|
|
|
|
|
entries, err := m.List(distDir)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.findArtifacts", "failed to read dist/", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, entry := range entries {
|
|
|
|
|
if entry.IsDir() {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name := entry.Name()
|
|
|
|
|
path := filepath.Join(distDir, name)
|
|
|
|
|
|
|
|
|
|
// Include archives and checksums
|
|
|
|
|
if strings.HasSuffix(name, ".tar.gz") ||
|
|
|
|
|
strings.HasSuffix(name, ".zip") ||
|
|
|
|
|
strings.HasSuffix(name, ".txt") ||
|
|
|
|
|
strings.HasSuffix(name, ".sig") {
|
|
|
|
|
artifacts = append(artifacts, build.Artifact{Path: path})
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return artifacts, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Run executes the full release process: determine version, build artifacts,
|
|
|
|
|
// generate changelog, and publish to configured targets.
|
|
|
|
|
// For separated concerns, prefer using `core build` then `core ci` (Publish).
|
|
|
|
|
// If dryRun is true, it will show what would be done without actually publishing.
|
|
|
|
|
func Run(ctx context.Context, cfg *Config, dryRun bool) (*Release, error) {
|
|
|
|
|
if cfg == nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.Run", "config is nil", nil)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m := io.Local
|
|
|
|
|
|
|
|
|
|
projectDir := cfg.projectDir
|
|
|
|
|
if projectDir == "" {
|
|
|
|
|
projectDir = "."
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Resolve to absolute path
|
|
|
|
|
absProjectDir, err := filepath.Abs(projectDir)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.Run", "failed to resolve project directory", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 1: Determine version
|
|
|
|
|
version := cfg.version
|
|
|
|
|
if version == "" {
|
|
|
|
|
version, err = DetermineVersion(absProjectDir)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.Run", "failed to determine version", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 2: Generate changelog
|
|
|
|
|
changelog, err := Generate(absProjectDir, "", version)
|
|
|
|
|
if err != nil {
|
|
|
|
|
// Non-fatal: continue with empty changelog
|
|
|
|
|
changelog = fmt.Sprintf("Release %s", version)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 3: Build artifacts
|
|
|
|
|
artifacts, err := buildArtifacts(ctx, m, cfg, absProjectDir, version)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.Run", "build failed", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
release := &Release{
|
|
|
|
|
Version: version,
|
|
|
|
|
Artifacts: artifacts,
|
|
|
|
|
Changelog: changelog,
|
|
|
|
|
ProjectDir: absProjectDir,
|
|
|
|
|
FS: m,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Step 4: Publish to configured targets
|
|
|
|
|
if len(cfg.Publishers) > 0 {
|
|
|
|
|
// Convert to publisher types
|
|
|
|
|
pubRelease := publishers.NewRelease(release.Version, release.Artifacts, release.Changelog, release.ProjectDir, release.FS)
|
|
|
|
|
|
|
|
|
|
for _, pubCfg := range cfg.Publishers {
|
|
|
|
|
publisher, err := getPublisher(pubCfg.Type)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return release, coreerr.E("release.Run", "unsupported publisher", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build extended config for publisher-specific settings
|
|
|
|
|
extendedCfg := buildExtendedConfig(pubCfg)
|
|
|
|
|
publisherCfg := publishers.NewPublisherConfig(pubCfg.Type, pubCfg.Prerelease, pubCfg.Draft, extendedCfg)
|
|
|
|
|
if err := publisher.Publish(ctx, pubRelease, publisherCfg, cfg, dryRun); err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return release, coreerr.E("release.Run", "publish to "+pubCfg.Type+" failed", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return release, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// buildArtifacts builds all artifacts for the release.
|
|
|
|
|
func buildArtifacts(ctx context.Context, fs io.Medium, cfg *Config, projectDir, version string) ([]build.Artifact, error) {
|
|
|
|
|
// Load build configuration
|
|
|
|
|
buildCfg, err := build.LoadConfig(fs, projectDir)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.buildArtifacts", "failed to load build config", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine targets
|
|
|
|
|
var targets []build.Target
|
|
|
|
|
if len(cfg.Build.Targets) > 0 {
|
|
|
|
|
for _, t := range cfg.Build.Targets {
|
|
|
|
|
targets = append(targets, build.Target{OS: t.OS, Arch: t.Arch})
|
|
|
|
|
}
|
|
|
|
|
} else if len(buildCfg.Targets) > 0 {
|
|
|
|
|
targets = buildCfg.ToTargets()
|
|
|
|
|
} else {
|
|
|
|
|
// Default targets
|
|
|
|
|
targets = []build.Target{
|
|
|
|
|
{OS: "linux", Arch: "amd64"},
|
|
|
|
|
{OS: "linux", Arch: "arm64"},
|
|
|
|
|
{OS: "darwin", Arch: "arm64"},
|
|
|
|
|
{OS: "windows", Arch: "amd64"},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine binary name
|
|
|
|
|
binaryName := cfg.Project.Name
|
|
|
|
|
if binaryName == "" {
|
|
|
|
|
binaryName = buildCfg.Project.Binary
|
|
|
|
|
}
|
|
|
|
|
if binaryName == "" {
|
|
|
|
|
binaryName = buildCfg.Project.Name
|
|
|
|
|
}
|
|
|
|
|
if binaryName == "" {
|
|
|
|
|
binaryName = filepath.Base(projectDir)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Determine output directory
|
|
|
|
|
outputDir := filepath.Join(projectDir, "dist")
|
|
|
|
|
|
|
|
|
|
// Get builder (detect project type)
|
|
|
|
|
projectType, err := build.PrimaryType(fs, projectDir)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.buildArtifacts", "failed to detect project type", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
builder, err := getBuilder(projectType)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build configuration
|
|
|
|
|
buildConfig := &build.Config{
|
|
|
|
|
FS: fs,
|
|
|
|
|
ProjectDir: projectDir,
|
|
|
|
|
OutputDir: outputDir,
|
|
|
|
|
Name: binaryName,
|
|
|
|
|
Version: version,
|
|
|
|
|
LDFlags: buildCfg.Build.LDFlags,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build
|
|
|
|
|
artifacts, err := builder.Build(ctx, buildConfig, targets)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.buildArtifacts", "build failed", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Archive artifacts
|
|
|
|
|
archivedArtifacts, err := build.ArchiveAll(fs, artifacts)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.buildArtifacts", "archive failed", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compute checksums
|
|
|
|
|
checksummedArtifacts, err := build.ChecksumAll(fs, archivedArtifacts)
|
|
|
|
|
if err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.buildArtifacts", "checksum failed", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write CHECKSUMS.txt
|
|
|
|
|
checksumPath := filepath.Join(outputDir, "CHECKSUMS.txt")
|
|
|
|
|
if err := build.WriteChecksumFile(fs, checksummedArtifacts, checksumPath); err != nil {
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.buildArtifacts", "failed to write checksums file", err)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add CHECKSUMS.txt as an artifact
|
|
|
|
|
checksumArtifact := build.Artifact{
|
|
|
|
|
Path: checksumPath,
|
|
|
|
|
}
|
|
|
|
|
checksummedArtifacts = append(checksummedArtifacts, checksumArtifact)
|
|
|
|
|
|
|
|
|
|
return checksummedArtifacts, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getBuilder returns the appropriate builder for the project type.
|
|
|
|
|
func getBuilder(projectType build.ProjectType) (build.Builder, error) {
|
|
|
|
|
switch projectType {
|
|
|
|
|
case build.ProjectTypeWails:
|
|
|
|
|
return builders.NewWailsBuilder(), nil
|
|
|
|
|
case build.ProjectTypeGo:
|
|
|
|
|
return builders.NewGoBuilder(), nil
|
|
|
|
|
case build.ProjectTypeNode:
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.getBuilder", "node.js builder not yet implemented", nil)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
case build.ProjectTypePHP:
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.getBuilder", "PHP builder not yet implemented", nil)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
default:
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.getBuilder", "unsupported project type: "+string(projectType), nil)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getPublisher returns the publisher for the given type.
|
|
|
|
|
func getPublisher(pubType string) (publishers.Publisher, error) {
|
|
|
|
|
switch pubType {
|
|
|
|
|
case "github":
|
|
|
|
|
return publishers.NewGitHubPublisher(), nil
|
|
|
|
|
case "linuxkit":
|
|
|
|
|
return publishers.NewLinuxKitPublisher(), nil
|
|
|
|
|
case "docker":
|
|
|
|
|
return publishers.NewDockerPublisher(), nil
|
|
|
|
|
case "npm":
|
|
|
|
|
return publishers.NewNpmPublisher(), nil
|
|
|
|
|
case "homebrew":
|
|
|
|
|
return publishers.NewHomebrewPublisher(), nil
|
|
|
|
|
case "scoop":
|
|
|
|
|
return publishers.NewScoopPublisher(), nil
|
|
|
|
|
case "aur":
|
|
|
|
|
return publishers.NewAURPublisher(), nil
|
|
|
|
|
case "chocolatey":
|
|
|
|
|
return publishers.NewChocolateyPublisher(), nil
|
|
|
|
|
default:
|
2026-03-16 21:03:21 +00:00
|
|
|
return nil, coreerr.E("release.getPublisher", "unsupported publisher type: "+pubType, nil)
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// buildExtendedConfig builds a map of extended configuration for a publisher.
|
|
|
|
|
func buildExtendedConfig(pubCfg PublisherConfig) map[string]any {
|
|
|
|
|
ext := make(map[string]any)
|
|
|
|
|
|
|
|
|
|
// LinuxKit-specific config
|
|
|
|
|
if pubCfg.Config != "" {
|
|
|
|
|
ext["config"] = pubCfg.Config
|
|
|
|
|
}
|
|
|
|
|
if len(pubCfg.Formats) > 0 {
|
|
|
|
|
ext["formats"] = toAnySlice(pubCfg.Formats)
|
|
|
|
|
}
|
|
|
|
|
if len(pubCfg.Platforms) > 0 {
|
|
|
|
|
ext["platforms"] = toAnySlice(pubCfg.Platforms)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Docker-specific config
|
|
|
|
|
if pubCfg.Registry != "" {
|
|
|
|
|
ext["registry"] = pubCfg.Registry
|
|
|
|
|
}
|
|
|
|
|
if pubCfg.Image != "" {
|
|
|
|
|
ext["image"] = pubCfg.Image
|
|
|
|
|
}
|
|
|
|
|
if pubCfg.Dockerfile != "" {
|
|
|
|
|
ext["dockerfile"] = pubCfg.Dockerfile
|
|
|
|
|
}
|
|
|
|
|
if len(pubCfg.Tags) > 0 {
|
|
|
|
|
ext["tags"] = toAnySlice(pubCfg.Tags)
|
|
|
|
|
}
|
|
|
|
|
if len(pubCfg.BuildArgs) > 0 {
|
|
|
|
|
args := make(map[string]any)
|
|
|
|
|
for k, v := range pubCfg.BuildArgs {
|
|
|
|
|
args[k] = v
|
|
|
|
|
}
|
|
|
|
|
ext["build_args"] = args
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// npm-specific config
|
|
|
|
|
if pubCfg.Package != "" {
|
|
|
|
|
ext["package"] = pubCfg.Package
|
|
|
|
|
}
|
|
|
|
|
if pubCfg.Access != "" {
|
|
|
|
|
ext["access"] = pubCfg.Access
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Homebrew-specific config
|
|
|
|
|
if pubCfg.Tap != "" {
|
|
|
|
|
ext["tap"] = pubCfg.Tap
|
|
|
|
|
}
|
|
|
|
|
if pubCfg.Formula != "" {
|
|
|
|
|
ext["formula"] = pubCfg.Formula
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Scoop-specific config
|
|
|
|
|
if pubCfg.Bucket != "" {
|
|
|
|
|
ext["bucket"] = pubCfg.Bucket
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// AUR-specific config
|
|
|
|
|
if pubCfg.Maintainer != "" {
|
|
|
|
|
ext["maintainer"] = pubCfg.Maintainer
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-16 21:03:21 +00:00
|
|
|
// Chocolatey-specific configuration
|
feat: extract build/, release/, sdk/ from go-devops
Build system (8 builders, signing, archiving), release pipeline
(7 publishers, versioning, changelog), and SDK generation
(OpenAPI diff, code gen). 18K LOC, all tests pass except Go
builder workspace isolation (pre-existing).
Co-Authored-By: Virgil <virgil@lethean.io>
2026-03-09 12:37:36 +00:00
|
|
|
if pubCfg.Push {
|
|
|
|
|
ext["push"] = pubCfg.Push
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Official repo config (shared by multiple publishers)
|
|
|
|
|
if pubCfg.Official != nil {
|
|
|
|
|
official := make(map[string]any)
|
|
|
|
|
official["enabled"] = pubCfg.Official.Enabled
|
|
|
|
|
if pubCfg.Official.Output != "" {
|
|
|
|
|
official["output"] = pubCfg.Official.Output
|
|
|
|
|
}
|
|
|
|
|
ext["official"] = official
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ext
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// toAnySlice converts a string slice to an any slice.
|
|
|
|
|
func toAnySlice(s []string) []any {
|
|
|
|
|
result := make([]any, len(s))
|
|
|
|
|
for i, v := range s {
|
|
|
|
|
result[i] = v
|
|
|
|
|
}
|
|
|
|
|
return result
|
|
|
|
|
}
|