From 3bbb45caac8e7ac2c7cc2eafa6f69610156a153f Mon Sep 17 00:00:00 2001 From: Virgil Date: Wed, 1 Apr 2026 18:32:46 +0000 Subject: [PATCH] feat(build): add release workflow generator --- pkg/build/workflow.go | 48 ++++++++++++++++++++++++++++++++++++++ pkg/build/workflow_test.go | 44 ++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 pkg/build/workflow.go create mode 100644 pkg/build/workflow_test.go diff --git a/pkg/build/workflow.go b/pkg/build/workflow.go new file mode 100644 index 0000000..7f9cfbe --- /dev/null +++ b/pkg/build/workflow.go @@ -0,0 +1,48 @@ +// Package build provides project type detection and cross-compilation for the Core build system. +// This file handles generation of the release GitHub Actions workflow from the embedded template. +package build + +import ( + "embed" + + "dappco.re/go/core/build/internal/ax" + io_interface "dappco.re/go/core/io" + coreerr "dappco.re/go/core/log" +) + +//go:embed templates/release.yml +var releaseWorkflowTemplate embed.FS + +// DefaultReleaseWorkflowPath is the conventional output path for the release workflow. +// +// path := build.DefaultReleaseWorkflowPath // ".github/workflows/release.yml" +const DefaultReleaseWorkflowPath = ".github/workflows/release.yml" + +// WriteReleaseWorkflow writes the embedded release workflow template to path. +// When path is empty, it writes to .github/workflows/release.yml. +// +// err := build.WriteReleaseWorkflow(io.Local, "") +// err := build.WriteReleaseWorkflow(io.Local, "/tmp/repo/.github/workflows/release.yml") +func WriteReleaseWorkflow(fs io_interface.Medium, path string) error { + if path == "" { + path = DefaultReleaseWorkflowPath + } + + content, err := releaseWorkflowTemplate.ReadFile("templates/release.yml") + if err != nil { + return coreerr.E("build.WriteReleaseWorkflow", "failed to read embedded workflow template", err) + } + + if err := fs.Write(path, string(content)); err != nil { + return coreerr.E("build.WriteReleaseWorkflow", "failed to write release workflow", err) + } + + return nil +} + +// ReleaseWorkflowPath joins a project directory with the conventional workflow path. +// +// path := build.ReleaseWorkflowPath("/home/user/project") +func ReleaseWorkflowPath(projectDir string) string { + return ax.Join(projectDir, DefaultReleaseWorkflowPath) +} diff --git a/pkg/build/workflow_test.go b/pkg/build/workflow_test.go new file mode 100644 index 0000000..edf8eb5 --- /dev/null +++ b/pkg/build/workflow_test.go @@ -0,0 +1,44 @@ +package build + +import ( + "testing" + + "dappco.re/go/core/io" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestWorkflow_WriteReleaseWorkflow_Good(t *testing.T) { + t.Run("writes the embedded template to the default path", func(t *testing.T) { + fs := io.NewMockMedium() + + err := WriteReleaseWorkflow(fs, "") + require.NoError(t, err) + + content, err := fs.Read(DefaultReleaseWorkflowPath) + require.NoError(t, err) + + template, err := releaseWorkflowTemplate.ReadFile("templates/release.yml") + require.NoError(t, err) + + assert.Equal(t, string(template), content) + assert.Contains(t, content, "workflow_call:") + assert.Contains(t, content, "workflow_dispatch:") + assert.Contains(t, content, "core build --targets") + }) + + t.Run("writes to a custom path", func(t *testing.T) { + fs := io.NewMockMedium() + + err := WriteReleaseWorkflow(fs, "custom/workflow.yml") + require.NoError(t, err) + + content, err := fs.Read("custom/workflow.yml") + require.NoError(t, err) + assert.NotEmpty(t, content) + }) +} + +func TestWorkflow_ReleaseWorkflowPath_Good(t *testing.T) { + assert.Equal(t, "/tmp/project/.github/workflows/release.yml", ReleaseWorkflowPath("/tmp/project")) +}