diff --git a/meta/domain-devspaces/index.yaml b/meta/domain-devspaces/index.yaml index 0b66537..02f35b8 100644 --- a/meta/domain-devspaces/index.yaml +++ b/meta/domain-devspaces/index.yaml @@ -82,6 +82,16 @@ options: type: boolean type: object type: object + autoCD: + default: true + examples: + - true + type: boolean + autoCI: + default: true + examples: + - true + type: boolean backups: default: enable: false diff --git a/meta/domain-devspaces/organisations.tf b/meta/domain-devspaces/organisations.tf index ec2c2f6..5ac9a4f 100644 --- a/meta/domain-devspaces/organisations.tf +++ b/meta/domain-devspaces/organisations.tf @@ -30,6 +30,8 @@ resource "kubectl_manifest" "organisations" { "datasets" = [] "haveGitea" = var.haveGitea "haveTekton" = var.haveTekton + "autoCI" = var.autoCI + "autoCD" = var.autoCD }, { for k, v in local.sorted-organisations[count.index] : k => v if !contains(["name"], k) } ))} diff --git a/share/gitea-tekton-org/auto-cd.tf b/share/gitea-tekton-org/auto-cd.tf new file mode 100644 index 0000000..5ca6a0a --- /dev/null +++ b/share/gitea-tekton-org/auto-cd.tf @@ -0,0 +1,200 @@ +locals { + create-labels = merge(local.common-labels, { + "type" = "repo-new" + }) + activate-labels = merge(local.common-labels, { + "type" = "package-new" + }) + delete-labels = merge(local.common-labels, { + "type" = "repo-delete" + }) +} + +resource "kubectl_manifest" "cd-trigger-create" { + count = var.autoCD?1:0 + yaml_body = <<-EOF + apiVersion: triggers.tekton.dev/v1beta1 + kind: Trigger + metadata: + metadata: + name: "${var.instance}-${var.component}-auto-create" + namespace: "${var.namespace}" + labels: ${jsonencode(local.create-labels)} + spec: + bindings: + - name: gitrepositoryname + value: $(body.repository.name) + - name: deployurl + value: $(extensions.deploy-url) + template: + spec: + params: + - name: gitrepositoryname + description: The git repository name + - name: deployurl + description: The git url for the deploy repository + resourcetemplates: + - apiVersion: tekton.dev/v1beta1 + kind: PipelineRun + metadata: + generateName: $(tt.params.gitrepositoryname)-create- + annotations: + "mayfly.cloud.namecheap.com/expire": "336h" # 2 weeks + spec: + pipelineRef: + name: "${var.instance}-${var.component}-auto-create" + params: + - name: project-name + value: $(tt.params.gitrepositoryname) + - name: deploy-url + value: $(tt.params.deployurl) + workspaces: + - name: source + volumeClaimTemplate: + metadata: + annotations: + "mayfly.cloud.namecheap.com/expire": "2h" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + - name: ssh + secret: + secretName: ssh-credentials + items: + - key: "known_hosts" + path: "known_hosts" + - key: "ssh-privatekey" + path: "id_rsa" + - key: "ssh-publickey" + path: "id_rsa.pub" + EOF +} + +resource "kubectl_manifest" "cd-trigger-activate" { + count = var.autoCD?1:0 + yaml_body = <<-EOF + apiVersion: triggers.tekton.dev/v1beta1 + kind: Trigger + metadata: + metadata: + name: "${var.instance}-${var.component}-auto-activate" + namespace: "${var.namespace}" + labels: ${jsonencode(local.activate-labels)} + spec: + bindings: + - name: gitrepositoryname + value: $(body.repository.name) + - name: deployurl + value: $(extensions.deploy-url) + template: + spec: + params: + - name: gitrepositoryname + description: The git repository name + - name: deployurl + description: The git url for the deploy repository + resourcetemplates: + - apiVersion: tekton.dev/v1beta1 + kind: PipelineRun + metadata: + generateName: $(tt.params.gitrepositoryname)-activate- + annotations: + "mayfly.cloud.namecheap.com/expire": "336h" # 2 weeks + spec: + pipelineRef: + name: "${var.instance}-${var.component}-auto-activate" + params: + - name: project-name + value: $(tt.params.gitrepositoryname) + - name: deploy-url + value: $(tt.params.deployurl) + workspaces: + - name: source + volumeClaimTemplate: + metadata: + annotations: + "mayfly.cloud.namecheap.com/expire": "2h" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + - name: ssh + secret: + secretName: ssh-credentials + items: + - key: "known_hosts" + path: "known_hosts" + - key: "ssh-privatekey" + path: "id_rsa" + - key: "ssh-publickey" + path: "id_rsa.pub" + EOF +} + +resource "kubectl_manifest" "ci-trigger-delete" { + count = var.autoCD?1:0 + yaml_body = <<-EOF + apiVersion: triggers.tekton.dev/v1beta1 + kind: Trigger + metadata: + metadata: + name: "${var.instance}-${var.component}-auto-delete" + namespace: "${var.namespace}" + labels: ${jsonencode(local.delete-labels)} + spec: + bindings: + - name: gitrepositoryname + value: $(body.repository.name) + - name: deployurl + value: $(extensions.deploy-url) + template: + spec: + params: + - name: gitrepositoryname + description: The git repository name + - name: deployurl + description: The git url for the deploy repository + resourcetemplates: + - apiVersion: tekton.dev/v1beta1 + kind: PipelineRun + metadata: + generateName: $(tt.params.gitrepositoryname)-delete- + annotations: + "mayfly.cloud.namecheap.com/expire": "1440h" # 2 months + spec: + pipelineRef: + name: "${var.instance}-${var.component}-delete" + params: + - name: project-name + value: $(tt.params.gitrepositoryname) + - name: deploy-url + value: $(tt.params.deployurl) + workspaces: + - name: source + volumeClaimTemplate: + metadata: + annotations: + "mayfly.cloud.namecheap.com/expire": "2h" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + - name: ssh + secret: + secretName: ssh-credentials + items: + - key: "known_hosts" + path: "known_hosts" + - key: "ssh-privatekey" + path: "id_rsa" + - key: "ssh-publickey" + path: "id_rsa.pub" + EOF +} diff --git a/share/gitea-tekton-org/auto-ci.tf b/share/gitea-tekton-org/auto-ci.tf new file mode 100644 index 0000000..19575b6 --- /dev/null +++ b/share/gitea-tekton-org/auto-ci.tf @@ -0,0 +1,178 @@ +locals { + push-labels = merge(local.common-labels, { + "type" = "branch-push" + }) + tag-labels = merge(local.common-labels, { + "type" = "tag-new" + }) +} + +resource "kubectl_manifest" "ci-trigger-push" { + count = var.autoCI?1:0 + yaml_body = <<-EOF + apiVersion: triggers.tekton.dev/v1beta1 + kind: Trigger + metadata: + metadata: + name: "${var.instance}-${var.component}-auto-push" + namespace: "${var.namespace}" + labels: ${jsonencode(local.push-labels)} + spec: + bindings: + - name: artifactory-url + value: "$(extensions.artifactory-url)" + - name: project-name + value: "$(extensions.project-name)" + - name: project-path + value: "$(extensions.project-path)" + - name: git-repository-url + value: "$(extensions.git-repository-url)" + - name: git-revision + value: "$(extensions.git-revision)" + - name: git-default-branch + value: "$(extensions.git-default-branch)" + - name: branch-name + value: $(extensions.branch-name) + template: + spec: + params: + - name: artifactory-url + description: The url of the current artifactory + - name: project-name + description: The git repository name + - name: project-path + description: The path of the current project + - name: git-repository-url + description: The git repository url + - name: git-revision + description: The git revision + default: main + - name: git-default-branch + description: The git revision + default: main + - name: branch-name + description: The git branch + default: main + resourcetemplates: + - apiVersion: tekton.dev/v1beta1 + kind: PipelineRun + metadata: + generateName: $(tt.params.gitrepositoryname)-push-$(tt.params.gitbranch)- + annotations: + "mayfly.cloud.namecheap.com/expire": "336h" # 2 weeks + spec: + pipelineRef: + name: "auto-ci-push" + params: + - name: artifactory-url + value: $(tt.params.artifactory-url) + - name: project-name + value: $(tt.params.project-name) + - name: project-path + value: $(tt.params.project-path) + - name: git-url + value: $(tt.params.git-repository-url) + - name: git-revision + value: $(tt.params.git-revision) + - name: git-default-branch + value: $(tt.params.git-default-branch) + - name: branch-name + value: $(tt.params.branch-name) + workspaces: + - name: source + volumeClaimTemplate: + metadata: + annotations: + "mayfly.cloud.namecheap.com/expire": "2h" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + - name: ssh + secret: + secretName: ssh-credentials + items: + - key: "known_hosts" + path: "known_hosts" + - key: "ssh-privatekey" + path: "id_rsa" + - key: "ssh-publickey" + path: "id_rsa.pub" + EOF +} +resource "kubectl_manifest" "ci-trigger-tag" { + count = var.autoCI?1:0 + yaml_body = <<-EOF + apiVersion: triggers.tekton.dev/v1beta1 + kind: Trigger + metadata: + metadata: + name: "${var.instance}-${var.component}-auto-tag" + namespace: "${var.namespace}" + labels: ${jsonencode(local.tag-labels)} + spec: + bindings: + - name: artifactory-url + value: "$(extensions.artifactory-url)" + - name: project-name + value: "$(extensions.project-name)" + - name: project-path + value: "$(extensions.project-path)" + - name: git-repository-url + value: "$(extensions.git-repository-url)" + - name: tag-name + value: $(extensions.tag-name) + template: + spec: + params: + - name: artifactory-url + description: The url of the current artifactory + - name: project-name + description: The git repository name + - name: project-path + description: The path of the current project + - name: git-repository-url + description: The git repository url + - name: tag-name + description: The git tag + resourcetemplates: + - apiVersion: tekton.dev/v1beta1 + kind: PipelineRun + metadata: + generateName: $(tt.params.project-name)-tag-$(tt.params.tag-name)- + annotations: + "mayfly.cloud.namecheap.com/expire": "1440h" # 2 months + spec: + pipelineRef: + name: "auto-ci-tag" + params: + - name: git-revision + value: $(tt.params.gitrevision) + - name: git-url + value: $(tt.params.gitrepositoryurl) + workspaces: + - name: source + volumeClaimTemplate: + metadata: + annotations: + "mayfly.cloud.namecheap.com/expire": "2h" + spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + - name: ssh + secret: + secretName: ssh-credentials + items: + - key: "known_hosts" + path: "known_hosts" + - key: "ssh-privatekey" + path: "id_rsa" + - key: "ssh-publickey" + path: "id_rsa.pub" + EOF +} diff --git a/share/gitea-tekton-org/gitea_hook.tf b/share/gitea-tekton-org/gitea_hook.tf index 14efba9..140dcd1 100644 --- a/share/gitea-tekton-org/gitea_hook.tf +++ b/share/gitea-tekton-org/gitea_hook.tf @@ -30,8 +30,12 @@ resource "restapi_object" "gitea_org_hook" { authorization_header = "" events = [ "create", + "delete", "push", - "repository" + "pull_request", + "repository", + "release", + "package" ] config = { url = "http://el-${var.instance}-${var.component}.${var.namespace}.svc:8080" diff --git a/share/gitea-tekton-org/index.yaml b/share/gitea-tekton-org/index.yaml index 5642526..1d8fde8 100644 --- a/share/gitea-tekton-org/index.yaml +++ b/share/gitea-tekton-org/index.yaml @@ -6,6 +6,16 @@ metadata: name: gitea-tekton-org description: null options: + autoCD: + default: true + examples: + - true + type: boolean + autoCI: + default: true + examples: + - true + type: boolean domain: default: your-company examples: diff --git a/share/gitea-tekton-org/listener.tf b/share/gitea-tekton-org/listener.tf index dc1042c..d008c9d 100644 --- a/share/gitea-tekton-org/listener.tf +++ b/share/gitea-tekton-org/listener.tf @@ -25,10 +25,206 @@ resource "kubectl_manifest" "el" { params: - name: "filter" value: "body.action == 'created'" + - name: add-deploy-url + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "overlays" + value: + - key: deploy-url + expression: "body.repository.ssh_url.replace([body.repository.name,'.git'].join(), 'deploy.git')" triggerSelector: labelSelector: matchLabels: type: repo-new + - name: repo-delete + interceptors: + - name: event-repository + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "header.match('X-GitHub-Event', 'repository')" + - name: action-deleted + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "body.action == 'deleted'" + - name: add-deploy-url + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "overlays" + value: + - key: artifactory-url + expression: "body.repository.clone_url.split('/')[2]" + - key: deploy-url + expression: "body.repository.ssh_url.replace([body.repository.name,'.git'].join(), 'deploy.git')" + - key: project-name + expression: "body.repository.name" + - key: project-path + expression: "body.repository.full_name" + - key: git-repository-url + expression: "body.repository.ssh_url" + - key: git-default-branch + expression: "body.repository.default_branch" + triggerSelector: + labelSelector: + matchLabels: + type: repo-delete + - name: release-new + interceptors: + - name: event-release + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "header.match('X-GitHub-Event', 'release')" + - name: action-published + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "body.action == 'published'" + - name: "overlays" + value: + - key: artifactory-url + expression: "body.repository.clone_url.split('/')[2]" + - key: project-name + expression: "body.repository.name" + - key: project-path + expression: "body.repository.full_name" + - key: git-repository-url + expression: "body.repository.ssh_url" + - key: release-name + expression: "body.release.name" + - key: release-url + expression: "body.release.html_url" + - key: tag-name + expression: "body.release.tag_name" + triggerSelector: + labelSelector: + matchLabels: + type: release-new + - name: release-update + interceptors: + - name: event-release + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "header.match('X-GitHub-Event', 'release')" + - name: action-updated + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "body.action == 'updated'" + - name: "overlays" + value: + - key: artifactory-url + expression: "body.repository.clone_url.split('/')[2]" + - key: project-name + expression: "body.repository.name" + - key: project-path + expression: "body.repository.full_name" + - key: git-repository-url + expression: "body.repository.ssh_url" + - key: release-name + expression: "body.release.name" + - key: release-url + expression: "body.release.html_url" + - key: tag-name + expression: "body.release.tag_name" + triggerSelector: + labelSelector: + matchLabels: + type: release-update + - name: release-delete + interceptors: + - name: event-release + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "header.match('X-GitHub-Event', 'release')" + - name: action-deleted + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "body.action == 'deleted'" + - name: "overlays" + value: + - key: artifactory-url + expression: "body.repository.clone_url.split('/')[2]" + - key: project-name + expression: "body.repository.name" + - key: project-path + expression: "body.repository.full_name" + - key: git-repository-url + expression: "body.repository.ssh_url" + - key: release-name + expression: "body.release.name" + - key: release-url + expression: "body.release.html_url" + - key: tag-name + expression: "body.release.tag_name" + triggerSelector: + labelSelector: + matchLabels: + type: release-delete + - name: pr-open + interceptors: + - name: event-repository + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "header.match('X-GitHub-Event', 'pull_request')" + - name: action-created + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "body.action == 'opened'" + triggerSelector: + labelSelector: + matchLabels: + type: pr-open + - name: pr-close + interceptors: + - name: event-repository + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "header.match('X-GitHub-Event', 'pull_request')" + - name: action-deleted + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "body.action == 'closed'" + triggerSelector: + labelSelector: + matchLabels: + type: pr-close - name: tag-new interceptors: - name: event-create @@ -45,10 +241,53 @@ resource "kubectl_manifest" "el" { params: - name: "filter" value: "body.ref_type == 'tag'" + - name: "overlays" + value: + - key: artifactory-url + expression: "body.repository.clone_url.split('/')[2]" + - key: project-name + expression: "body.repository.name" + - key: project-path + expression: "body.repository.full_name" + - key: git-repository-url + expression: "body.repository.ssh_url" + - key: tag-name + expression: "body.ref" triggerSelector: labelSelector: matchLabels: - type: tag-new + - name: tag-delete + interceptors: + - name: event-delete + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "header.match('X-GitHub-Event', 'delete')" + - name: reftype-tag + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "body.ref_type == 'tag'" + - name: "overlays" + value: + - key: artifactory-url + expression: "body.repository.clone_url.split('/')[2]" + - key: project-name + expression: "body.repository.name" + - key: project-path + expression: "body.repository.full_name" + - key: git-repository-url + expression: "body.repository.ssh_url" + - key: tag-name + expression: "body.ref" + triggerSelector: + labelSelector: + matchLabels: + type: tag-delete - name: branch-new interceptors: - name: event-push @@ -65,6 +304,20 @@ resource "kubectl_manifest" "el" { params: - name: "filter" value: "body.ref_type == 'branch'" + - name: "overlays" + value: + - key: artifactory-url + expression: "body.repository.clone_url.split('/')[2]" + - key: project-name + expression: "body.repository.name" + - key: project-path + expression: "body.repository.full_name" + - key: git-repository-url + expression: "body.repository.ssh_url" + - key: git-default-branch + expression: "body.repository.default_branch" + - key: branch-name + expression: "body.ref" triggerSelector: labelSelector: matchLabels: @@ -78,10 +331,6 @@ resource "kubectl_manifest" "el" { params: - name: "filter" value: "header.match('X-GitHub-Event', 'push')" - - name: "overlays" - value: - - key: branch_name - expression: "body.ref.split('/')[2]" - name: ref-heads ref: kind: ClusterInterceptor @@ -89,9 +338,71 @@ resource "kubectl_manifest" "el" { params: - name: "filter" value: "body.ref.split('/')[1] == 'heads'" + - name: "overlays" + value: + - key: artifactory-url + expression: "body.repository.clone_url.split('/')[2]" + - key: project-name + expression: "body.repository.name" + - key: project-path + expression: "body.repository.full_name" + - key: git-repository-url + expression: "body.repository.ssh_url" + - key: git-default-branch + expression: "body.repository.default_branch" + - key: git-revision + expression: "body.head_commit.id" + - key: branch-name + expression: "body.ref.split('/')[2]" triggerSelector: labelSelector: matchLabels: type: branch-push + - name: tag-push + interceptors: + - name: event-push + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "header.match('X-GitHub-Event', 'push')" + - name: ref-tags + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "body.ref.split('/')[1] == 'tags'" + - name: total-commits-positive + ref: + kind: ClusterInterceptor + name: "cel" + params: + - name: "filter" + value: "body.total_commits > 0" + - name: "overlays" + value: + - key: artifactory-url + expression: "body.repository.clone_url.split('/')[2]" + - key: project-name + expression: "body.repository.name" + - key: project-path + expression: "body.repository.full_name" + - key: git-repository-url + expression: "body.repository.ssh_url" + - key: git-revision + expression: "body.head_commit.id" + - key: tag-name + expression: "body.ref.split('/')[2]" + triggerSelector: + labelSelector: + matchLabels: + type: tag-push + - name: all + triggerSelector: + labelSelector: + matchLabels: + type: all EOF } diff --git a/share/gitea-tekton-org/tekton.dev_v1_Pipeline_auto-ci-push.yaml b/share/gitea-tekton-org/tekton.dev_v1_Pipeline_auto-ci-push.yaml new file mode 100644 index 0000000..0c60a42 --- /dev/null +++ b/share/gitea-tekton-org/tekton.dev_v1_Pipeline_auto-ci-push.yaml @@ -0,0 +1,153 @@ +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: auto-ci-push +spec: + workspaces: + - name: source + - name: ssh + params: + - name: artifactory-url + default: docker.io + description: The url of the current artifactory + type: string + - name: project-name + description: The name of the current project + type: string + - name: project-path + description: The path of the current project + type: string + - name: git-default-branch + description: The git revision + default: main + - name: git-url + type: string + - name: git-revision + type: string + - name: branch-name + type: string + tasks: + - name: git-clone + params: + - name: url + value: $(params.git-url) + - name: revision + value: $(params.git-revision) + - name: depth + value: 0 + taskRef: + name: git-clone + workspaces: + - name: source + workspace: source + - name: ssh-directory + workspace: ssh + - name: git-version + runAfter: [git-clone] + params: + - name: branch + value: $(params.branch-name) + taskRef: + name: git-version + workspaces: + - name: source + - name: detect-stages + runAfter: [git-version] + params: + - name: artifactory-url + value: $(params.artifactory-url) + - name: project-name + value: $(params.project-name) + - name: project-path + value: $(params.project-path) + taskRef: + name: detect-stages + workspaces: + - name: source + - name: lint-shell + runAfter: [detect-stages] + when: + - input: "lint-shell" + operator: in + values: ["$(tasks.detect-stages.results.stages-lint[*])"] + params: + - name: args + value: $(tasks.detect-stages.results.file-shell) + taskRef: + name: shellcheck + workspaces: + - name: shared-workspace + workspace: source + - name: lint-docker + runAfter: [detect-stages] + when: + - input: "lint-docker" + operator: in + values: ["$(tasks.detect-stages.results.stages-lint[*])"] + taskRef: + name: hadolint + matrix: + params: + - name: dockerfile-path + value: $(tasks.detect-stages.results.file-docker) + workspaces: + - name: source + - name: lint-yaml + runAfter: [detect-stages] + when: + - input: "lint-yaml" + operator: in + values: ["$(tasks.detect-stages.results.lstages-int[*])"] + params: + - name: args + value: ["."] + taskRef: + name: yaml-lint + workspaces: + - name: shared-workspace + workspace: source + - name: lint-black + runAfter: [detect-stages] + when: + - input: "lint-black" + operator: in + values: ["$(tasks.detect-stages.results.stages-lint[*])"] + params: + - name: args + value: ["--check", "--diff", "$(tasks.detect-stages.results.file-python[*])"] + taskRef: + name: black + workspaces: + - name: shared-workspace + workspace: source + - name: lint-python + runAfter: [detect-stages] + when: + - input: "lint-python" + operator: in + values: ["$(tasks.detect-stages.results.stages-lint[*])"] + params: + - name: args + value: ["$(tasks.detect-stages.results.file-python[*])"] + taskRef: + name: pylint + workspaces: + - name: shared-workspace + workspace: source + - name: publish-docker + runAfter: [detect-stages, "$(tasks.detect-stages.results.stages-prepare[*])", "lint-docker", "$(tasks.detect-stages.results.stages-test[*])"] + when: + - input: "publish-docker" + operator: in + values: ["$(tasks.detect-stages.results.stages-publish[*])"] + - input: $(params.branch-name) + operator: in + values: ["$(params.git-default-branch)"] + taskRef: + name: buildkit-daemonless + matrix: + params: + - name: DOCKERFILE + value: $(tasks.detect-stages.results.file-docker) + workspaces: + - name: source \ No newline at end of file diff --git a/share/gitea-tekton-org/tekton.dev_v1_Task_auto-ci-detector.yaml b/share/gitea-tekton-org/tekton.dev_v1_Task_auto-ci-detector.yaml new file mode 100644 index 0000000..7e0bae0 --- /dev/null +++ b/share/gitea-tekton-org/tekton.dev_v1_Task_auto-ci-detector.yaml @@ -0,0 +1,179 @@ +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: auto-ci-detector +spec: + results: + - name: stages-prepare + description: list of prepare actions + type: array + - name: stages-lint + description: list of lint actions + type: array + - name: stages-test + description: list of test actions + type: array + - name: stages-publish + description: list of publish actions + type: array + - name: file-shell + description: list of shell files if any + type: array + - name: file-python + description: list of python files if any + type: array + - name: file-docker + description: list of Dockerfiles if any + type: array + params: + - name: toolbox-image + default: sebt3/basic-toolbox-image:1.30.0 + description: The name of the toolbox image + type: string + - name: artifactory-url + default: docker.io + description: The url of the current artifactory + type: string + - name: project-name + description: The name of the current project + type: string + - name: project-path + description: The path of the current project + type: string + steps: + - name: detect-stages + image: $(params.toolbox-image) + workingDir: $(workspaces.source.path) + script: | + #!/usr/bin/env python3 + import os + import re + import json + import yaml + import collections.abc + import argparse + + root = '.' + def save_json(filename,data): + with open(filename, 'w') as file: + file.write(json.dumps(data)) + # detect files based on their extention + def detect_files(root_dir): + ret = {} + supported_extention = ['ts','js', 'py', 'yaml','yml', 'sh', 'rs', 'Dockerfile'] + supported_filename = ['package.json', 'yarn.lock', 'schema.prisma'] + for directory, subdir_list, file_list in os.walk(root_dir): + for filename in file_list: + if filename in supported_filename: + if not filename in ret: + ret[filename] = [] + ret[filename].append(os.path.join(directory,filename)) + ext = filename.split(".")[len(filename.split("."))-1] + if ext in supported_extention: + if not ext in ret: + ret[ext] = [] + ret[ext].append(os.path.join(directory,filename)) + return ret + def load_yaml(filename): + docs=[] + with open(filename, 'r') as file: + try: + data = yaml.safe_load_all(file) + for doc in data: + docs.append(doc) + except yaml.constructor.ConstructorError: + pass + else: + pass + return docs + def load_json(filename): + data={} + with open(filename, 'r') as file: + data = json.loads(file.read()) + return data + + def append_key(to,key,val): + if not key in to: + to[key] = [] + to[key].append(val) + def set_js_stages(stages,files,root_dir): + if 'package.json' in files and os.path.join(root_dir,'package.json') in files['package.json']: + if 'yarn.lock' in files and os.path.join(root_dir,'yarn.lock') in files['yarn.lock']: + append_key(stages,'prepare','prepare-yarn') + else: + append_key(stages,'prepare','prepare-npm') + if 'schema.prisma' in files and os.path.join(root_dir,'prisma','schema.prisma') in files['schema.prisma']: + append_key(stages,'prepare','prepare-prisma') + defs = load_json(os.path.join(root_dir,'package.json')) + if 'scripts' in defs and 'lint' in defs['scripts']: + append_key(stages,'lint','lint-javascript') + if 'scripts' in defs and 'test' in defs['scripts']: + append_key(stages,'test','test-javascript') + def set_yaml_stages(stages,files,root_dir): + have_k8s = False + have_ansible = False + yamls = [] + if 'yaml' in files: + yamls += files['yaml'] + if 'yml' in files: + yamls += files['yml'] + for file in yamls: + objs = load_yaml(file) + for obj in objs: + if obj == None: + continue + if isinstance(obj, collections.abc.Sequence): + for item in obj: + if 'name' in item and ('register' in item or 'changed_when' in item or 'loop_control' in item or 'ansible.builtin.template' in item): + have_ansible = True + elif 'apiVersion' in obj: + have_k8s = True + append_key(stages,'lint','lint-yaml') + if have_k8s: + append_key(stages,'lint','lint-kube') + if have_ansible: + append_key(stages,'lint','lint-ansible') + def get_images_name(dockerfiles,root_dir): + ret = [] + for f in dockerfiles: + dir = os.path.dirname(f) + print('get_image_name', dir, root_dir) + return ret + def get_stages(files,root_dir): + ret = {} + ret['prepare'] = [] + ret['lint'] = [] + ret['test'] = [] + ret['publish'] = [] + if 'Dockerfile' in files: + append_key(ret,'lint','lint-docker') + append_key(ret,'publish','publish-docker') + if 'yaml' in files or 'yml' in files: + set_yaml_stages(ret,files,root_dir) + if 'sh' in files: + append_key(ret,'lint', 'lint-shell') + if 'rs' in files: + append_key(ret,'lint', 'lint-clippy') + if 'py' in files: + append_key(ret,'lint','lint-python') + append_key(ret,'lint','lint-black') + if len([t for t in files['py'] if re.match('/test_',t) != None]) > 0: + append_key(ret,'test','test-python') + if 'ts' in files or 'js' in files: + set_js_stages(ret,files,root_dir) + return ret + files = detect_files(root) + stages = get_stages(files,root) + save_json("$(results.stages-prepare.path)", stages['prepare']) + save_json("$(results.stages-lint.path)", stages['lint']) + save_json("$(results.stages-test.path)", stages['test']) + save_json("$(results.stages-publish.path)", stages['publish']) + save_json("$(results.file-shell.path)", files['sh'] if 'sh' in files else []) + save_json("$(results.file-python.path)", files['py'] if 'py' in files else []) + save_json("$(results.file-docker.path)", files['Dockerfile'] if 'Dockerfile' in files else []) + save_json("$(results.images-name.path)", get_images_name(files['Dockerfile'] if 'Dockerfile' in files else [],root)) + for stage in ['prepare','lint','test','publish']: + print(stage,json.dumps(stages[stage])) + workspaces: + - name: source + mountPath: /data \ No newline at end of file diff --git a/share/organisation/ci-space.tf b/share/organisation/ci-space.tf index c5c133d..43e6085 100644 --- a/share/organisation/ci-space.tf +++ b/share/organisation/ci-space.tf @@ -24,6 +24,9 @@ resource "kubectl_manifest" "tekton" { options: domain: "${var.domain}" organization: "${trimprefix(var.instance,"org-")}" + autoCI: ${jsonencode(var.haveGitea&&var.haveTekton&& var.autoCI)} + autoCD: ${jsonencode(var.haveGitea&&var.haveTekton&& var.autoCD)} + EOF } diff --git a/share/organisation/index.yaml b/share/organisation/index.yaml index d8346ab..13216df 100644 --- a/share/organisation/index.yaml +++ b/share/organisation/index.yaml @@ -11,6 +11,16 @@ options: examples: - dev type: string + autoCD: + default: true + examples: + - true + type: boolean + autoCI: + default: true + examples: + - true + type: boolean backups: default: enable: false