version: 3

# We have multiple parallel tasks that run for a long time. Prefix their output with the task name so we can understand
# what task is writing.
output: prefixed

# Variables that are shared across tasks.
vars:
  GO_VERSION:
    sh: sed -n 's/^toolchain go//p' go.mod | grep . || sed -n 's/^go //p' go.mod
  # renovate: datasource=docker depName=kindest/node versioning=semver
  E2E_KUBERNETES_VERSION: v1.36.1
  E2E_CLUSTER_NAME: barman-cloud-plugin-e2e-{{.E2E_KUBERNETES_VERSION}}
  REGISTRY_NETWORK: barman-cloud-plugin
  REGISTRY_NAME: registry.barman-cloud-plugin
  REGISTRY_PORT: 5000
  DAGGER_ENGINE_CONTAINER_NAME: e2e-dagger-engine

tasks:
  lint:
    desc: Run golangci-lint
    env:
      # renovate: datasource=git-refs depName=golangci-lint lookupName=https://github.com/sagikazarmark/daggerverse currentValue=main
      DAGGER_GOLANGCI_LINT_SHA: ff27cd50f6b4eed2e3753c520632cd6099e1ce52
      # renovate: datasource=docker depName=golangci/golangci-lint versioning=semver
      GOLANGCI_LINT_VERSION: v2.12.2
    cmds:
      - >
        GITHUB_REF= dagger -sc "github.com/sagikazarmark/daggerverse/golangci-lint@${DAGGER_GOLANGCI_LINT_SHA}
        --version ${GOLANGCI_LINT_VERSION} |
        run . --config .golangci.yml | stdout"
    sources:
      - ./**/*.go

  wordlist-ordered:
    desc: Order the word list file
    cmds:
      - LANG=C LC_ALL=C sort .wordlist.txt > .wordlist.txt.new
      - mv -f .wordlist.txt.new .wordlist.txt
    sources:
      - .wordlist.txt

  spellcheck:
    desc: Run spellcheck
    deps:
      - wordlist-ordered
    env:
      # renovate: datasource=git-refs depName=spellcheck lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
      DAGGER_SPELLCHECK_SHA: f7187c307f2ba79290efbfff5ce436b956162c53
    cmds:
      - >
        GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/spellcheck@${DAGGER_SPELLCHECK_SHA}
        spellcheck --source . with-exec --use-entrypoint --args="" stdout
    sources:
      - ./**/*.md
      - .spellcheck.yaml
      - .wordlist.txt

  commitlint:
    desc: Check for conventional commits
    env:
      # renovate: datasource=git-refs depName=commitlint lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
      DAGGER_COMMITLINT_SHA: f7187c307f2ba79290efbfff5ce436b956162c53
    cmds:
      - >
        GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/commitlint@${DAGGER_COMMITLINT_SHA}
        lint --source . --args "--from=origin/main" stdout

  uncommitted:
    desc: Check for uncommitted changes
    deps:
      - manifest-main
      - apidoc
      - wordlist-ordered
    env:
      # renovate: datasource=git-refs depName=uncommitted lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
      DAGGER_UNCOMMITTED_SHA: f7187c307f2ba79290efbfff5ce436b956162c53
    cmds:
      - GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/uncommitted@${DAGGER_UNCOMMITTED_SHA} check-uncommitted --source . stdout
    sources:
      - ./**

  apidoc:
    desc: Update the API Reference section of the documentation
    deps:
      - controller-gen
    env:
      # renovate: datasource=git-refs depName=crd-gen-refs lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
      DAGGER_CRDGENREF_SHA: f7187c307f2ba79290efbfff5ce436b956162c53
      # renovate: datasource=go depName=github.com/elastic/crd-ref-docs
      CRDREFDOCS_VERSION: v0.3.0
    cmds:
      - >
        GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/crd-ref-docs@${DAGGER_CRDGENREF_SHA}
        --version ${CRDREFDOCS_VERSION}
        generate
        --src .
        --source-path api/v1
        --config-file hack/crd-gen-refs/config.yaml
        --renderer markdown
        --templates-dir hack/crd-gen-refs/markdown
        file --path out.md
        export --path web/docs/plugin-barman-cloud.v1.md
    sources:
      - ./api/**/*.go
      - ./hack/docs/crd-gen-refs/**/*
      - ./Taskfile.yml

  docusaurus-build-test:
    desc: Check that the documentation builds
    deps:
    - apidoc
    env:
      # renovate: datasource=git-refs depName=docusaurus lookupName=https://github.com/levlaz/daggerverse currentValue=main
      DAGGER_DOCUSAURUS_SHA: 93f57fccbd5afd22fa917107ab7697f3e7db0e5a
    cmds:
      - GITHUB_REF= dagger -s call -m github.com/levlaz/daggerverse/docusaurus@${DAGGER_DOCUSAURUS_SHA}
        --src web --yarn build
    src:
      - ./web/**/*

  docusaurus-version-is-aligned:
    desc: Verify that a documentation version exists for the current version of the plugin
    cmds:
      - $(GITHUB_REF= dagger -s call -m dagger/check-doc-version has-version-documentation --src .)
    src:
      - .release-please-manifest.json
      - ./web/versions.json

  go-test:
    desc: Run go test
    env:
      # renovate: datasource=git-refs depname=kubernetes packageName=https://github.com/kubernetes/kubernetes versioning=semver
      K8S_VERSION: 1.31.0
      # renovate: datasource=git-refs depName=controller-runtime packageName=https://github.com/kubernetes-sigs/controller-runtime versioning=semver
      SETUP_ENVTEST_VERSION: 0.24.1
    cmds:
      - >
        GITHUB_REF= dagger -s call -m ./dagger/gotest
        --go-version {{.GO_VERSION}}
        --kube-version ${K8S_VERSION}
        --setup-envtest-version ${SETUP_ENVTEST_VERSION}
        unit-test --src .
        stdout
    sources:
      - ./**/*.go

  generate-certs:
    desc: Generate certificates for the local registry
    run: once
    cmds:
      - > 
          mkdir -p certs &&
          docker volume create certs &&
          docker run -v certs:/certs -w /certs --name certs --entrypoint=/bin/sh alpine/openssl -c '
          openssl genrsa -out ca-key.pem 4096 &&
          openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem \
              -subj "/O=CloudNativePG/OU=Barman Cloud Plugin Testing" &&
          openssl genrsa -out server-key.pem 4096 &&
          openssl req -subj "/CN={{ .REGISTRY_NAME }}" -sha256 -new -key server-key.pem -out server.csr &&
          echo subjectAltName = DNS:{{ .REGISTRY_NAME }},IP:127.0.0.1 >> extfile.cnf &&
          echo extendedKeyUsage = serverAuth >> extfile.cnf &&
          openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
              -CAcreateserial -out server-cert.pem -extfile extfile.cnf'
          docker cp certs:/certs/ca.pem certs/ca.pem &&
          docker rm certs
    status:
      - docker volume inspect certs
      - test -f certs/ca.pem

  start-build-network:
    desc: Create a docker network for image building used by the dagger engine and the registry
    run: once
    cmds:
      - docker network create {{ .REGISTRY_NETWORK}}
    status:
      - docker network inspect {{ .REGISTRY_NETWORK }}

  start-registry:
    desc: Start a container registry
    run: once
    deps:
      - generate-certs
      - start-build-network
    env:
      # renovate: datasource=docker depName=registry versioning=semver
      REGISTRY_VERSION: 2
    cmds:
      - >
        docker run -d --name {{ .REGISTRY_NAME }}
        -p {{ .REGISTRY_PORT }}:5000
        --network {{ .REGISTRY_NETWORK }}
        -v certs:/certs
        -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server-cert.pem -e REGISTRY_HTTP_TLS_KEY=/certs/server-key.pem
        registry:${REGISTRY_VERSION}
    status:
      - \[ "$(docker inspect -f {{`'{{.State.Running}}'`}} "{{ .REGISTRY_NAME }}" 2> /dev/null )" == 'true' \]


  # Start a dagger engine that mounts the CA certificate for the local registry.
  start-dagger-engine-for-local-builds:
    desc: Start a dagger engine mounting the CA
    run: once
    deps:
      - generate-certs
      - start-build-network
    vars:
      # renovate: datasource=github-tags depName=dagger/dagger versioning=semver
      DAGGER_VERSION: 0.21.7
      DAGGER_ENGINE_IMAGE: registry.dagger.io/engine:v{{ .DAGGER_VERSION }}
    cmds:
      - >
        docker run -d -v /var/lib/dagger --name "{{ .DAGGER_ENGINE_CONTAINER_NAME }}"
        --network={{ .REGISTRY_NETWORK }}
        -v certs:/usr/local/share/ca-certificates/
        --privileged {{ .DAGGER_ENGINE_IMAGE }}
    status:
      - \[ "$(docker inspect -f {{`'{{.State.Running}}'`}} "{{ .DAGGER_ENGINE_CONTAINER_NAME }}" 2> /dev/null )" == 'true' \]

  # We build an image and push it to a local registry.
  # The name is always `plugin-barman-cloud:testing`.
  build-plugin-image:
    desc: Build the operator container image for the plugin
    deps:
      - start-registry
      - start-dagger-engine-for-local-builds
    env:
      # renovate: datasource=git-refs depName=docker lookupName=https://github.com/purpleclay/daggerverse currentValue=main
      DAGGER_DOCKER_SHA: ee12c1a4a2630e194ec20c5a9959183e3a78c192
      _EXPERIMENTAL_DAGGER_RUNNER_HOST: docker-container://{{ .DAGGER_ENGINE_CONTAINER_NAME }}
    cmds:
      - >
        GITHUB_REF= dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
        build --dir . --file containers/Dockerfile.plugin --args GO_VERSION={{.GO_VERSION}} --platform linux/amd64
        publish --ref {{ .REGISTRY_NAME }}:{{ .REGISTRY_PORT }}/plugin-barman-cloud --tags testing

  # We build an image and push it to a local registry.
  # The name is always `sidecar-barman-cloud:testing`.
  build-sidecar-image:
    desc: Build the sidecar container image for the plugin
    deps:
      - start-registry
      - start-dagger-engine-for-local-builds
    env:
      # renovate: datasource=git-refs depName=docker lookupName=https://github.com/purpleclay/daggerverse currentValue=main
      DAGGER_DOCKER_SHA: ee12c1a4a2630e194ec20c5a9959183e3a78c192
      _EXPERIMENTAL_DAGGER_RUNNER_HOST: docker-container://{{ .DAGGER_ENGINE_CONTAINER_NAME }}
    cmds:
      - >
        GITHUB_REF= dagger -s call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
        build --dir . --file containers/Dockerfile.sidecar --args GO_VERSION={{.GO_VERSION}} --platform linux/amd64
        publish --ref {{ .REGISTRY_NAME }}:{{ .REGISTRY_PORT }}/sidecar-barman-cloud --tags testing

  build-images:
    desc: Build the container images for the plugin
    deps:
      - build-plugin-image
      - build-sidecar-image

  # Install kind if not at the expected version.
  install-kind:
    desc: Install kind
    run: once
    vars:
      # renovate: datasource=git-refs depName=kind lookupName=https://github.com/kubernetes-sigs/kind versioning=semver
      KIND_VERSION: v0.32.0
    cmds:
      - go install sigs.k8s.io/kind@{{.KIND_VERSION}}
      - kind version | grep -q {{.KIND_VERSION}}
    status:
        - kind version | grep -q {{.KIND_VERSION}}

  start-kind-cluster:
    desc: Start a kind cluster
    deps:
      - install-kind
      - start-build-network
      - generate-certs
    run: once
    cmds:
      - >
        kind create cluster --name {{ .E2E_CLUSTER_NAME }}
        --image kindest/node:{{ .E2E_KUBERNETES_VERSION }}
        --config hack/kind-config.yaml
        --wait 5m
      - >
        for node in $(kind get nodes --name {{ .E2E_CLUSTER_NAME }} ); do
          docker network connect {{ .REGISTRY_NETWORK }} $node;
          docker exec $node sh -c "update-ca-certificates";
        done
    status:
      - kind get clusters | grep -q {{ .E2E_CLUSTER_NAME }}

  # TODO: see if it is possible to daggerize this. It will have to manage docker to make kind work.
  # TODO: add a task to clean up the kind cluster for new test runs.
  # Run the e2e tests. This task will start a kind cluster, deploy the plugin, and run the tests.
  # Running the e2e tests requires:
  # * The registry to have a valid TLS certificate.
  # * The registry to be in the same network of the dagger-engine.
  # * The dagger-engine to mount the CA.
  # * The kind cluster to mount the CA.
  e2e-external-kind:
    desc: Run e2e tests in a local kind cluster
    deps:
      - build-images
      - start-kind-cluster
    vars:
      KUBECONFIG_PATH:
        sh: mktemp -t kubeconfig-XXXXX
    env:
      _EXPERIMENTAL_DAGGER_RUNNER_HOST: docker-container://{{ .DAGGER_ENGINE_CONTAINER_NAME }}
    cmds:
      - kind get kubeconfig --internal --name {{ .E2E_CLUSTER_NAME }} > {{ .KUBECONFIG_PATH }}
      - >
        GITHUB_REF= dagger call -m  dagger/e2e/ run
        --source .
        --kubeconfig {{.KUBECONFIG_PATH}}
        --go-version {{.GO_VERSION}}

  e2e-ephemeral:
    desc: Run e2e tests in an ephemeral k3s cluster
    deps:
      - build-images
    env:
      _EXPERIMENTAL_DAGGER_RUNNER_HOST: docker-container://{{ .DAGGER_ENGINE_CONTAINER_NAME }}
    cmds:
      - >
        GITHUB_REF= dagger call -m  dagger/e2e/ run-ephemeral
        --source .
        --ca certs/ca.pem
        --registry {{.REGISTRY_NAME}}:{{.REGISTRY_PORT}}
        --go-version {{.GO_VERSION}}

  ci:
    desc: Run the CI pipeline
    deps:
      - spellcheck
      - commitlint
      - uncommitted
      - lint
      - go-test
      - e2e-ephemeral
      - docusaurus-build-test
      - docusaurus-version-is-aligned

  publish:
    desc: Build and publish a container image for the plugin
    requires:
      # We expect this to run in a GitHub workflow, so we put a few GitHub-specific vars here
      # to prevent running this task locally by accident.
      vars:
        - CI
        - GITHUB_REPOSITORY
        - GITHUB_REF
        - GITHUB_REF_NAME
        - REGISTRY_USER
        - REGISTRY_PASSWORD
    vars:
      PLUGIN_IMAGE_NAME: ghcr.io/{{.GITHUB_REPOSITORY}}{{if not (hasPrefix "refs/tags/v" .GITHUB_REF)}}-testing{{end}}
      SIDECAR_IMAGE_NAME: ghcr.io/{{.GITHUB_REPOSITORY}}-sidecar{{if not (hasPrefix "refs/tags/v" .GITHUB_REF)}}-testing{{end}}
      # remove /merge suffix from the branch name. This is a workaround for the GitHub workflow on PRs,
      # where the branch name is suffixed with /merge. Prepend pr- to the branch name on PRs.
      # Any remaining "/" (e.g. from namespaced branches like "dev/foo") is replaced with "-" since
      # "/" is not a valid character in a Docker tag.
      IMAGE_VERSION: '{{replace "/" "-" (regexReplaceAll "(\\d+)/merge" .GITHUB_REF_NAME "pr-${1}")}}'
    env:
      # renovate: datasource=git-refs depName=docker lookupName=https://github.com/purpleclay/daggerverse currentValue=main
      DAGGER_DOCKER_SHA: ee12c1a4a2630e194ec20c5a9959183e3a78c192
    cmds:
      - >
        GITHUB_REF= dagger call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
        --registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD
        build --dir . --file containers/Dockerfile.plugin --args GO_VERSION={{.GO_VERSION}} --platform linux/amd64 --platform linux/arm64
        publish --ref {{.PLUGIN_IMAGE_NAME}} --tags {{.IMAGE_VERSION}}
      - >
        GITHUB_REF= dagger call -m github.com/purpleclay/daggerverse/docker@${DAGGER_DOCKER_SHA}
        --registry ghcr.io --username $REGISTRY_USER --password env:REGISTRY_PASSWORD
        build --dir . --file containers/Dockerfile.sidecar --args GO_VERSION={{.GO_VERSION}} --platform linux/amd64 --platform linux/arm64
        publish --ref {{.SIDECAR_IMAGE_NAME}} --tags {{.IMAGE_VERSION}}

  controller-gen:
    desc: Run controller-gen
    run: once
    env:
      # renovate: datasource=git-refs depName=controller-gen lookupName=https://github.com/cloudnative-pg/daggerverse currentValue=main
      DAGGER_CONTROLLER_GEN_SHA: f7187c307f2ba79290efbfff5ce436b956162c53
    cmds:
      - >
        GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/controller-gen@${DAGGER_CONTROLLER_GEN_SHA}
        controller-gen --source . --args object:headerFile=hack/boilerplate.go.txt --args paths=./api/...
        file --path api/v1/zz_generated.deepcopy.go export --path api/v1/zz_generated.deepcopy.go
      - >
        GITHUB_REF= dagger -s call -m github.com/cloudnative-pg/daggerverse/controller-gen@${DAGGER_CONTROLLER_GEN_SHA}
        controller-gen --source . --args rbac:roleName=plugin-barman-cloud --args crd --args webhook
        --args paths=./api/... --args paths=./internal/... --args output:crd:artifacts:config=config/crd/bases
        directory --path config/
        filter --include crd/bases/,rbac/
        export --path config/
    sources:
      - ./api/**/*.go
      - ./internal/**/*.go
    generates:
      - ./api/v1/zz_generated.deepcopy.go
      - ./config/rbac/role.yaml
      - ./config/crd/bases/*.yaml

  manifest-main:
    deps:
      - controller-gen
    desc: Generate the manifest for the main branch
    vars:
      GITHUB_REPOSITORY: cloudnative-pg/plugin-barman-cloud
      GITHUB_REF: main
      GITHUB_REF_NAME: main
    cmds:
      - task: manifest-internal
        vars:
          GITHUB_REPOSITORY: '{{.GITHUB_REPOSITORY}}'
          GITHUB_REF: '{{.GITHUB_REF}}'
          GITHUB_REF_NAME: '{{.GITHUB_REF_NAME}}'

  manifest:
    desc: Generate the manifest to be uploaded to the release or as a workflow artifact
    deps:
      - controller-gen
    requires:
      # We expect this to run in a GitHub workflow, so we put a few GitHub-specific vars here
      # to prevent running this task locally by accident.
      vars:
        - CI
        - GITHUB_REPOSITORY
        - GITHUB_REF
        - GITHUB_REF_NAME
    cmds:
      - task: manifest-internal
        vars:
          GITHUB_REPOSITORY: '{{.GITHUB_REPOSITORY}}'
          GITHUB_REF: '{{.GITHUB_REF}}'
          GITHUB_REF_NAME: '{{.GITHUB_REF_NAME}}'

  manifest-internal:
    desc: Update the image in the Kustomization
    label: manifest-internal-{{.GITHUB_REF_NAME}}
    internal: true
    requires:
      vars:
        - GITHUB_REPOSITORY
        - GITHUB_REF
        - GITHUB_REF_NAME
    vars:
      PLUGIN_IMAGE_NAME: ghcr.io/{{.GITHUB_REPOSITORY}}{{if not (hasPrefix "refs/tags/v" .GITHUB_REF)}}-testing{{end}}
      SIDECAR_IMAGE_NAME: ghcr.io/{{.GITHUB_REPOSITORY}}-sidecar{{if not (hasPrefix "refs/tags/v" .GITHUB_REF)}}-testing{{end}}
      # remove /merge suffix from the branch name. This is a workaround for the GitHub workflow on PRs,
      # where the branch name is suffixed with /merge. Prepend pr- to the branch name on PRs.
      # Any remaining "/" (e.g. from namespaced branches like "dev/foo") is replaced with "-" since
      # "/" is not a valid character in a Docker tag.
      IMAGE_VERSION: '{{replace "/" "-" (regexReplaceAll "(\\d+)/merge" .GITHUB_REF_NAME "pr-${1}")}}'
    env:
      # renovate: datasource=git-refs depName=kustomize lookupName=https://github.com/sagikazarmark/daggerverse currentValue=main
      DAGGER_KUSTOMIZE_SHA: ff27cd50f6b4eed2e3753c520632cd6099e1ce52
    cmds:
      - >
        GITHUB_REF= dagger -s call -m https://github.com/sagikazarmark/daggerverse/kustomize@${DAGGER_KUSTOMIZE_SHA}
        edit --source . --dir kubernetes
        set image --image plugin-barman-cloud={{.PLUGIN_IMAGE_NAME}}:{{.IMAGE_VERSION}}
        set secret --secret plugin-barman-cloud --from-literal SIDECAR_IMAGE={{.SIDECAR_IMAGE_NAME}}:{{.IMAGE_VERSION}}
        directory directory --path kubernetes export --path manifest-build
      - >
        GITHUB_REF= dagger -s call -m github.com/sagikazarmark/daggerverse/kustomize@${DAGGER_KUSTOMIZE_SHA}
        build --source . --dir manifest-build export --path manifest.yaml
    sources:
      - ./config/**/*.yaml
      - ./kubernetes/**/*.yaml
    generates:
      - ./manifest.yaml

  upload-manifest-to-release:
    desc: Upload the manifest to the release
    requires:
      # We expect this to run in a GitHub workflow, so we put a few GitHub-specific vars here
      # to prevent running this task locally by accident.
      vars:
        - CI
        - GITHUB_REPOSITORY
        - GITHUB_REF
        - GITHUB_REF_NAME
        - GITHUB_TOKEN
    env:
      # renovate: datasource=git-refs depName=gh lookupName=https://github.com/sagikazarmark/daggerverse
      DAGGER_GH_SHA: ff27cd50f6b4eed2e3753c520632cd6099e1ce52
    preconditions:
      - sh: "[[ {{.GITHUB_REF}} =~ 'refs/tags/v.*' ]]"
        msg: not a tag, failing
    cmds:
        - >
            GITHUB_REF= dagger -s call -m github.com/sagikazarmark/daggerverse/gh@${DAGGER_GH_SHA}
            with-source --source .
            run --repo {{.GITHUB_REPOSITORY}} --token env:GITHUB_TOKEN
            --cmd "release upload {{.GITHUB_REF_NAME}} manifest.yaml"

  clean:
    desc: Remove autogenerated artifacts
    cmds:
      - rm -rf .task/
