Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 27 additions & 5 deletions cmd/func-util/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,20 +74,31 @@ func socat(ctx context.Context) error {
}

func scaffold(ctx context.Context) error {

if len(os.Args) != 2 {
return fmt.Errorf("expected exactly one positional argument (function project path)")
if len(os.Args) != 3 {
return fmt.Errorf("expected exactly two positional arguments (function project path, builder)")
}

path := os.Args[1]
builder := os.Args[2]

f, err := fn.NewFunction(path)
if err != nil {
return fmt.Errorf("cannot load func project: %w", err)
}

// TODO: gauron99 - Set the builder from the passed argument if not already set in the function config.
// This is necessary because the builder value needs to be known during scaffolding to
// determine the correct build directory (.s2i/builds/last vs .func/builds/last), but it
// may not be persisted to func.yaml yet. By passing it as an argument from the Tekton
// pipeline, we ensure the correct builder is used even when the function config is incomplete.
if f.Build.Builder == "" {
f.Build.Builder = builder
}

fmt.Printf("#### scaffold: builder='%s', runtime='%s'\n", f.Build.Builder, f.Runtime)

if f.Runtime != "go" && f.Runtime != "python" {
// Scaffolding is for now supported/needed only for Go.
// Scaffolding is for now supported/needed only for Go&Python
return nil
}

Expand All @@ -97,13 +108,25 @@ func scaffold(ctx context.Context) error {
}

appRoot := filepath.Join(f.Root, ".s2i", "builds", "last")
if f.Build.Builder != "s2i" {
// TODO: gauron99 - change this completely
appRoot = filepath.Join(f.Root, ".func", "builds", "last")
}
fmt.Printf("appRoot is '%s'\n", appRoot)
_ = os.RemoveAll(appRoot)

// build step now includes scaffolding for go-pack
err = scaffolding.Write(appRoot, f.Root, f.Runtime, f.Invoke, embeddedRepo.FS())
if err != nil {
return fmt.Errorf("cannot write the scaffolding: %w", err)
}

if f.Build.Builder != "s2i" {
return nil
}

// add s2i specific changes

if err := os.MkdirAll(filepath.Join(f.Root, ".s2i", "bin"), 0755); err != nil {
return fmt.Errorf("unable to create .s2i bin dir. %w", err)
}
Expand All @@ -121,7 +144,6 @@ func scaffold(ctx context.Context) error {
if err := os.WriteFile(filepath.Join(f.Root, ".s2i", "bin", "assemble"), []byte(asm), 0755); err != nil {
return fmt.Errorf("unable to write go assembler. %w", err)
}

return nil
}

Expand Down
53 changes: 50 additions & 3 deletions pkg/builders/buildpacks/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,14 @@ import (
"knative.dev/func/pkg/builders"
"knative.dev/func/pkg/docker"
fn "knative.dev/func/pkg/functions"
"knative.dev/func/pkg/scaffolding"
)

// DefaultName when no WithName option is provided to NewBuilder
const DefaultName = builders.Pack

var DefaultBaseBuilder = "ghcr.io/knative/builder-jammy-base:latest"
var DefaultTinyBuilder = "ghcr.io/knative/builder-jammy-tiny:latest"
var DefaultBaseBuilder = "ghcr.io/gauron99/builder-jammy-base:latest"
var DefaultTinyBuilder = "ghcr.io/gauron99/builder-jammy-tiny:latest"

var (
DefaultBuilderImages = map[string]string{
Expand All @@ -46,6 +47,7 @@ var (
// Ensure that all entries in this list are terminated with a trailing "/"
// See GHSA-5336-2g3f-9g3m for details
trustedBuilderImagePrefixes = []string{
"quay.io/dfridric/",
"quay.io/boson/",
"gcr.io/paketo-buildpacks/",
"docker.io/paketobuildpacks/",
Expand Down Expand Up @@ -116,7 +118,7 @@ func WithTimestamp(v bool) Option {
}
}

var DefaultLifecycleImage = "docker.io/buildpacksio/lifecycle:553c041"
var DefaultLifecycleImage = "docker.io/buildpacksio/lifecycle:3659764"

// Build the Function at path.
func (b *Builder) Build(ctx context.Context, f fn.Function, platforms []fn.Platform) (err error) {
Expand Down Expand Up @@ -171,6 +173,16 @@ func (b *Builder) Build(ctx context.Context, f fn.Function, platforms []fn.Platf
Volumes []string
}{Network: "", Volumes: nil},
}

// NOTE: gauron99 - this might be even created into a Client function and
// ran before the client.Build() all together (in the CLI). There are gonna
// be commonalitites across the builders for scaffolding with some nuances
// which could be handled by each "scaffolder" - similarly to builders.
// scaffold
if err = scaffold(f); err != nil {
return
}

if b.withTimestamp {
now := time.Now()
opts.CreationTime = &now
Expand All @@ -186,6 +198,12 @@ func (b *Builder) Build(ctx context.Context, f fn.Function, platforms []fn.Platf
opts.Env["BPE_DEFAULT_LISTEN_ADDRESS"] = "[::]:8080"
}

// go specific workdir set to where main is
if f.Runtime == "go" {
if _, ok := opts.Env["BP_GO_WORKDIR"]; !ok {
opts.Env["BP_GO_WORKDIR"] = ".func/builds/last"
}
}
var bindings = make([]string, 0, len(f.Build.Mounts))
for _, m := range f.Build.Mounts {
bindings = append(bindings, fmt.Sprintf("%s:%s", m.Source, m.Destination))
Expand Down Expand Up @@ -312,3 +330,32 @@ type ErrRuntimeNotSupported struct {
func (e ErrRuntimeNotSupported) Error() string {
return fmt.Sprintf("Pack builder has no default builder image for the '%v' language runtime. Please provide one.", e.Runtime)
}

// TODO: gauron99 - unify this with other builders; temporary for the go pack
//
// scaffold the project
func scaffold(f fn.Function) error {
// Scafffolding is currently only supported by the Go runtime
// Python currently uses an injector instead of this
if f.Runtime != "go" {
return nil
}

contextDir := filepath.Join(".func", "builds", "last")
appRoot := filepath.Join(f.Root, contextDir)
_ = os.RemoveAll(appRoot)

// The embedded repository contains the scaffolding code itself which glues
// together the middleware and a function via main
embeddedRepo, err := fn.NewRepository("", "") // default is the embedded fs
if err != nil {
return fmt.Errorf("unable to load the embedded scaffolding. %w", err)
}

// Write scaffolding to .func/builds/last
err = scaffolding.Write(appRoot, f.Root, f.Runtime, f.Invoke, embeddedRepo.FS())
if err != nil {
return fmt.Errorf("unable to build due to a scaffold error. %w", err)
}
return nil
}
6 changes: 3 additions & 3 deletions pkg/builders/buildpacks/builder_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,11 +86,11 @@ func TestBuild_BuildpacksDefault(t *testing.T) {
var (
i = &mockImpl{}
b = NewBuilder(WithImpl(i))
f = fn.Function{Runtime: "go"}
f = fn.Function{Runtime: "node"}
)

i.BuildFn = func(ctx context.Context, opts pack.BuildOptions) error {
expected := defaultBuildpacks["go"]
expected := defaultBuildpacks["node"]
if !reflect.DeepEqual(expected, opts.Buildpacks) {
t.Fatalf("expected buildpacks '%v', got '%v'", expected, opts.Buildpacks)
}
Expand Down Expand Up @@ -141,7 +141,7 @@ func TestBuild_BuilderImageExclude(t *testing.T) {
b = NewBuilder( // Func Builder logic
WithName(builders.Pack), WithImpl(i))
f = fn.Function{
Runtime: "go",
Runtime: "node",
}
)
funcIgnoreContent := []byte(`#testing comments
Expand Down
5 changes: 4 additions & 1 deletion pkg/pipelines/tekton/tasks.go
Original file line number Diff line number Diff line change
Expand Up @@ -440,13 +440,16 @@ spec:
- name: path
description: Path to the function project
default: ""
- name: builder
description: Builder to be used (pack or s2i)
default: ""
workspaces:
- name: source
description: The workspace containing the function project
steps:
- name: func-scaffold
image: %s
command: ["scaffold", "$(params.path)"]
command: ["scaffold", "$(params.path)", "$(params.builder)"]
`, ScaffoldImage)
}

Expand Down
5 changes: 5 additions & 0 deletions pkg/pipelines/tekton/templates.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,11 @@ func createAndApplyPipelineRunTemplate(f fn.Function, namespace string, labels m
}
}

// add BP_GO_WORKDIR for go-build buildpack
if f.Runtime == "go" {
buildEnvs = append(buildEnvs, "BP_GO_WORKDIR=.func/builds/last")
}

s2iImageScriptsUrl := defaultS2iImageScriptsUrl
if f.Runtime == "quarkus" {
s2iImageScriptsUrl = quarkusS2iImageScriptsUrl
Expand Down
2 changes: 2 additions & 0 deletions pkg/pipelines/tekton/templates_pack.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ spec:
params:
- name: path
value: $(workspaces.source.path)/$(params.contextDir)
- name: builder
value: pack
workspaces:
- name: source
workspace: source-workspace
Expand Down
2 changes: 2 additions & 0 deletions pkg/pipelines/tekton/templates_s2i.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ spec:
params:
- name: path
value: $(workspaces.source.path)/$(params.contextDir)
- name: builder
value: s2i
workspaces:
- name: source
workspace: source-workspace
Expand Down
2 changes: 1 addition & 1 deletion pkg/scaffolding/scaffold.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import (
// fs: filesytem which contains scaffolding at '[runtime]/scaffolding'
// (exclusive with 'repo')
func Write(out, src, runtime, invoke string, fs filesystem.Filesystem) (err error) {

fmt.Println("#### scaffolding.Write")
// detect the signature of the source code in the given location, presuming
// a runtime and invocation hint (default "http")
s, err := detectSignature(src, runtime, invoke)
Expand Down
Loading