Skip to content

feat: Remote builds from a git repository no longer require a local checkout - #4039

Draft
gauron99 wants to merge 6 commits into
knative:mainfrom
gauron99:push-mmxznyrpmwxy
Draft

feat: Remote builds from a git repository no longer require a local checkout#4039
gauron99 wants to merge 6 commits into
knative:mainfrom
gauron99:push-mmxznyrpmwxy

Conversation

@gauron99

@gauron99 gauron99 commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Changes

func deploy --remote --git-url built the pipeline from the local func.yaml while the cluster cloned the repository and read its own. The local copy existed only to feed the CLI, so it was required and had to match the branch and directory being built.

  • 🎁 The repository is now the source of the function: NewFunctionFromGit reads func.yaml from the requested revision (branch, tag or commit) and --git-dir, the flags apply to that, and the pipeline runs for it. A local function at the path is optional; when present it only records the git settings and the outcome (image, namespace, deployer, exposure). Migrations take the serialized bytes instead of re-reading f.Root, so a function without a working tree can be migrated.
  • 🐛 The image's org.opencontainers.image.revision label was the local HEAD, not the revision the cluster builds. It is now resolved from the git source before any cluster resource is created, so an unknown revision fails early.
  • 🐛 A second remote build of the same function from git failed in the fetch step: the git-clone StepAction (user 65532) could not clear sources left by the build user (1001). A root clean-src step empties the workspace before the clone; the upload path and the cache workspace are untouched.
  • 🧹 The remote git e2e tests deploy from an empty directory, dropping their clone/checkout/cd workarounds.

Prerequisite: #4038 (wait for the CoreDNS rollout in func cluster create). This branch includes that commit; it was needed to get a local cluster up for the verification below.

Pre-existing and out of scope: deploy-intent flags (--deployer, --expose, --env) do not reach the cluster in the git path, and private repositories are still fetched anonymously on the cluster.

testing

Verified on a kind cluster with Tekton: the four remote e2e tests pass, plus manual deploys from an empty directory by branch and by subdirectory, from a checkout on another branch, a wrong revision (no PipelineRun created) and a redeploy on the same volume.

/kind enhancement

Fixes #3203

Release Note

release-note
func deploy --remote --git-url no longer needs a local copy of the function: func.yaml is read from the repository at the requested --git-branch and --git-dir. Deploying the same function from git a second time no longer fails in the clone step.

Magic DNS patched the coredns deployment, slept, then waited for every
kube-system pod to be Ready. The old coredns pods are terminating after
the patch and never become Ready again, so the wait timed out after 60s
on hosts where they took a while to go, and the whole cluster was torn
down at the very last step. Wait for the deployment rollout instead: the
new pods are available and the old ones are gone. hack/cluster.sh has
the same sleep-and-wait, from which this was ported.
NewFunctionFromGit reads func.yaml from a revision of a remote repository
(default branch, branch, tag or commit hash) in memory, and GitRemoteCommit
reports the commit that revision resolves to. Both reuse the credential
lookup the template repositories already use.

Migrations used to re-read the on-disk func.yaml from f.Root to see the
previous structure, so a function with no working tree could not be
migrated. hasInitializedFunction in the client hit the same problem by
migrating an unmarshalled function that had no Root. Migrations now
receive the serialized bytes they were parsed from, and NewFunction,
NewFunctionFromGit and hasInitializedFunction share parseFunction.

Groundwork for knative#3203.
The Tekton provider read two things from the local checkout that do not
describe a build from a git repository: the commit label came from the
local HEAD (fn.GitCommit on f.Root) rather than the revision the cluster
clones, and a .tekton/ override was looked up under f.Root, which for a
function without a Root resolved to the current directory.

The commit is now resolved from the source the pipeline builds, via
GitRemoteCommit for a git source, and before any cluster resource is
created, so an unknown revision fails early. The override lookup is
skipped without a Root, and uploading sources without a Root is refused
with a clear error.
A remote deployment of a git repository had two sources of truth: the
CLI built the Tekton pipeline from the local func.yaml while the cluster
cloned the repository and read its func.yaml. The local copy existed
only to feed the CLI, so it was required, and had to be on the right
branch and in the right directory to match what the cluster built.

The repository is now the source of the function when --remote has a
git URL. The CLI reads func.yaml from the requested revision and
directory (NewFunctionFromGit), applies the flags to that, and runs the
pipeline for it. A local function at the path is optional. When present
it records the request and the outcome (git settings, registry,
deployed image, namespace, deployer, exposure) so describe, delete and
later deploys find them, and its own metadata is left untouched.

The prompts of build, run and deploy take the loaded function instead
of loading one from the path themselves, and Validate no longer demands
a Root: where a function lives is not part of its correctness, and Write
is what needs one. The branch-mismatch warning is gone with the mismatch.

Closes knative#3203.
@knative-prow

knative-prow Bot commented Sep 2, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@knative-prow knative-prow Bot added do-not-merge/work-in-progress 🤖 PR should not merge because it is a work in progress. kind/enhancement Feature additions or improvements to existing labels Sep 2, 2026
@gauron99
gauron99 requested a balanced review from Copilot and removed request for dsimansk and jrangelramos September 2, 2026 22:46
@knative-prow

knative-prow Bot commented Sep 2, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: gauron99

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@knative-prow knative-prow Bot added approved 🤖 PR has been approved by an approver from all required OWNERS files. size/XXL 🤖 PR changes 1000+ lines, ignoring generated files. labels Sep 2, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Remote metadata, built source, and persisted deployment identity can diverge in several supported flows.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Enables remote git deployments without a local function checkout and includes the CoreDNS rollout prerequisite.

Changes:

  • Loads and migrates func.yaml directly from git.
  • Resolves source commits and cleans Tekton workspaces before cloning.
  • Updates CLI flows, tests, E2E coverage, and documentation.
File summaries
File Description
pkg/pipelines/tekton/templates.go Supports rootless functions and commit labels.
pkg/pipelines/tekton/templates_test.go Tests rootless pipeline rendering.
pkg/pipelines/tekton/tasks_test.go Verifies cleanup-step ordering.
pkg/pipelines/tekton/task-s2i.yaml.tmpl Cleans git source workspace.
pkg/pipelines/tekton/task-buildpack.yaml.tmpl Cleans git source workspace.
pkg/pipelines/tekton/source_commit_test.go Tests source commit resolution.
pkg/pipelines/tekton/pipelines_provider.go Resolves commits before resource creation.
pkg/functions/git_commit.go Adds remote commit lookup.
pkg/functions/function.go Parses rootless serialized functions.
pkg/functions/function_migrations.go Migrates directly from serialized bytes.
pkg/functions/function_git.go Loads functions from git revisions.
pkg/functions/function_git_test.go Tests git loading and migration.
pkg/functions/client.go Reuses serialized-function parsing.
pkg/cluster/dns.go Waits for the CoreDNS rollout.
e2e/e2e_remote_test.go Removes local checkout workarounds.
docs/reference/func_deploy.md Documents checkout-free deployment.
cmd/run.go Supplies function context to prompts.
cmd/deploy.go Selects and persists remote functions.
cmd/deploy_test.go Tests checkout-free deploy behavior.
cmd/config_git_set.go Supplies function context to prompts.
cmd/build.go Supplies function context to prompts.
Review details
  • Files reviewed: 21/22 changed files
  • Comments generated: 5
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread cmd/deploy.go
// For now, give a more helpful error.
return errors.New("please ensure the function's source is also available locally")
}
if f, err = cfg.function(cmd.Context(), local); err != nil {
Comment thread cmd/deploy.go
Comment on lines +443 to +445
// A local function at path, if there is one, records the request and the
// outcome so that later commands (describe, delete, another deploy) find
// them; its own metadata is left alone.
// checkout otherwise.
func sourceCommit(ctx context.Context, f fn.Function) (string, error) {
if f.Build.Git.URL != "" {
commit, err := fn.GitRemoteCommit(ctx, f.Build.Git)
Comment thread cmd/deploy.go
return wrapValidateError(err, "deploy")
}
// The prompt may have made the source a git repository
if cfg.Remote && cfg.GitURL != "" && f.Root != "" {
Comment thread cmd/deploy.go
local.Deploy.Namespace = f.Deploy.Namespace
local.Deploy.Deployer = f.Deploy.Deployer
local.Deploy.Expose = f.Deploy.Expose
f = local
TestRemote_Source, TestRemote_Ref and TestRemote_Dir cloned the
repository, checked out the branch or changed into the subdirectory
before deploying, because the CLI read the function's metadata from the
local func.yaml. The function now comes from the repository, so the
tests deploy from an empty directory, which is what they set out to
cover.
The git-clone StepAction runs as user 65532 and empties the source
workspace before cloning. The previous run of the pipeline leaves the
sources there owned by the build user (the prepare step chowns the tree
to 1001 for the buildpacks lifecycle), which 65532 can neither delete
nor create .git next to. Every remote build of a function from git after
its first therefore failed in the fetch step, until func delete removed
the volume.

A clean-src step, run as root and gated on a git URL like fetch-src,
now empties the workspace and hands the directory to the clone user
before the clone. The upload path is unaffected, and the cache
workspace is a separate directory that is left alone.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved 🤖 PR has been approved by an approver from all required OWNERS files. do-not-merge/work-in-progress 🤖 PR should not merge because it is a work in progress. kind/enhancement Feature additions or improvements to existing size/XXL 🤖 PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remote builds require checkout

2 participants