chore(ax): resolve docker and linuxkit runtime commands
This commit is contained in:
parent
1c5e7b77fd
commit
6950a75fa3
6 changed files with 127 additions and 30 deletions
|
|
@ -40,13 +40,13 @@ func (b *DockerBuilder) Detect(fs io.Medium, dir string) (bool, error) {
|
|||
// Build builds Docker images for the specified targets.
|
||||
// Usage example: call value.Build(...) from integrating code.
|
||||
func (b *DockerBuilder) Build(ctx context.Context, cfg *build.Config, targets []build.Target) ([]build.Artifact, error) {
|
||||
// Validate docker CLI is available
|
||||
if err := b.validateDockerCli(); err != nil {
|
||||
dockerCommand, err := b.resolveDockerCli()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Ensure buildx is available
|
||||
if err := b.ensureBuildx(ctx); err != nil {
|
||||
if err := b.ensureBuildx(ctx, dockerCommand); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
|
@ -162,7 +162,7 @@ func (b *DockerBuilder) Build(ctx context.Context, cfg *build.Config, targets []
|
|||
core.Print(nil, " Platforms: %s", core.Join(", ", platforms...))
|
||||
core.Print(nil, " Tags: %s", core.Join(", ", imageRefs...))
|
||||
|
||||
if err := ax.ExecDir(ctx, cfg.ProjectDir, "docker", args...); err != nil {
|
||||
if err := ax.ExecDir(ctx, cfg.ProjectDir, dockerCommand, args...); err != nil {
|
||||
return nil, coreerr.E("DockerBuilder.Build", "buildx build failed", err)
|
||||
}
|
||||
|
||||
|
|
@ -179,25 +179,35 @@ func (b *DockerBuilder) Build(ctx context.Context, cfg *build.Config, targets []
|
|||
return artifacts, nil
|
||||
}
|
||||
|
||||
// validateDockerCli checks if the docker CLI is available.
|
||||
func (b *DockerBuilder) validateDockerCli() error {
|
||||
if _, err := ax.LookPath("docker"); err != nil {
|
||||
return coreerr.E("DockerBuilder.validateDockerCli", "docker CLI not found. Install it from https://docs.docker.com/get-docker/", err)
|
||||
// resolveDockerCli returns the executable path for the docker CLI.
|
||||
func (b *DockerBuilder) resolveDockerCli(paths ...string) (string, error) {
|
||||
if len(paths) == 0 {
|
||||
paths = []string{
|
||||
"/usr/local/bin/docker",
|
||||
"/opt/homebrew/bin/docker",
|
||||
"/Applications/Docker.app/Contents/Resources/bin/docker",
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
||||
command, err := ax.ResolveCommand("docker", paths...)
|
||||
if err != nil {
|
||||
return "", coreerr.E("DockerBuilder.resolveDockerCli", "docker CLI not found. Install it from https://docs.docker.com/get-docker/", err)
|
||||
}
|
||||
|
||||
return command, nil
|
||||
}
|
||||
|
||||
// ensureBuildx ensures docker buildx is available and has a builder.
|
||||
func (b *DockerBuilder) ensureBuildx(ctx context.Context) error {
|
||||
func (b *DockerBuilder) ensureBuildx(ctx context.Context, dockerCommand string) error {
|
||||
// Check if buildx is available
|
||||
if err := ax.Exec(ctx, "docker", "buildx", "version"); err != nil {
|
||||
if err := ax.Exec(ctx, dockerCommand, "buildx", "version"); err != nil {
|
||||
return coreerr.E("DockerBuilder.ensureBuildx", "buildx is not available. Install it from https://docs.docker.com/buildx/working-with-buildx/", err)
|
||||
}
|
||||
|
||||
// Check if we have a builder, create one if not
|
||||
if err := ax.Exec(ctx, "docker", "buildx", "inspect", "--bootstrap"); err != nil {
|
||||
if err := ax.Exec(ctx, dockerCommand, "buildx", "inspect", "--bootstrap"); err != nil {
|
||||
// Try to create a builder
|
||||
if err := ax.Exec(ctx, "docker", "buildx", "create", "--use", "--bootstrap"); err != nil {
|
||||
if err := ax.Exec(ctx, dockerCommand, "buildx", "create", "--use", "--bootstrap"); err != nil {
|
||||
return coreerr.E("DockerBuilder.ensureBuildx", "failed to create buildx builder", err)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,3 +81,22 @@ func TestDocker_DockerBuilderInterface_Good(t *testing.T) {
|
|||
var _ build.Builder = (*DockerBuilder)(nil)
|
||||
var _ build.Builder = NewDockerBuilder()
|
||||
}
|
||||
|
||||
func TestDocker_DockerBuilderResolveDockerCli_Good(t *testing.T) {
|
||||
builder := NewDockerBuilder()
|
||||
fallbackDir := t.TempDir()
|
||||
fallbackPath := ax.Join(fallbackDir, "docker")
|
||||
require.NoError(t, ax.WriteFile(fallbackPath, []byte("#!/bin/sh\nexit 0\n"), 0o755))
|
||||
|
||||
command, err := builder.resolveDockerCli(fallbackPath)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, fallbackPath, command)
|
||||
}
|
||||
|
||||
func TestDocker_DockerBuilderResolveDockerCli_Bad(t *testing.T) {
|
||||
builder := NewDockerBuilder()
|
||||
|
||||
_, err := builder.resolveDockerCli(ax.Join(t.TempDir(), "missing-docker"))
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "docker CLI not found")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ func (p *DockerPublisher) Publish(ctx context.Context, release *Release, pubCfg
|
|||
}
|
||||
|
||||
// Validate docker CLI is available after local config checks.
|
||||
if err := validateDockerCli(); err != nil {
|
||||
dockerCommand, err := resolveDockerCli()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -62,7 +63,7 @@ func (p *DockerPublisher) Publish(ctx context.Context, release *Release, pubCfg
|
|||
return p.dryRunPublish(release, dockerCfg)
|
||||
}
|
||||
|
||||
return p.executePublish(ctx, release, dockerCfg)
|
||||
return p.executePublish(ctx, release, dockerCfg, dockerCommand)
|
||||
}
|
||||
|
||||
// parseConfig extracts Docker-specific configuration.
|
||||
|
|
@ -164,9 +165,9 @@ func (p *DockerPublisher) dryRunPublish(release *Release, cfg DockerConfig) erro
|
|||
}
|
||||
|
||||
// executePublish builds and pushes Docker images.
|
||||
func (p *DockerPublisher) executePublish(ctx context.Context, release *Release, cfg DockerConfig) error {
|
||||
func (p *DockerPublisher) executePublish(ctx context.Context, release *Release, cfg DockerConfig, dockerCommand string) error {
|
||||
// Ensure buildx is available and builder is set up
|
||||
if err := p.ensureBuildx(ctx); err != nil {
|
||||
if err := p.ensureBuildx(ctx, dockerCommand); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -177,7 +178,7 @@ func (p *DockerPublisher) executePublish(ctx context.Context, release *Release,
|
|||
args := p.buildBuildxArgs(cfg, tags, release.Version)
|
||||
|
||||
publisherPrint("Building and pushing Docker image: %s", cfg.Image)
|
||||
if err := publisherRun(ctx, release.ProjectDir, nil, "docker", args...); err != nil {
|
||||
if err := publisherRun(ctx, release.ProjectDir, nil, dockerCommand, args...); err != nil {
|
||||
return coreerr.E("docker.Publish", "buildx build failed", err)
|
||||
}
|
||||
|
||||
|
|
@ -245,16 +246,16 @@ func (p *DockerPublisher) buildBuildxArgs(cfg DockerConfig, tags []string, versi
|
|||
}
|
||||
|
||||
// ensureBuildx ensures docker buildx is available and has a builder.
|
||||
func (p *DockerPublisher) ensureBuildx(ctx context.Context) error {
|
||||
func (p *DockerPublisher) ensureBuildx(ctx context.Context, dockerCommand string) error {
|
||||
// Check if buildx is available
|
||||
if err := ax.Exec(ctx, "docker", "buildx", "version"); err != nil {
|
||||
if err := ax.Exec(ctx, dockerCommand, "buildx", "version"); err != nil {
|
||||
return coreerr.E("docker.ensureBuildx", "buildx is not available. Install it from https://docs.docker.com/buildx/working-with-buildx/", nil)
|
||||
}
|
||||
|
||||
// Check if we have a builder, create one if not
|
||||
if err := ax.Exec(ctx, "docker", "buildx", "inspect", "--bootstrap"); err != nil {
|
||||
if err := ax.Exec(ctx, dockerCommand, "buildx", "inspect", "--bootstrap"); err != nil {
|
||||
// Try to create a builder
|
||||
if err := publisherRun(ctx, "", nil, "docker", "buildx", "create", "--use", "--bootstrap"); err != nil {
|
||||
if err := publisherRun(ctx, "", nil, dockerCommand, "buildx", "create", "--use", "--bootstrap"); err != nil {
|
||||
return coreerr.E("docker.ensureBuildx", "failed to create buildx builder", err)
|
||||
}
|
||||
}
|
||||
|
|
@ -262,10 +263,28 @@ func (p *DockerPublisher) ensureBuildx(ctx context.Context) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// resolveDockerCli returns the executable path for the docker CLI.
|
||||
func resolveDockerCli(paths ...string) (string, error) {
|
||||
if len(paths) == 0 {
|
||||
paths = []string{
|
||||
"/usr/local/bin/docker",
|
||||
"/opt/homebrew/bin/docker",
|
||||
"/Applications/Docker.app/Contents/Resources/bin/docker",
|
||||
}
|
||||
}
|
||||
|
||||
command, err := ax.ResolveCommand("docker", paths...)
|
||||
if err != nil {
|
||||
return "", coreerr.E("docker.resolveDockerCli", "docker CLI not found. Install it from https://docs.docker.com/get-docker/", err)
|
||||
}
|
||||
|
||||
return command, nil
|
||||
}
|
||||
|
||||
// validateDockerCli checks if the docker CLI is available.
|
||||
func validateDockerCli() error {
|
||||
if _, err := ax.LookPath("docker"); err != nil {
|
||||
return coreerr.E("docker.validateDockerCli", "docker CLI not found. Install it from https://docs.docker.com/get-docker/", nil)
|
||||
if _, err := resolveDockerCli(); err != nil {
|
||||
return coreerr.E("docker.validateDockerCli", "docker CLI not found. Install it from https://docs.docker.com/get-docker/", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -649,6 +649,22 @@ func TestDocker_ValidateDockerCli_Good(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestDocker_ResolveDockerCli_Good(t *testing.T) {
|
||||
fallbackDir := t.TempDir()
|
||||
fallbackPath := ax.Join(fallbackDir, "docker")
|
||||
require.NoError(t, ax.WriteFile(fallbackPath, []byte("#!/bin/sh\nexit 0\n"), 0o755))
|
||||
|
||||
command, err := resolveDockerCli(fallbackPath)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, fallbackPath, command)
|
||||
}
|
||||
|
||||
func TestDocker_ResolveDockerCli_Bad(t *testing.T) {
|
||||
_, err := resolveDockerCli(ax.Join(t.TempDir(), "missing-docker"))
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "docker CLI not found")
|
||||
}
|
||||
|
||||
func TestDocker_DockerPublisherPublishWithCLI_Good(t *testing.T) {
|
||||
// These tests run only when docker CLI is available
|
||||
if err := validateDockerCli(); err != nil {
|
||||
|
|
|
|||
|
|
@ -42,8 +42,8 @@ func (p *LinuxKitPublisher) Name() string {
|
|||
// Publish builds LinuxKit images and uploads them to the GitHub release.
|
||||
// Usage example: call value.Publish(...) from integrating code.
|
||||
func (p *LinuxKitPublisher) Publish(ctx context.Context, release *Release, pubCfg PublisherConfig, relCfg ReleaseConfig, dryRun bool) error {
|
||||
// Validate linuxkit CLI is available
|
||||
if err := validateLinuxKitCli(); err != nil {
|
||||
linuxkitCommand, err := resolveLinuxKitCli()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +75,7 @@ func (p *LinuxKitPublisher) Publish(ctx context.Context, release *Release, pubCf
|
|||
return p.dryRunPublish(release, lkCfg, repo)
|
||||
}
|
||||
|
||||
return p.executePublish(ctx, release, lkCfg, repo)
|
||||
return p.executePublish(ctx, release, lkCfg, repo, linuxkitCommand)
|
||||
}
|
||||
|
||||
// parseConfig extracts LinuxKit-specific configuration.
|
||||
|
|
@ -172,7 +172,7 @@ func (p *LinuxKitPublisher) dryRunPublish(release *Release, cfg LinuxKitConfig,
|
|||
}
|
||||
|
||||
// executePublish builds LinuxKit images and uploads them.
|
||||
func (p *LinuxKitPublisher) executePublish(ctx context.Context, release *Release, cfg LinuxKitConfig, repo string) error {
|
||||
func (p *LinuxKitPublisher) executePublish(ctx context.Context, release *Release, cfg LinuxKitConfig, repo, linuxkitCommand string) error {
|
||||
outputDir := ax.Join(release.ProjectDir, "dist", "linuxkit")
|
||||
|
||||
// Create output directory
|
||||
|
|
@ -197,7 +197,7 @@ func (p *LinuxKitPublisher) executePublish(ctx context.Context, release *Release
|
|||
// Build the image
|
||||
args := p.buildLinuxKitArgs(cfg.Config, format, outputName, outputDir, arch)
|
||||
publisherPrint("Building LinuxKit image: %s (%s)", outputName, format)
|
||||
if err := publisherRun(ctx, release.ProjectDir, nil, "linuxkit", args...); err != nil {
|
||||
if err := publisherRun(ctx, release.ProjectDir, nil, linuxkitCommand, args...); err != nil {
|
||||
return coreerr.E("linuxkit.Publish", "build failed for "+platform+"/"+format, err)
|
||||
}
|
||||
|
||||
|
|
@ -292,9 +292,26 @@ func (p *LinuxKitPublisher) getFormatExtension(format string) string {
|
|||
}
|
||||
}
|
||||
|
||||
// resolveLinuxKitCli returns the executable path for the linuxkit CLI.
|
||||
func resolveLinuxKitCli(paths ...string) (string, error) {
|
||||
if len(paths) == 0 {
|
||||
paths = []string{
|
||||
"/usr/local/bin/linuxkit",
|
||||
"/opt/homebrew/bin/linuxkit",
|
||||
}
|
||||
}
|
||||
|
||||
command, err := ax.ResolveCommand("linuxkit", paths...)
|
||||
if err != nil {
|
||||
return "", coreerr.E("linuxkit.resolveLinuxKitCli", "linuxkit CLI not found. Install it from https://github.com/linuxkit/linuxkit", err)
|
||||
}
|
||||
|
||||
return command, nil
|
||||
}
|
||||
|
||||
// validateLinuxKitCli checks if the linuxkit CLI is available.
|
||||
func validateLinuxKitCli() error {
|
||||
if _, err := ax.LookPath("linuxkit"); err != nil {
|
||||
if _, err := resolveLinuxKitCli(); err != nil {
|
||||
return coreerr.E("linuxkit.validateLinuxKitCli", "linuxkit CLI not found. Install it from https://github.com/linuxkit/linuxkit", err)
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
|
|
@ -266,6 +266,22 @@ func TestLinuxKit_ValidateLinuxKitCli_Good(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestLinuxKit_ResolveLinuxKitCli_Good(t *testing.T) {
|
||||
fallbackDir := t.TempDir()
|
||||
fallbackPath := ax.Join(fallbackDir, "linuxkit")
|
||||
require.NoError(t, ax.WriteFile(fallbackPath, []byte("#!/bin/sh\nexit 0\n"), 0o755))
|
||||
|
||||
command, err := resolveLinuxKitCli(fallbackPath)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, fallbackPath, command)
|
||||
}
|
||||
|
||||
func TestLinuxKit_ResolveLinuxKitCli_Bad(t *testing.T) {
|
||||
_, err := resolveLinuxKitCli(ax.Join(t.TempDir(), "missing-linuxkit"))
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "linuxkit CLI not found")
|
||||
}
|
||||
|
||||
func TestLinuxKit_LinuxKitPublisherPublishWithCLI_Good(t *testing.T) {
|
||||
// These tests run only when linuxkit CLI is available
|
||||
if err := validateLinuxKitCli(); err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue