an image artifact may name its own build context, apart from the module's repository
route-proxy's own Dockerfile documents the shape it has always needed and
never had: 'the proxy source is not vendored here... the build context is
the mesh-controller repository root, and this Dockerfile compiles
./examples/route-proxy from it.' Nothing in the mesh could do that — the
build command clones one repository and builds every artifact from
within it, so route-proxy has never once been built through the pipeline,
consistent with it never having been assigned anywhere. Found attempting
exactly that build tonight: 'stat go.mod: file does not exist', because
the context was mesh-catalog, which does not have one.
An image artifact may now carry a context: {repository, ref}, cloned
fresh alongside the module's own tree. The recipe (Dockerfile) is still
read from the module's own directory, at the module's own commit — only
docker build's own context argument moves. Packaging and source stay
exactly as separate as route-proxy's own comment already said they were,
now for real.
This commit is contained in:
@@ -177,7 +177,7 @@ func Build(ctx context.Context, run Runner, publish Publisher,
|
||||
sort.Slice(artifacts, func(i, j int) bool { return artifacts[i].Name < artifacts[j].Name })
|
||||
for _, a := range artifacts {
|
||||
say("artifact", "%s (%s%s) — starting", a.Name, a.Kind, langSuffix(a))
|
||||
made, err := one(ctx, run, publish, manifest.Module, within, commit, a, args, held, npmrcPath, say)
|
||||
made, err := one(ctx, run, publish, manifest.Module, within, workspace, commit, a, args, held, npmrcPath, say)
|
||||
if err != nil {
|
||||
say("artifact", "%s FAILED: %v", a.Name, err)
|
||||
return Result{}, err
|
||||
@@ -210,6 +210,28 @@ func logging(log Log) func(step, format string, args ...any) {
|
||||
}
|
||||
}
|
||||
|
||||
// contextFrom clones an image artifact's own build context, when it names one apart from this
|
||||
// module's own repository — a fresh tree, the same way the module's own is, keyed by artifact
|
||||
// name so two artifacts of one module naming different contexts do not collide.
|
||||
func contextFrom(ctx context.Context, run Runner, workspace, artifact string,
|
||||
from catalogue.ArtifactContext, say func(step, format string, args ...any)) (string, error) {
|
||||
say("context", "cloning %s at %s for %s", from.Repository, refOrHead(from.Ref), artifact)
|
||||
dir := filepath.Join(workspace, "context-"+artifact)
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
return "", err
|
||||
}
|
||||
if _, err := run(ctx, workspace, "git", "clone", "--quiet", from.Repository, dir); err != nil {
|
||||
return "", fmt.Errorf("cannot clone %s: %w", from.Repository, err)
|
||||
}
|
||||
if from.Ref != "" {
|
||||
if _, err := run(ctx, dir, "git", "checkout", "--quiet", from.Ref); err != nil {
|
||||
return "", fmt.Errorf("%s has no %s: %w", from.Repository, from.Ref, err)
|
||||
}
|
||||
}
|
||||
say("context", "done")
|
||||
return dir, nil
|
||||
}
|
||||
|
||||
func describePath(path string) string {
|
||||
if path == "" {
|
||||
return ""
|
||||
@@ -333,7 +355,7 @@ func wantsPackages(manifest catalogue.Manifest, within string) bool {
|
||||
}
|
||||
|
||||
func one(ctx context.Context, run Runner, publish Publisher,
|
||||
module, tree, commit string, a catalogue.Artifact, args []string,
|
||||
module, tree, workspace, commit string, a catalogue.Artifact, args []string,
|
||||
held map[string]string, npmrc string, say func(step, format string, args ...any)) (catalogue.Built, error) {
|
||||
|
||||
switch a.Kind {
|
||||
@@ -405,7 +427,27 @@ func one(ctx context.Context, run Runner, publish Publisher,
|
||||
"and start FROM ${<NAME>} (novox/hq ADR 0097)",
|
||||
module, a.From, strings.Join(bases, ", "))
|
||||
}
|
||||
invocation := append([]string{"build", "-f", a.From, "-t", local}, args...)
|
||||
// The recipe is always read from this module's own tree, at this module's own commit — only
|
||||
// the context docker build's final argument names can come from somewhere else, when the
|
||||
// artifact says so.
|
||||
recipePath := a.From
|
||||
buildDir := tree
|
||||
if a.Context != nil {
|
||||
cloned, err := contextFrom(ctx, run, workspace, a.Name, *a.Context, say)
|
||||
if err != nil {
|
||||
return catalogue.Built{}, fmt.Errorf("%s: %s's context: %w", module, a.Name, err)
|
||||
}
|
||||
// docker build accepts -f outside the context it is given; the recipe stays exactly
|
||||
// where it was read from and validated against, absolute so the working directory
|
||||
// switching to the cloned context does not change which file that is.
|
||||
absRecipe, err := filepath.Abs(filepath.Join(tree, a.From))
|
||||
if err != nil {
|
||||
return catalogue.Built{}, fmt.Errorf("%s: %s's recipe: %w", module, a.Name, err)
|
||||
}
|
||||
recipePath = absRecipe
|
||||
buildDir = cloned
|
||||
}
|
||||
invocation := append([]string{"build", "-f", recipePath, "-t", local}, args...)
|
||||
if a.Target != "" {
|
||||
invocation = append(invocation, "--target", a.Target)
|
||||
}
|
||||
@@ -417,8 +459,8 @@ func one(ctx context.Context, run Runner, publish Publisher,
|
||||
invocation = append(invocation, "--network", "host")
|
||||
}
|
||||
invocation = append(invocation, ".")
|
||||
say("image", "docker build -f %s", a.From)
|
||||
if _, err := run(ctx, tree, "docker", invocation...); err != nil {
|
||||
say("image", "docker build -f %s", recipePath)
|
||||
if _, err := run(ctx, buildDir, "docker", invocation...); err != nil {
|
||||
return catalogue.Built{}, fmt.Errorf("%s: building %s failed: %w", module, a.Name, err)
|
||||
}
|
||||
say("image", "built, publishing")
|
||||
|
||||
Reference in New Issue
Block a user