buildpacks / tekton-integration

Buildpacks + Tekton
22 stars 3 forks source link

Failed to build function with tekton #4

Closed benjaminhuo closed 3 years ago

benjaminhuo commented 3 years ago

I am able to build sample functions https://github.com/OpenFunction/function-samples with the following command , google.go.functions-framework is detected correctly:

pack build --builder gcr.io/buildpacks/builder:v1 --env GOOGLE_FUNCTION_SIGNATURE_TYPE=http --env GOOGLE_FUNCTION_TARGET=HelloWorld benjaminhuo/sample-go-func:latest
v1: Pulling from buildpacks/builder
Digest: sha256:889d1cc172467dfb5560c69e5a24d8215804e0fb9ae36e2774f33bc2033ffb8c
Status: Image is up to date for gcr.io/buildpacks/builder:v1
v1: Pulling from buildpacks/gcp/run
Digest: sha256:35c7b9995b7b0ad398e504bc178e38b28626e1ce9052cfeabc8750fc313b4d36
Status: Image is up to date for gcr.io/buildpacks/gcp/run:v1
===> DETECTING
4 of 6 buildpacks participating
google.go.runtime             0.9.1
**google.go.functions-framework 0.9.3**
google.go.build               0.9.0
google.utils.label            0.0.1
===> ANALYZING
Previous image with name "benjaminhuo/sample-go-func:latest" not found
===> RESTORING
===> BUILDING
=== Go - Runtime (google.go.runtime@0.9.1) ===
Using runtime version from go.mod: 1.15
Installing Go v1.15
--------------------------------------------------------------------------------
Running "bash -c curl --fail --show-error --silent --location --retry 3 https://dl.google.com/go/go1.15.linux-amd64.tar.gz | tar xz --directory /layers/google.go.runtime/go --strip-components=1"
Done "bash -c curl --fail --show-error --silent --location --retry..." (49.627675478s)
=== Go - Functions Framework (google.go.functions-framework@0.9.3) ===
--------------------------------------------------------------------------------
Running "go run main -dir /workspace/serverless_function_source_code (GOPATH=/cnb/buildpacks/google.go.functions-framework/0.9.3/converter/get_package GOCACHE=/tmp/serverless_function_app815959087)"
helloDone "go run main -dir /workspace/serverless_function_source_code ..." (764.8063ms)
No framework version specified, using default
--------------------------------------------------------------------------------
Running "go get github.com/GoogleCloudPlatform/functions-framework-go@v1.2.0"
go: downloading github.com/GoogleCloudPlatform/functions-framework-go v1.2.0
Done "go get github.com/GoogleCloudPlatform/functions-framework-go..." (2.526341623s)
=== Go - Build (google.go.build@0.9.0) ===
--------------------------------------------------------------------------------
Running "go list -f {{if eq .Name \"main\"}}{{.Dir}}{{end}} ./..."
go: downloading github.com/cloudevents/sdk-go/v2 v2.2.0
go: downloading github.com/GoogleCloudPlatform/functions-framework-go v1.2.0
go: downloading cloud.google.com/go v0.63.0
go: downloading go.uber.org/zap v1.10.0
go: downloading go.opencensus.io v0.22.4
go: downloading github.com/google/uuid v1.1.1
go: downloading github.com/lightstep/tracecontext.go v0.0.0-20181129014701-1757c391b1ac
go: downloading go.uber.org/multierr v1.1.0
go: downloading go.uber.org/atomic v1.4.0
go: downloading github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e
/workspace
Done "go list -f {{if eq .Name \"main\"}}{{.Dir}}{{end}} ./..." (2.416441543s)
--------------------------------------------------------------------------------
Running "go build -o /layers/google.go.build/bin/main ./. (GOCACHE=/layers/google.go.build/gocache)"
Done "go build -o /layers/google.go.build/bin/main ./. (GOCACHE=/l..." (1.954832873s)
=== Utils - Label Image (google.utils.label@0.0.1) ===
===> EXPORTING
Adding layer 'google.go.build:bin'
Adding 1/1 app layer(s)
Adding layer 'launcher'
Adding layer 'config'
Adding layer 'process-types'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
Setting default process type 'web'
*** Images (a65b5fafa023):
      benjaminhuo/sample-go-func:latest
Adding cache layer 'google.go.runtime:go'
Successfully built image benjaminhuo/sample-go-func:latest

But when I use tekton to build the same function with gcr.io/buildpacks/builder:v1, google.go.functions-framework cannot be detected even after I add correct function environment to tekton tasks:

  stepTemplate:
    env:
      - name: CNB_PLATFORM_API
        value: "0.3"
      - name: GOOGLE_FUNCTION_SIGNATURE_TYPE
        value: "http"
      - name: GOOGLE_FUNCTION_TARGET
        value: "HelloWorld"
021/01/29 09:17:56 unsuccessful cred copy: ".docker" from "/tekton/creds" to "/tekton/home": unable to open destination: open /tekton/home/.docker/config.json: permission denied
===> DETECTING
3 of 6 buildpacks participating
google.go.runtime  0.9.1
google.go.build    0.9.0
google.utils.label 0.0.1
===> ANALYZING
Restoring metadata for "google.go.build:bin" from app image
===> RESTORING
===> BUILDING
=== Go - Runtime (google.go.runtime@0.9.1) ===
Using runtime version from go.mod: 1.15
Installing Go v1.15
--------------------------------------------------------------------------------
Running "bash -c curl --fail --show-error --silent --location --retry 3 https://dl.google.com/go/go1.15.linux-amd64.tar.gz | tar xz --directory /layers/google.go.runtime/go --strip-components=1"
Done "bash -c curl --fail --show-error --silent --location --retry..." (49.726331998s)
=== Go - Build (google.go.build@0.9.0) ===
--------------------------------------------------------------------------------
Running "go list -f {{if eq .Name \"main\"}}{{.Dir}}{{end}} ./..."
Done "go list -f {{if eq .Name \"main\"}}{{.Dir}}{{end}} ./..." (95.171861ms)
--------------------------------------------------------------------------------
Running "go build -o /layers/google.go.build/bin/main . (GOCACHE=/layers/google.go.build/gocache)"
Done "go build -o /layers/google.go.build/bin/main . (GOCACHE=/lay..." (221.209006ms)
=== Utils - Label Image (google.utils.label@0.0.1) ===
===> EXPORTING
Reusing layers from image 'index.docker.io/benjaminhuo/sample-go-func@sha256:cdef2bd124e6f8eeff2fcb4bfc63c189cf86bd04f322fbf51e5e91463ac71c30'
Adding layer 'google.go.build:bin'
Adding 1/1 app layer(s)
Reusing layer 'launcher'
Reusing layer 'config'
Adding label 'io.buildpacks.lifecycle.metadata'
Adding label 'io.buildpacks.build.metadata'
Adding label 'io.buildpacks.project.metadata'
*** Images (sha256:5d7e02be54eb0e88db49918b379de6637558a41397214f6e84d91e37ab0370ae):
      benjaminhuo/sample-go-func:latest
Adding cache layer 'google.go.runtime:go'

The tekton stuff is based on the CNB official website example with some modification

---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-clone
  labels:
    app.kubernetes.io/version: "0.2"
  annotations:
    tekton.dev/pipelines.minVersion: "0.12.1"
    tekton.dev/tags: git
    tekton.dev/displayName: "git clone"
spec:
  description: >-
    These Tasks are Git tasks to work with repositories used by other tasks
    in your Pipeline.

    The git-clone Task will clone a repo from the provided url into the
    output Workspace. By default the repo will be cloned into the root of
    your Workspace. You can clone into a subdirectory by setting this Task's
    subdirectory param.

  workspaces:
    - name: output
      description: The git repo will be cloned onto the volume backing this workspace
  params:
    - name: url
      description: git url to clone
      type: string
    - name: revision
      description: git revision to checkout (branch, tag, sha, ref…)
      type: string
      default: ""
    - name: refspec
      description: (optional) git refspec to fetch before checking out revision
      default: ""
    - name: submodules
      description: defines if the resource should initialize and fetch the submodules
      type: string
      default: "true"
    - name: depth
      description: performs a shallow clone where only the most recent commit(s) will be fetched
      type: string
      default: "1"
    - name: sslVerify
      description: defines if http.sslVerify should be set to true or false in the global git config
      type: string
      default: "true"
    - name: subdirectory
      description: subdirectory inside the "output" workspace to clone the git repo into
      type: string
      default: ""
    - name: deleteExisting
      description: clean out the contents of the repo's destination directory (if it already exists) before trying to clone the repo there
      type: string
      default: "true"
    - name: httpProxy
      description: git HTTP proxy server for non-SSL requests
      type: string
      default: ""
    - name: httpsProxy
      description: git HTTPS proxy server for SSL requests
      type: string
      default: ""
    - name: noProxy
      description: git no proxy - opt out of proxying HTTP/HTTPS requests
      type: string
      default: ""
    - name: verbose
      description: log the commands used during execution
      type: string
      default: "true"
    - name: gitInitImage
      description: the image used where the git-init binary is
      type: string
      default: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.18.1"
  results:
    - name: commit
      description: The precise commit SHA that was fetched by this Task
    - name: url
      description: The precise URL that was fetched by this Task
  steps:
    - name: clone
      image: $(params.gitInitImage)
      script: |
        #!/bin/sh
        set -eu -o pipefail

        if [[ "$(params.verbose)" == "true" ]] ; then
          set -x
        fi

        CHECKOUT_DIR="$(workspaces.output.path)/$(params.subdirectory)"

        cleandir() {
          # Delete any existing contents of the repo directory if it exists.
          #
          # We don't just "rm -rf $CHECKOUT_DIR" because $CHECKOUT_DIR might be "/"
          # or the root of a mounted volume.
          if [[ -d "$CHECKOUT_DIR" ]] ; then
            # Delete non-hidden files and directories
            rm -rf "$CHECKOUT_DIR"/*
            # Delete files and directories starting with . but excluding ..
            rm -rf "$CHECKOUT_DIR"/.[!.]*
            # Delete files and directories starting with .. plus any other character
            rm -rf "$CHECKOUT_DIR"/..?*
          fi
        }

        if [[ "$(params.deleteExisting)" == "true" ]] ; then
          cleandir
        fi

        test -z "$(params.httpProxy)" || export HTTP_PROXY=$(params.httpProxy)
        test -z "$(params.httpsProxy)" || export HTTPS_PROXY=$(params.httpsProxy)
        test -z "$(params.noProxy)" || export NO_PROXY=$(params.noProxy)

        /ko-app/git-init \
          -url "$(params.url)" \
          -revision "$(params.revision)" \
          -refspec "$(params.refspec)" \
          -path "$CHECKOUT_DIR" \
          -sslVerify="$(params.sslVerify)" \
          -submodules="$(params.submodules)" \
          -depth "$(params.depth)"
        cd "$CHECKOUT_DIR"
        RESULT_SHA="$(git rev-parse HEAD)"
        EXIT_CODE="$?"
        if [ "$EXIT_CODE" != 0 ] ; then
          exit $EXIT_CODE
        fi
        # ensure we don't add a trailing newline to the result
        echo -n "$RESULT_SHA" > $(results.commit.path)
        echo -n "$(params.url)" > $(results.url.path)
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: buildpacks
  labels:
    app.kubernetes.io/version: "0.1"
  annotations:
    tekton.dev/pipelines.minVersion: "0.12.1"
    tekton.dev/tags: image-build
    tekton.dev/deprecated: "true"
    tekton.dev/displayName: "buildpacks"
spec:
  description: >-
    The Buildpacks task builds source into a container image and pushes it to a registry,
    using Cloud Native Buildpacks.
    Cloud Native Buildpacks are pluggable, modular tools that transform application source code
    into OCI images. They replace Dockerfiles in the app development lifecycle, and allow for swift
    rebasing of images, and give modular control over images through the use of builders, among other
    benefits. This command uses a builder to construct the image, and pushes it to the registry provided.
  params:
    - name: BUILDER_IMAGE
      description: The image on which builds will run (must include lifecycle and compatible buildpacks).
    - name: CACHE
      description: The name of the persistent app cache volume.
      default: empty-dir
    - name: CACHE_IMAGE
      description: The name of the persistent app cache image.
      default: ""
    - name: PLATFORM_DIR
      description: The name of the platform directory.
      default: empty-dir
    - name: USER_ID
      description: The user ID of the builder image user.
      default: "1000"
    - name: GROUP_ID
      description: The group ID of the builder image user.
      default: "1000"
    - name: PROCESS_TYPE
      description: The default process type to set on the image.
      default: "web"
    - name: SOURCE_SUBPATH
      description: A subpath within the source input where the source to build is located.
      default: ""
    - name: SKIP_RESTORE
      description: Do not write layer metadata or restore cached layers
      default: "false"
    - name: RUN_IMAGE
      description: Reference to a run image to use
      default: ""

  resources:
    outputs:
      - name: image
        type: image

  workspaces:
    - name: source

  stepTemplate:
    env:
      - name: CNB_PLATFORM_API
        value: "0.3"
      - name: GOOGLE_FUNCTION_SIGNATURE_TYPE
        value: "http"
      - name: GOOGLE_FUNCTION_TARGET
        value: "HelloWorld" 

  steps:
    - name: prepare
      image: docker.io/library/alpine:3.12@sha256:d7342993700f8cd7aba8496c2d0e57be0666e80b4c441925fc6f9361fa81d10e #tag: 3.12
      imagePullPolicy: Always
      command: ["/bin/sh"]
      args:
        - "-c"
        - |-
          chown -R "$(params.USER_ID):$(params.GROUP_ID)" "/tekton/home" &&
          chown -R "$(params.USER_ID):$(params.GROUP_ID)" "/layers" &&
          chown -R "$(params.USER_ID):$(params.GROUP_ID)" "/cache" &&
          chown -R "$(params.USER_ID):$(params.GROUP_ID)" "$(workspaces.source.path)"
      volumeMounts:
        - name: layers-dir
          mountPath: /layers
        - name: $(params.CACHE)
          mountPath: /cache
      securityContext:
        privileged: true

    - name: create
      image: $(params.BUILDER_IMAGE)
      imagePullPolicy: Always
      command: ["/cnb/lifecycle/creator"]
      args:
        - "-app=$(workspaces.source.path)/$(params.SOURCE_SUBPATH)"
        - "-cache-dir=/cache"
        - "-cache-image=$(params.CACHE_IMAGE)"
        - "-gid=$(params.GROUP_ID)"
        - "-layers=/layers"
        - "-platform=/platform"
        - "-process-type=$(params.PROCESS_TYPE)"
        - "-skip-restore=$(params.SKIP_RESTORE)"
        - "-previous-image=$(resources.outputs.image.url)"
        - "-run-image=$(params.RUN_IMAGE)"
        - "-uid=$(params.USER_ID)"
        - "$(resources.outputs.image.url)"
      volumeMounts:
        - name: layers-dir
          mountPath: /layers
        - name: $(params.CACHE)
          mountPath: /cache
        - name: $(params.PLATFORM_DIR)
          mountPath: /platform

  volumes:
    - name: empty-dir
      emptyDir: {}
    - name: layers-dir
      emptyDir: {}
---
apiVersion: v1
kind: Secret
metadata:
    name: basic-user-pass
    annotations:
        tekton.dev/docker-0: "https://index.docker.io/v1/"
type: kubernetes.io/basic-auth
stringData:
    username: xxx 
    password: xxx
---
apiVersion: v1
kind: ServiceAccount
metadata:
    name: buildpacks-service-account
secrets:
    - name: basic-user-pass
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: buildpacks-source-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: buildpacks-cache-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: buildpacks-app-image 
spec:
  type: image
  params:
    - name: url
      value: benjaminhuo/sample-go-func:latest #This defines the name of output image
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: buildpacks-test-pipeline
spec:
  workspaces:
  - name: shared-workspace
  resources:
  - name: build-image
    type: image
  tasks:
  - name: fetch-repository # This task fetches a repository from github, using the `git-clone` task we installed
    taskRef:
      name: git-clone
    workspaces:
    - name: output
      workspace: shared-workspace
    params:
    - name: url
      value: https://github.com/OpenFunction/function-samples.git
    - name: subdirectory
      value: ""
    - name: deleteExisting
      value: "true"
  - name: buildpacks # This task uses the buildpacks task to build the application
    taskRef:
      name: buildpacks
    runAfter:
    - fetch-repository
    workspaces:
    - name: source
      workspace: shared-workspace
    params:
    - name: SOURCE_SUBPATH
      value: 'hello-world-go' # This is the path within our samples repo we want to build
    - name: BUILDER_IMAGE
      value: 'gcr.io/buildpacks/builder:v1' # This is the builder we want the task to use
    - name: CACHE
      value: buildpacks-cache
    resources:
      outputs:
      - name: image
        resource: build-image
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: buildpacks-test-pipeline-run
spec:
  serviceAccountName: buildpacks-service-account # Only needed if you set up authorization
  pipelineRef:
    name: buildpacks-test-pipeline
  workspaces:
  - name: shared-workspace
    persistentvolumeclaim:
      claimName: buildpacks-source-pvc
  resources:
  - name: build-image
    resourceRef:
      name: buildpacks-app-image
  podTemplate:
    volumes:
    - name: buildpacks-cache
      persistentVolumeClaim:
        claimName: buildpacks-cache-pvc
natalieparellano commented 3 years ago

@benjaminhuo I believe pack is processing the --env flag differently from the Tekton task env, which could explain the failure to detect.

pack build --env MY_VAR=MY_VAL will create a /platform/env/MY_VAR file with contents MY_VAL in the builder where the lifecycle is running. So to achieve parity in Tekton, you'd need to mount a platform directory with /platform/env/GOOGLE_FUNCTION_SIGNATURE_TYPE and /platform/env/GOOGLE_FUNCTION_TARGET files.

There are two sections in the example taskrun (https://github.com/tektoncd/catalog/blob/master/task/buildpacks/0.2/README.md) that you'd want to uncomment to provide a platform directory (see # Uncomment the lines below to provide a platform directory).

Could you give it a try and let us know if it resolves the issue?

benjaminhuo commented 3 years ago

https://github.com/tektoncd/catalog/blob/master/task/buildpacks/0.2/README.md

Thanks very much @natalieparellano , that sounds like the root cause. I'll give it a try and let you know!

benjaminhuo commented 3 years ago

@natalieparellano Finally it works after adding platform settings as you suggested, thanks!

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: function-env
data:
  GOOGLE_FUNCTION_TARGET: HelloWorld
  GOOGLE_FUNCTION_SIGNATURE_TYPE: http
---
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
  name: buildpacks-test-pipeline
spec:
  workspaces:
  - name: shared-workspace
  resources:
  - name: build-image
    type: image
  tasks:
  - name: fetch-repository # This task fetches a repository from github, using the `git-clone` task we installed
    taskRef:
      name: git-clone
    workspaces:
    - name: output
      workspace: shared-workspace
    params:
    - name: url
      value: https://github.com/OpenFunction/function-samples.git
    - name: subdirectory
      value: ""
    - name: deleteExisting
      value: "true"
  - name: buildpacks # This task uses the buildpacks task to build the application
    taskRef:
      name: buildpacks
    runAfter:
    - fetch-repository
    workspaces:
    - name: source
      workspace: shared-workspace
    params:
    - name: SOURCE_SUBPATH
      value: 'hello-world-go' # This is the path within our samples repo we want to build
    - name: BUILDER_IMAGE
      value: 'gcr.io/buildpacks/builder:v1' # This is the builder we want the task to use
    - name: CACHE
      value: buildpacks-cache
    - name: PLATFORM_DIR
      value: platform-dir
    resources:
      outputs:
      - name: image
        resource: build-image
---
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
  name: buildpacks-test-pipeline-run
spec:
  serviceAccountName: buildpacks-service-account # Only needed if you set up authorization
  pipelineRef:
    name: buildpacks-test-pipeline
  workspaces:
  - name: shared-workspace
    persistentvolumeclaim:
      claimName: buildpacks-source-pvc
  resources:
  - name: build-image
    resourceRef:
      name: buildpacks-app-image
  podTemplate:
    volumes:
    - name: buildpacks-cache
      persistentVolumeClaim:
        claimName: buildpacks-cache-pvc
    - name: platform-dir
      configMap:
        name: function-env
        items:
        - key: GOOGLE_FUNCTION_TARGET
          path: env/GOOGLE_FUNCTION_TARGET
        - key: GOOGLE_FUNCTION_SIGNATURE_TYPE
          path: env/GOOGLE_FUNCTION_SIGNATURE_TYPE 
---
apiVersion: tekton.dev/v1alpha1
kind: PipelineResource
metadata:
  name: buildpacks-app-image 
spec:
  type: image
  params:
    - name: url
      value: benjaminhuo/sample-go-func:latest #This defines the name of output image
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: git-clone
  labels:
    app.kubernetes.io/version: "0.2"
  annotations:
    tekton.dev/pipelines.minVersion: "0.12.1"
    tekton.dev/tags: git
    tekton.dev/displayName: "git clone"
spec:
  description: >-
    These Tasks are Git tasks to work with repositories used by other tasks
    in your Pipeline.

    The git-clone Task will clone a repo from the provided url into the
    output Workspace. By default the repo will be cloned into the root of
    your Workspace. You can clone into a subdirectory by setting this Task's
    subdirectory param.

  workspaces:
    - name: output
      description: The git repo will be cloned onto the volume backing this workspace
  params:
    - name: url
      description: git url to clone
      type: string
    - name: revision
      description: git revision to checkout (branch, tag, sha, ref…)
      type: string
      default: ""
    - name: refspec
      description: (optional) git refspec to fetch before checking out revision
      default: ""
    - name: submodules
      description: defines if the resource should initialize and fetch the submodules
      type: string
      default: "true"
    - name: depth
      description: performs a shallow clone where only the most recent commit(s) will be fetched
      type: string
      default: "1"
    - name: sslVerify
      description: defines if http.sslVerify should be set to true or false in the global git config
      type: string
      default: "true"
    - name: subdirectory
      description: subdirectory inside the "output" workspace to clone the git repo into
      type: string
      default: ""
    - name: deleteExisting
      description: clean out the contents of the repo's destination directory (if it already exists) before trying to clone the repo there
      type: string
      default: "true"
    - name: httpProxy
      description: git HTTP proxy server for non-SSL requests
      type: string
      default: ""
    - name: httpsProxy
      description: git HTTPS proxy server for SSL requests
      type: string
      default: ""
    - name: noProxy
      description: git no proxy - opt out of proxying HTTP/HTTPS requests
      type: string
      default: ""
    - name: verbose
      description: log the commands used during execution
      type: string
      default: "true"
    - name: gitInitImage
      description: the image used where the git-init binary is
      type: string
      default: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.18.1"
  results:
    - name: commit
      description: The precise commit SHA that was fetched by this Task
    - name: url
      description: The precise URL that was fetched by this Task
  steps:
    - name: clone
      image: $(params.gitInitImage)
      script: |
        #!/bin/sh
        set -eu -o pipefail

        if [[ "$(params.verbose)" == "true" ]] ; then
          set -x
        fi

        CHECKOUT_DIR="$(workspaces.output.path)/$(params.subdirectory)"

        cleandir() {
          # Delete any existing contents of the repo directory if it exists.
          #
          # We don't just "rm -rf $CHECKOUT_DIR" because $CHECKOUT_DIR might be "/"
          # or the root of a mounted volume.
          if [[ -d "$CHECKOUT_DIR" ]] ; then
            # Delete non-hidden files and directories
            rm -rf "$CHECKOUT_DIR"/*
            # Delete files and directories starting with . but excluding ..
            rm -rf "$CHECKOUT_DIR"/.[!.]*
            # Delete files and directories starting with .. plus any other character
            rm -rf "$CHECKOUT_DIR"/..?*
          fi
        }

        if [[ "$(params.deleteExisting)" == "true" ]] ; then
          cleandir
        fi

        test -z "$(params.httpProxy)" || export HTTP_PROXY=$(params.httpProxy)
        test -z "$(params.httpsProxy)" || export HTTPS_PROXY=$(params.httpsProxy)
        test -z "$(params.noProxy)" || export NO_PROXY=$(params.noProxy)

        /ko-app/git-init \
          -url "$(params.url)" \
          -revision "$(params.revision)" \
          -refspec "$(params.refspec)" \
          -path "$CHECKOUT_DIR" \
          -sslVerify="$(params.sslVerify)" \
          -submodules="$(params.submodules)" \
          -depth "$(params.depth)"
        cd "$CHECKOUT_DIR"
        RESULT_SHA="$(git rev-parse HEAD)"
        EXIT_CODE="$?"
        if [ "$EXIT_CODE" != 0 ] ; then
          exit $EXIT_CODE
        fi
        # ensure we don't add a trailing newline to the result
        echo -n "$RESULT_SHA" > $(results.commit.path)
        echo -n "$(params.url)" > $(results.url.path)
---
apiVersion: tekton.dev/v1beta1
kind: Task
metadata:
  name: buildpacks
  labels:
    app.kubernetes.io/version: "0.2"
  annotations:
    tekton.dev/pipelines.minVersion: "0.12.1"
    tekton.dev/tags: image-build
    tekton.dev/displayName: "buildpacks"
spec:
  description: >-
    The Buildpacks task builds source into a container image and pushes it to a registry,
    using Cloud Native Buildpacks.
    Cloud Native Buildpacks are pluggable, modular tools that transform application source code
    into OCI images. They replace Dockerfiles in the app development lifecycle, and allow for swift
    rebasing of images, and give modular control over images through the use of builders, among other
    benefits. This command uses a builder to construct the image, and pushes it to the registry provided.
  params:
    - name: BUILDER_IMAGE
      description: The image on which builds will run (must include lifecycle and compatible buildpacks).
    - name: CACHE
      description: The name of the persistent app cache volume.
      default: empty-dir
    - name: CACHE_IMAGE
      description: The name of the persistent app cache image.
      default: ""
    - name: PLATFORM_DIR
      description: The name of the platform directory.
      default: empty-dir
    - name: USER_ID
      description: The user ID of the builder image user.
      default: "1000"
    - name: GROUP_ID
      description: The group ID of the builder image user.
      default: "1000"
    - name: PROCESS_TYPE
      description: The default process type to set on the image.
      default: "web"
    - name: SOURCE_SUBPATH
      description: A subpath within the `source` input where the source to build is located.
      default: ""
    - name: SKIP_RESTORE
      description: Do not write layer metadata or restore cached layers
      default: "false"
    - name: RUN_IMAGE
      description: Reference to a run image to use
      default: ""

  resources:
    outputs:
      - name: image
        type: image

  workspaces:
    - name: source

  stepTemplate:
    env:
      - name: CNB_PLATFORM_API
        value: "0.3"

  steps:
    - name: prepare
      # Latest alpine as of Oct 22, 2020
      image: docker.io/alpine@sha256:203ee936961c0f491f72ce9d3c3c67d9440cdb1d61b9783cf340baa09308ffc1
      imagePullPolicy: Always
      command: ["/bin/sh"]
      args:
        - "-c"
        - |-
          chown -R "$(params.USER_ID):$(params.GROUP_ID)" "/tekton/home" &&
          chown -R "$(params.USER_ID):$(params.GROUP_ID)" "/layers" &&
          chown -R "$(params.USER_ID):$(params.GROUP_ID)" "/cache" &&
          chown -R "$(params.USER_ID):$(params.GROUP_ID)" "$(workspaces.source.path)"
      volumeMounts:
        - name: layers-dir
          mountPath: /layers
        - name: $(params.CACHE)
          mountPath: /cache

    - name: create
      image: $(params.BUILDER_IMAGE)
      imagePullPolicy: Always
      command: ["/cnb/lifecycle/creator"]
      args:
        - "-app=$(workspaces.source.path)/$(params.SOURCE_SUBPATH)"
        - "-cache-dir=/cache"
        - "-cache-image=$(params.CACHE_IMAGE)"
        - "-gid=$(params.GROUP_ID)"
        - "-layers=/layers"
        - "-platform=/platform"
        - "-process-type=$(params.PROCESS_TYPE)"
        - "-skip-restore=$(params.SKIP_RESTORE)"
        - "-previous-image=$(resources.outputs.image.url)"
        - "-run-image=$(params.RUN_IMAGE)"
        - "-uid=$(params.USER_ID)"
        - "$(resources.outputs.image.url)"
      volumeMounts:
        - name: layers-dir
          mountPath: /layers
        - name: $(params.CACHE)
          mountPath: /cache
        - name: $(params.PLATFORM_DIR)
          mountPath: /platform
      securityContext:
        runAsUser: 1000
        runAsGroup: 1000

  volumes:
    - name: empty-dir
      emptyDir: {}
    - name: layers-dir
      emptyDir: {}
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: buildpacks-source-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: buildpacks-cache-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 500Mi
---
apiVersion: v1
kind: Secret
metadata:
    name: basic-user-pass
    annotations:
        tekton.dev/docker-0: "https://index.docker.io/v1/"
type: kubernetes.io/basic-auth
stringData:
    username: xxx 
    password: xxx
---
apiVersion: v1
kind: ServiceAccount
metadata:
    name: buildpacks-service-account
secrets:
    - name: basic-user-pass