├── .gitignore ├── README.md ├── cd ├── gogs.yaml ├── nexus.yaml ├── reports-repo.yaml └── sonarqube.yaml ├── config ├── gogs-configmap.yaml ├── gogs-init-taskrun.yaml ├── maven-settings-configmap.yaml └── pipeline-pvc.yaml ├── demo.sh ├── docs ├── images │ ├── pipeline-diagram-dev.svg │ ├── pipeline-diagram-stage.svg │ ├── pipeline-viz.png │ ├── pipelines.png │ └── projects.svg ├── pipeline-diagram-dev.drawio ├── pipeline-diagram-stage.drawio └── projects.drawio ├── pipelines ├── pipeline-deploy-dev.yaml └── pipeline-deploy-stage.yaml ├── runs ├── pipeline-deploy-dev-run.yaml └── pipeline-deploy-stage-run.yaml ├── tasks ├── dependency-report-task.yaml ├── deploy-app-task.yaml ├── gatling-task.yaml ├── mvn-task.yaml └── s2i-java-11-task.yaml └── triggers ├── eventlistener.yaml ├── gogs-triggerbinding.yaml └── triggertemplate.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | tmp/ -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | > For a CI/CD demo using Tekton Pipelines and Argo CD on OpenShift refer to: 3 | > https://github.com/siamaksade/openshift-cicd-demo 4 | 5 | # CI/CD Demo with Tekton Pipelines 6 | 7 | This repo is CI/CD demo using [Tekton](http://www.tekton.dev) pipelines on OpenShift which builds and deploys the [Spring PetClinic](https://github.com/spring-projects/spring-petclinic) sample Spring Boot application. This demo creates: 8 | * 3 namespaces for CI/CD, DEV and STAGE projects 9 | * 2 Tekton pipelines for deploying application to DEV and promoting to STAGE environments 10 | * Gogs git server (username/password: `gogs`/`gogs`) 11 | * Sonatype Nexus (username/password: `admin`/`admin123`) 12 | * SonarQube (username/password: `admin`/`admin`) 13 | * Report repository for test and project generated reports 14 | * Imports [Spring PetClinic](https://github.com/spring-projects/spring-petclinic) repository into Gogs git server 15 | * Adds a webhook to `spring-petclinic` repository in Gogs to start the Tekton pipeline 16 | 17 |

18 | 19 |

20 | 21 | ## Deploy DEV Pipeline 22 | 23 | On every push to the `spring-petclinic` git repository on Gogs git server, the following steps are executed within the DEV pipeline: 24 | 25 | 1. Code is cloned from Gogs git server and the unit-tests are run 26 | 1. Unit tests are executed and in parallel the code is analyzed by SonarQube for anti-patterns, and a dependency report is generated 27 | 1. Application is packaged as a JAR and released to Sonatype Nexus snapshot repository 28 | 1. A container image is built in DEV environment using S2I, and pushed to OpenShift internal registry, and tagged with `spring-petclinic:[branch]-[commit-sha]` and `spring-petclinic:latest` 29 | 1. Kubernetes manifests and performance tests configurations are cloned from Git repository 30 | 1. Application is deployed into the DEV environment using `kustomize`, the DEV manifests from Git, and the application `[branch]-[commit-sha]` image tag built in previous steps 31 | 1. Integrations tests and Gatling performance tests are executed in parallel against the DEV environment and the results are uploaded to the report server 32 | 33 | ![Pipeline Diagram](docs/images/pipeline-diagram-dev.svg) 34 | 35 | ## Deploy STAGE Pipeline 36 | 37 | The STAGE deploy pipeline requires the image tag that you want to deploy into STAGE environment. The following steps take place within the STAGE pipeline: 38 | 1. Kubernetes manifests are cloned from Git repository 39 | 1. Application is deployed into the STAGE environment using `kustomize`, the STAGE manifests from Git, and the application `[branch]-[commit-sha]` image tag built in previous steps. Alternatively you can deploy the `latest` tag of the application image for demo purposes. 40 | 1. In parallel, tests are cloned from Git repository 41 | 1. Tests are executed against the staging environment 42 | 43 | ![Pipeline Diagram](docs/images/pipeline-diagram-stage.svg) 44 | 45 | 46 | # Deploy 47 | 48 | 1. Get an OpenShift cluster via https://try.openshift.com 49 | 1. Install OpenShift Pipelines Operator 50 | 1. Download [OpenShift CLI](https://mirror.openshift.com/pub/openshift-v4/clients/ocp/latest/) and [Tekton CLI](https://github.com/tektoncd/cli/releases) 51 | 1. Deploy the demo 52 | 53 | ``` 54 | $ oc new-project demo 55 | $ git clone https://github.com/siamaksade/tekton-cd-demo 56 | $ demo.sh install 57 | ``` 58 | 59 | 1. Start the deploy pipeline by making a change in the `spring-petclinic` Git repository on Gogs, or run the following: 60 | 61 | ``` 62 | $ demo.sh start 63 | ``` 64 | 65 | 1. Check pipeline run logs 66 | 67 | ``` 68 | $ tkn pipeline logs petclinic-deploy-dev -n NAMESPACE 69 | ``` 70 | 71 | ![Pipelines in Dev Console](docs/images/pipelines.png) 72 | 73 | ![Pipeline Diagram](docs/images/pipeline-viz.png) 74 | 75 | 76 | # Troubleshooting 77 | 78 | ## Why am I getting `unable to recognize "tasks/task.yaml": no matches for kind "Task" in version "tekton.dev/v1beta1"` errors? 79 | 80 | You might have just installed the OpenShift Pipelines operator on the cluster and the operator has not finished installing Tekton on the cluster yet. Wait a few minutes for the operator to finish and then install the demo. 81 | -------------------------------------------------------------------------------- /cd/gogs.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: gogs-postgresql 6 | annotations: 7 | image.openshift.io/triggers: >- 8 | [{"from":{"kind":"ImageStreamTag","name":"postgresql:latest", "namespace":"openshift"},"fieldPath":"spec.template.spec.containers[?(@.name==\"postgresql\")].image"}] 9 | labels: 10 | app: gogs 11 | app.kubernetes.io/component: database 12 | app.kubernetes.io/instance: gogs 13 | app.kubernetes.io/name: gogs-postgresql 14 | app.kubernetes.io/part-of: gogs 15 | spec: 16 | replicas: 1 17 | selector: 18 | matchLabels: 19 | app: gogs 20 | name: gogs-postgresql 21 | template: 22 | metadata: 23 | labels: 24 | app: gogs 25 | name: gogs-postgresql 26 | spec: 27 | containers: 28 | - name: postgresql 29 | imagePullPolicy: Always 30 | image: postgresql:latest 31 | env: 32 | - name: POSTGRESQL_USER 33 | value: gogs 34 | - name: POSTGRESQL_PASSWORD 35 | value: gogs 36 | - name: POSTGRESQL_DATABASE 37 | value: gogs 38 | - name: POSTGRESQL_MAX_CONNECTIONS 39 | value: "100" 40 | - name: POSTGRESQL_SHARED_BUFFERS 41 | value: 12MB 42 | - name: POSTGRESQL_ADMIN_PASSWORD 43 | value: gogs 44 | ports: 45 | - containerPort: 5432 46 | livenessProbe: 47 | initialDelaySeconds: 30 48 | tcpSocket: 49 | port: 5432 50 | timeoutSeconds: 1 51 | failureThreshold: 10 52 | periodSeconds: 20 53 | readinessProbe: 54 | exec: 55 | command: 56 | - /bin/sh 57 | - -i 58 | - -c 59 | - psql -h 127.0.0.1 -U ${POSTGRESQL_USER} -q -d ${POSTGRESQL_DATABASE} -c 'SELECT 1' 60 | resources: 61 | limits: 62 | memory: 512Mi 63 | volumeMounts: 64 | - mountPath: /var/lib/pgsql/data 65 | name: gogs-postgres-data 66 | volumes: 67 | - name: gogs-postgres-data 68 | persistentVolumeClaim: 69 | claimName: gogs-postgres-data 70 | --- 71 | kind: Service 72 | apiVersion: v1 73 | metadata: 74 | name: gogs-postgresql 75 | labels: 76 | app: gogs 77 | spec: 78 | ports: 79 | - name: postgresql 80 | port: 5432 81 | targetPort: 5432 82 | selector: 83 | name: gogs-postgresql 84 | app: gogs 85 | --- 86 | apiVersion: apps/v1 87 | kind: Deployment 88 | metadata: 89 | name: gogs 90 | labels: 91 | app: gogs 92 | app.kubernetes.io/component: gogs 93 | app.kubernetes.io/instance: gogs 94 | app.kubernetes.io/name: gogs 95 | app.kubernetes.io/part-of: gogs 96 | spec: 97 | replicas: 1 98 | selector: 99 | matchLabels: 100 | app: gogs 101 | name: gogs 102 | template: 103 | metadata: 104 | labels: 105 | app: gogs 106 | name: gogs 107 | spec: 108 | containers: 109 | - name: gogs 110 | imagePullPolicy: Always 111 | image: quay.io/siamaksade/gogs:stable 112 | ports: 113 | - containerPort: 3000 114 | protocol: TCP 115 | volumeMounts: 116 | - name: gogs-data 117 | mountPath: /opt/gogs/data 118 | - name: gogs-config 119 | mountPath: /etc/gogs/conf 120 | readinessProbe: 121 | httpGet: 122 | path: / 123 | port: 3000 124 | scheme: HTTP 125 | initialDelaySeconds: 40 126 | timeoutSeconds: 1 127 | periodSeconds: 20 128 | successThreshold: 1 129 | failureThreshold: 10 130 | livenessProbe: 131 | httpGet: 132 | path: / 133 | port: 3000 134 | scheme: HTTP 135 | initialDelaySeconds: 40 136 | timeoutSeconds: 1 137 | periodSeconds: 10 138 | successThreshold: 1 139 | failureThreshold: 10 140 | volumes: 141 | - name: gogs-data 142 | persistentVolumeClaim: 143 | claimName: gogs-data 144 | - name: gogs-config 145 | configMap: 146 | name: gogs-config 147 | items: 148 | - key: app.ini 149 | path: app.ini 150 | --- 151 | kind: Service 152 | apiVersion: v1 153 | metadata: 154 | labels: 155 | app: gogs 156 | name: gogs 157 | spec: 158 | ports: 159 | - name: 3000-tcp 160 | port: 3000 161 | protocol: TCP 162 | targetPort: 3000 163 | selector: 164 | app: gogs 165 | name: gogs 166 | type: ClusterIP 167 | --- 168 | kind: Route 169 | apiVersion: v1 170 | id: gogs-http 171 | metadata: 172 | labels: 173 | app: gogs 174 | name: gogs 175 | spec: 176 | to: 177 | name: gogs 178 | --- 179 | kind: PersistentVolumeClaim 180 | apiVersion: v1 181 | metadata: 182 | name: gogs-data 183 | labels: 184 | app: gogs 185 | spec: 186 | accessModes: 187 | - ReadWriteOnce 188 | resources: 189 | requests: 190 | storage: 1Gi 191 | --- 192 | kind: PersistentVolumeClaim 193 | apiVersion: v1 194 | metadata: 195 | name: gogs-postgres-data 196 | labels: 197 | app: gogs 198 | spec: 199 | accessModes: 200 | - ReadWriteOnce 201 | resources: 202 | requests: 203 | storage: 1Gi -------------------------------------------------------------------------------- /cd/nexus.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | labels: 6 | app: nexus 7 | app.kubernetes.io/instance: nexus 8 | app.kubernetes.io/name: nexus 9 | app.kubernetes.io/part-of: nexus 10 | name: nexus 11 | spec: 12 | replicas: 1 13 | selector: 14 | matchLabels: 15 | app: nexus 16 | template: 17 | metadata: 18 | labels: 19 | app: nexus 20 | spec: 21 | containers: 22 | - name: nexus 23 | image: quay.io/siamaksade/nexus3:3.16.2 24 | env: 25 | - name: CONTEXT_PATH 26 | value: / 27 | imagePullPolicy: IfNotPresent 28 | ports: 29 | - containerPort: 8081 30 | protocol: TCP 31 | livenessProbe: 32 | exec: 33 | command: 34 | - echo 35 | - ok 36 | failureThreshold: 3 37 | initialDelaySeconds: 30 38 | periodSeconds: 10 39 | successThreshold: 1 40 | timeoutSeconds: 1 41 | readinessProbe: 42 | failureThreshold: 3 43 | httpGet: 44 | path: / 45 | port: 8081 46 | scheme: HTTP 47 | initialDelaySeconds: 30 48 | periodSeconds: 10 49 | successThreshold: 1 50 | timeoutSeconds: 1 51 | resources: 52 | limits: 53 | memory: 4Gi 54 | cpu: 2 55 | requests: 56 | memory: 512Mi 57 | cpu: 200m 58 | terminationMessagePath: /dev/termination-log 59 | volumeMounts: 60 | - mountPath: /nexus-data 61 | name: nexus-data 62 | volumes: 63 | - name: nexus-data 64 | persistentVolumeClaim: 65 | claimName: nexus-pv 66 | --- 67 | apiVersion: v1 68 | kind: Service 69 | metadata: 70 | labels: 71 | app: nexus 72 | name: nexus 73 | spec: 74 | ports: 75 | - name: 8081-tcp 76 | port: 8081 77 | protocol: TCP 78 | targetPort: 8081 79 | selector: 80 | app: nexus 81 | sessionAffinity: None 82 | type: ClusterIP 83 | --- 84 | apiVersion: v1 85 | kind: Route 86 | metadata: 87 | labels: 88 | app: nexus 89 | name: nexus 90 | spec: 91 | port: 92 | targetPort: 8081-tcp 93 | to: 94 | kind: Service 95 | name: nexus 96 | weight: 100 97 | --- 98 | apiVersion: v1 99 | kind: PersistentVolumeClaim 100 | metadata: 101 | labels: 102 | app: nexus 103 | name: nexus-pv 104 | spec: 105 | accessModes: 106 | - ReadWriteOnce 107 | resources: 108 | requests: 109 | storage: 5Gi -------------------------------------------------------------------------------- /cd/reports-repo.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | labels: 6 | app: reports-repo 7 | app.kubernetes.io/instance: reports-repo 8 | app.kubernetes.io/name: reports-repo 9 | app.kubernetes.io/part-of: reports-repo 10 | name: reports-repo 11 | spec: 12 | replicas: 1 13 | selector: 14 | matchLabels: 15 | app: reports-repo 16 | deployment: reports-repo 17 | template: 18 | metadata: 19 | labels: 20 | app: reports-repo 21 | deployment: reports-repo 22 | spec: 23 | containers: 24 | - name: uploader 25 | image: quay.io/chmouel/go-simple-uploader:latest 26 | imagePullPolicy: IfNotPresent 27 | env: 28 | - name: UPLOADER_PORT 29 | value: "9000" 30 | - name: UPLOADER_DIRECTORY 31 | value: "/fileuploads" 32 | volumeMounts: 33 | - mountPath: /fileuploads 34 | name: staticfiles 35 | - image: quay.io/siamaksade/nginx:latest 36 | name: nginx 37 | ports: 38 | - containerPort: 8080 39 | protocol: TCP 40 | volumeMounts: 41 | - mountPath: /etc/nginx/conf.d/ 42 | name: nginx-conf 43 | - mountPath: /fileuploads 44 | name: staticfiles 45 | volumes: 46 | - name: nexus-data 47 | persistentVolumeClaim: 48 | claimName: nexus-pv 49 | volumes: 50 | - configMap: 51 | defaultMode: 420 52 | name: reports-repo-nginx-conf 53 | name: nginx-conf 54 | - name: staticfiles 55 | persistentVolumeClaim: 56 | claimName: reports-repo-pv 57 | --- 58 | apiVersion: v1 59 | kind: ConfigMap 60 | metadata: 61 | name: reports-repo-nginx-conf 62 | data: 63 | htpasswd: | 64 | reports:$apr1$MHzwWLP6$P/dRWWfgBe4J8wfId78v71 65 | nginx.conf: "types {\n text/plain yaml yml;\n}\n\nserver {\n listen 8080 66 | default_server;\n gzip on;\n\n\tlocation /upload {\n\t\tsatisfy any;\n\t\tauth_basic 67 | \"Welcome to the Jungle!\"; #For Basic Auth\n \tauth_basic_user_file conf.d/htpasswd; 68 | \ #For Basic Auth\n\t\tdeny all;\n\n\t\tproxy_set_header Host $host;\n\t\tproxy_set_header 69 | \ X-Real-IP $remote_addr;\n\t\tproxy_set_header X-Forwarded-Proto https;\n\t\tproxy_set_header 70 | \ X-Forwarded-For $remote_addr;\n\t\tproxy_set_header X-Forwarded-Host $remote_addr;\n\n\t\tproxy_pass 71 | http://localhost:9000;\n\t}\n\n\tlocation /private {\n\t\troot /fileuploads;\n\n\t\tsatisfy 72 | any;\n\t\tauth_basic \"Welcome to the Jungle!\"; #For Basic Auth\n \tauth_basic_user_file 73 | conf.d/htpasswd; #For Basic Auth\n\t\tdeny all;\n\n\t autoindex 74 | on;\n\t autoindex_exact_size off;\n\t autoindex_localtime on;\n\t}\n\n\tlocation 75 | / {\n\t\troot /fileuploads;\n\t autoindex on;\n\t autoindex_exact_size off;\n\t 76 | \ autoindex_localtime on;\n\t}\n}\n" 77 | --- 78 | apiVersion: v1 79 | kind: Service 80 | metadata: 81 | labels: 82 | app: reports-repo 83 | name: reports-repo 84 | spec: 85 | ports: 86 | - name: 8080-tcp 87 | port: 8080 88 | protocol: TCP 89 | targetPort: 8080 90 | selector: 91 | app: reports-repo 92 | deployment: reports-repo 93 | --- 94 | apiVersion: v1 95 | kind: Route 96 | metadata: 97 | labels: 98 | app: reports-repo 99 | name: reports-repo 100 | spec: 101 | port: 102 | targetPort: 8080-tcp 103 | to: 104 | kind: Service 105 | name: reports-repo 106 | weight: 100 107 | --- 108 | apiVersion: v1 109 | kind: PersistentVolumeClaim 110 | metadata: 111 | labels: 112 | app: reports-repo 113 | name: reports-repo-pv 114 | spec: 115 | accessModes: 116 | - ReadWriteOnce 117 | resources: 118 | requests: 119 | storage: 5Gi -------------------------------------------------------------------------------- /cd/sonarqube.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: sonarqube 6 | labels: 7 | app: sonarqube 8 | app.kubernetes.io/component: sonarqube 9 | app.kubernetes.io/instance: sonarqube 10 | app.kubernetes.io/name: sonarqube 11 | app.kubernetes.io/part-of: sonarqube 12 | spec: 13 | replicas: 1 14 | selector: 15 | matchLabels: 16 | app: sonarqube 17 | name: sonarqube 18 | template: 19 | metadata: 20 | labels: 21 | app: sonarqube 22 | name: sonarqube 23 | spec: 24 | containers: 25 | - name: sonarqube 26 | imagePullPolicy: Always 27 | image: quay.io/siamaksade/sonarqube:8.3-community 28 | ports: 29 | - containerPort: 9000 30 | protocol: TCP 31 | volumeMounts: 32 | - mountPath: /opt/sq/temp 33 | name: sonarqube-temp 34 | - mountPath: /opt/sq/conf 35 | name: sonarqube-conf 36 | - mountPath: /opt/sq/data 37 | name: sonarqube-data 38 | - mountPath: /opt/sq/extensions 39 | name: sonarqube-extensions 40 | - mountPath: /opt/sq/logs 41 | name: sonarqube-logs 42 | livenessProbe: 43 | failureThreshold: 10 44 | httpGet: 45 | path: / 46 | port: 9000 47 | scheme: HTTP 48 | initialDelaySeconds: 45 49 | periodSeconds: 10 50 | successThreshold: 1 51 | timeoutSeconds: 1 52 | readinessProbe: 53 | failureThreshold: 10 54 | httpGet: 55 | path: / 56 | port: 9000 57 | scheme: HTTP 58 | initialDelaySeconds: 10 59 | periodSeconds: 10 60 | successThreshold: 1 61 | timeoutSeconds: 1 62 | resources: 63 | limits: 64 | cpu: "1" 65 | memory: 4Gi 66 | requests: 67 | cpu: 200m 68 | memory: 512Mi 69 | volumes: 70 | - name: sonarqube-temp 71 | emptyDir: {} 72 | - name: sonarqube-conf 73 | emptyDir: {} 74 | - name: sonarqube-data 75 | emptyDir: {} 76 | - name: sonarqube-extensions 77 | emptyDir: {} 78 | - name: sonarqube-logs 79 | emptyDir: {} 80 | --- 81 | apiVersion: v1 82 | kind: Route 83 | metadata: 84 | labels: 85 | app: sonarqube 86 | name: sonarqube 87 | spec: 88 | port: 89 | targetPort: 9000-tcp 90 | tls: 91 | termination: edge 92 | to: 93 | kind: Service 94 | name: sonarqube 95 | weight: 100 96 | wildcardPolicy: None 97 | --- 98 | apiVersion: v1 99 | kind: Service 100 | metadata: 101 | labels: 102 | app: sonarqube 103 | name: sonarqube 104 | spec: 105 | ports: 106 | - name: 9000-tcp 107 | port: 9000 108 | protocol: TCP 109 | targetPort: 9000 110 | selector: 111 | app: sonarqube 112 | name: sonarqube 113 | type: ClusterIP -------------------------------------------------------------------------------- /config/gogs-configmap.yaml: -------------------------------------------------------------------------------- 1 | kind: ConfigMap 2 | apiVersion: v1 3 | metadata: 4 | name: gogs-config 5 | labels: 6 | app: gogs 7 | data: 8 | app.ini: | 9 | RUN_MODE = prod 10 | RUN_USER = gogs 11 | 12 | [database] 13 | DB_TYPE = postgres 14 | HOST = gogs-postgresql:5432 15 | NAME = gogs 16 | USER = gogs 17 | PASSWD = gogs 18 | 19 | [repository] 20 | ROOT = /opt/gogs/data/repositories 21 | 22 | [server] 23 | ROOT_URL=http://@HOSTNAME 24 | SSH_DOMAIN=@HOSTNAME 25 | 26 | [security] 27 | INSTALL_LOCK = true 28 | 29 | [service] 30 | ENABLE_CAPTCHA = false 31 | 32 | [webhook] 33 | SKIP_TLS_VERIFY = true -------------------------------------------------------------------------------- /config/gogs-init-taskrun.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: TaskRun 3 | metadata: 4 | generateName: init-gogs- 5 | spec: 6 | taskSpec: 7 | params: 8 | - name: GOGS_USER 9 | type: string 10 | description: Gogs admin username 11 | default: gogs 12 | - name: GOGS_PASSWORD 13 | type: string 14 | description: Gogs admin password 15 | default: gogs 16 | stepTemplate: 17 | env: 18 | - name: NAMESPACE 19 | valueFrom: 20 | fieldRef: 21 | fieldPath: metadata.namespace 22 | steps: 23 | - name: init-gogs 24 | image: quay.io/siamaksade/python-oc 25 | script: | 26 | #!/usr/bin/env python3 27 | 28 | import os 29 | import requests 30 | 31 | gogs_user = "$(params.GOGS_USER)" 32 | gogs_pwd = "$(params.GOGS_PASSWORD)" 33 | webhookURL = "http://" + os.popen('oc get route webhook -o template --template="{{.spec.host}}"').read() 34 | gogsURL = "http://" + os.popen('oc get svc gogs -o template --template="{{.spec.clusterIP}}"').read() + ":3000" 35 | 36 | # create admin user 37 | data_user = { 38 | 'user_name': gogs_user, 39 | 'password': gogs_pwd, 40 | 'retype': gogs_pwd, 41 | 'email': 'admin@gogs.com' 42 | } 43 | 44 | resp = requests.post(url = gogsURL + "/user/sign_up", data = data_user) 45 | 46 | if resp.status_code != 200: 47 | print("Error creating Gogs admin (status code: {})".format(resp.status_code)) 48 | print(resp.content) 49 | else: 50 | print("Created admin user {}:{}".format(gogs_user, gogs_pwd)) 51 | 52 | # create git repo spring-petclinic 53 | data_repo = '{"clone_addr": "https://github.com/siamaksade/spring-petclinic", "uid": 1, "repo_name": "spring-petclinic"}' 54 | headers = {'Content-Type': 'application/json'} 55 | resp = requests.post(url = gogsURL + "/api/v1/repos/migrate", headers = headers, auth = (gogs_user, gogs_pwd), data = data_repo) 56 | 57 | if resp.status_code != 200 and resp.status_code != 201: 58 | print("Error creating git repo (status code: {})".format(resp.status_code)) 59 | print(resp.content) 60 | else: 61 | print("Created git repo spring-petclinic") 62 | 63 | # configure webhook on spring-petclinic 64 | data_webhook = '{"type": "gogs", "config": { "url": "' + webhookURL + '", "content_type": "json"}, "events": ["push"], "active": true}' 65 | headers = {'Content-Type': 'application/json'} 66 | resp = requests.post(url = gogsURL + "/api/v1/repos/" + gogs_user + "/spring-petclinic/hooks", 67 | headers = headers, 68 | auth = (gogs_user, gogs_pwd), 69 | data = data_webhook) 70 | 71 | if resp.status_code != 200 and resp.status_code != 201: 72 | print("Error configuring the webhook (status code: {})".format(resp.status_code)) 73 | print(resp.content) 74 | else: 75 | print("Configured webhook: " + webhookURL) 76 | 77 | # create git repo spring-petclinic-config 78 | data_repo = '{"clone_addr": "https://github.com/siamaksade/spring-petclinic-config.git", "uid": 1, "repo_name": "spring-petclinic-config"}' 79 | headers = {'Content-Type': 'application/json'} 80 | resp = requests.post(url = gogsURL + "/api/v1/repos/migrate", headers = headers, auth = (gogs_user, gogs_pwd), data = data_repo) 81 | 82 | if resp.status_code != 200 and resp.status_code != 201: 83 | print("Error creating git repo (status code: {})".format(resp.status_code)) 84 | print(resp.content) 85 | else: 86 | print("Created git repo spring-petclinic-config") 87 | 88 | # configure webhook on spring-petclinic-config 89 | data_webhook = '{"type": "gogs", "config": { "url": "' + webhookURL + '", "content_type": "json"}, "events": ["push"], "active": true}' 90 | headers = {'Content-Type': 'application/json'} 91 | resp = requests.post(url = gogsURL + "/api/v1/repos/" + gogs_user + "/spring-petclinic-config/hooks", 92 | headers = headers, 93 | auth = (gogs_user, gogs_pwd), 94 | data = data_webhook) 95 | 96 | if resp.status_code != 200 and resp.status_code != 201: 97 | print("Error configuring the webhook (status code: {})".format(resp.status_code)) 98 | print(resp.content) 99 | else: 100 | print("Configured webhook: " + webhookURL) 101 | 102 | # create git repo spring-petclinic-gatling 103 | data_repo = '{"clone_addr": "https://github.com/siamaksade/spring-petclinic-gatling", "uid": 1, "repo_name": "spring-petclinic-gatling"}' 104 | headers = {'Content-Type': 'application/json'} 105 | resp = requests.post(url = gogsURL + "/api/v1/repos/migrate", headers = headers, auth = (gogs_user, gogs_pwd), data = data_repo) 106 | 107 | if resp.status_code != 200 and resp.status_code != 201: 108 | print("Error creating git repo (status code: {})".format(resp.status_code)) 109 | print(resp.content) 110 | else: 111 | print("Created git repo spring-petclinic-gatling") 112 | 113 | -------------------------------------------------------------------------------- /config/maven-settings-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: maven-settings 5 | data: 6 | settings.xml: | 7 | 8 | 9 | 10 | 11 | nexus 12 | admin 13 | admin123 14 | 15 | 16 | 17 | 18 | nexus 19 | nexus 20 | http://nexus:8081/repository/maven-public/ 21 | * 22 | 23 | 24 | -------------------------------------------------------------------------------- /config/pipeline-pvc.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: PersistentVolumeClaim 4 | metadata: 5 | name: petclinic-dev-workspace 6 | spec: 7 | resources: 8 | requests: 9 | storage: 5Gi 10 | volumeMode: Filesystem 11 | accessModes: 12 | - ReadWriteOnce 13 | persistentVolumeReclaimPolicy: Retain 14 | --- 15 | apiVersion: v1 16 | kind: PersistentVolumeClaim 17 | metadata: 18 | name: petclinic-stage-workspace 19 | spec: 20 | resources: 21 | requests: 22 | storage: 5Gi 23 | volumeMode: Filesystem 24 | accessModes: 25 | - ReadWriteOnce 26 | persistentVolumeReclaimPolicy: Retain -------------------------------------------------------------------------------- /demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -e -u -o pipefail 4 | declare -r SCRIPT_DIR=$(cd -P $(dirname $0) && pwd) 5 | declare PRJ_PREFIX="demo" 6 | declare COMMAND="help" 7 | 8 | valid_command() { 9 | local fn=$1; shift 10 | [[ $(type -t "$fn") == "function" ]] 11 | } 12 | 13 | info() { 14 | printf "\n# INFO: $@\n" 15 | } 16 | 17 | err() { 18 | printf "\n# ERROR: $1\n" 19 | exit 1 20 | } 21 | 22 | while (( "$#" )); do 23 | case "$1" in 24 | install|uninstall|start|promote) 25 | COMMAND=$1 26 | shift 27 | ;; 28 | -p|--project-prefix) 29 | PRJ_PREFIX=$2 30 | shift 2 31 | ;; 32 | --) 33 | shift 34 | break 35 | ;; 36 | -*|--*) 37 | err "Error: Unsupported flag $1" 38 | ;; 39 | *) 40 | break 41 | esac 42 | done 43 | 44 | declare -r dev_prj="$PRJ_PREFIX-dev" 45 | declare -r stage_prj="$PRJ_PREFIX-stage" 46 | declare -r cicd_prj="$PRJ_PREFIX-cicd" 47 | 48 | command.help() { 49 | cat <<-EOF 50 | 51 | Usage: 52 | demo [command] [options] 53 | 54 | Example: 55 | demo install --project-prefix mydemo 56 | 57 | COMMANDS: 58 | install Sets up the demo and creates namespaces 59 | uninstall Deletes the demo 60 | start Starts the deploy DEV pipeline 61 | promote Starts the deploy STAGE pipeline 62 | help Help about this command 63 | 64 | OPTIONS: 65 | -p|--project-prefix [string] Prefix to be added to demo project names e.g. PREFIX-dev 66 | EOF 67 | } 68 | 69 | command.install() { 70 | oc version >/dev/null 2>&1 || err "no oc binary found" 71 | 72 | info "Creating namespaces $cicd_prj, $dev_prj, $stage_prj" 73 | oc get ns $cicd_prj 2>/dev/null || { 74 | oc new-project $cicd_prj 75 | } 76 | oc get ns $dev_prj 2>/dev/null || { 77 | oc new-project $dev_prj 78 | } 79 | oc get ns $stage_prj 2>/dev/null || { 80 | oc new-project $stage_prj 81 | } 82 | 83 | info "Configure service account permissions for pipeline" 84 | oc policy add-role-to-user edit system:serviceaccount:$cicd_prj:pipeline -n $dev_prj 85 | oc policy add-role-to-user edit system:serviceaccount:$cicd_prj:pipeline -n $stage_prj 86 | oc policy add-role-to-user edit system:serviceaccount:$stage_prj:default -n $dev_prj 87 | 88 | info "Deploying CI/CD infra to $cicd_prj namespace" 89 | oc apply -f cd -n $cicd_prj 90 | GOGS_HOSTNAME=$(oc get route gogs -o template --template='{{.spec.host}}' -n $cicd_prj) 91 | 92 | info "Deploying pipeline and tasks to $cicd_prj namespace" 93 | oc apply -f tasks -n $cicd_prj 94 | oc create -f config/maven-settings-configmap.yaml -n $cicd_prj 95 | oc apply -f config/pipeline-pvc.yaml -n $cicd_prj 96 | sed "s/demo-dev/$dev_prj/g" pipelines/pipeline-deploy-dev.yaml | sed -E "s#https://github.com/siamaksade#http://$GOGS_HOSTNAME/gogs#g" | oc apply -f - -n $cicd_prj 97 | sed "s/demo-dev/$dev_prj/g" pipelines/pipeline-deploy-stage.yaml | sed -E "s/demo-stage/$stage_prj/g" | sed -E "s#https://github.com/siamaksade#http://$GOGS_HOSTNAME/gogs#g" | oc apply -f - -n $cicd_prj 98 | 99 | oc apply -f triggers/gogs-triggerbinding.yaml -n $cicd_prj 100 | oc apply -f triggers/triggertemplate.yaml -n $cicd_prj 101 | sed "s/demo-dev/$dev_prj/g" triggers/eventlistener.yaml | oc apply -f - -n $cicd_prj 102 | 103 | info "Initiatlizing git repository in Gogs and configuring webhooks" 104 | sed "s/@HOSTNAME/$GOGS_HOSTNAME/g" config/gogs-configmap.yaml | oc create -f - -n $cicd_prj 105 | oc rollout status deployment/gogs -n $cicd_prj 106 | oc create -f config/gogs-init-taskrun.yaml -n $cicd_prj 107 | 108 | oc project $cicd_prj 109 | 110 | cat <<-EOF 111 | 112 | ############################################################################ 113 | ############################################################################ 114 | 115 | Demo is installed! Give it a few minutes to finish deployments and then: 116 | 117 | 1) Go to spring-petclinic Git repository in Gogs: 118 | http://$GOGS_HOSTNAME/gogs/spring-petclinic.git 119 | 120 | 2) Log into Gogs with username/password: gogs/gogs 121 | 122 | 3) Edit a file in the repository and commit to trigger the pipeline 123 | 124 | 4) Check the pipeline run logs in Dev Console or Tekton CLI: 125 | 126 | \$ tkn pipeline logs petclinic-deploy-dev -f -n $cicd_prj 127 | 128 | 129 | You can find further details at: 130 | 131 | Gogs Git Server: http://$GOGS_HOSTNAME/explore/repos 132 | Reports Server: http://$(oc get route reports-repo -o template --template='{{.spec.host}}' -n $cicd_prj) 133 | SonarQube: https://$(oc get route sonarqube -o template --template='{{.spec.host}}' -n $cicd_prj) 134 | Sonatype Nexus: http://$(oc get route nexus -o template --template='{{.spec.host}}' -n $cicd_prj) 135 | 136 | ############################################################################ 137 | ############################################################################ 138 | EOF 139 | } 140 | 141 | command.start() { 142 | oc create -f runs/pipeline-deploy-dev-run.yaml -n $cicd_prj 143 | } 144 | 145 | command.promote() { 146 | oc create -f runs/pipeline-deploy-stage-run.yaml -n $cicd_prj 147 | } 148 | 149 | command.uninstall() { 150 | oc delete project $dev_prj $stage_prj $cicd_prj 151 | } 152 | 153 | main() { 154 | local fn="command.$COMMAND" 155 | valid_command "$fn" || { 156 | err "invalid command '$COMMAND'" 157 | } 158 | 159 | cd $SCRIPT_DIR 160 | $fn 161 | return $? 162 | } 163 | 164 | main -------------------------------------------------------------------------------- /docs/images/pipeline-diagram-dev.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Clone Code
Clone Code
Gogs
Git Server
Gogs...
Release App
Release App
Static Analysis
Static Analysis
Sonatype
Nexus
Sonatype...
SonarQube
SonarQube
Build Image
(S2I Java)
Build Image...
Deploy App to OpenShift DEV
Deploy App to OpenSh...
Generate Project Report
Generate Project Rep...
Run Int Tests
 in DEV
Run Int Tests...
Run Performance Tests in DEV
Run Performance Test...
Reports
Repository
Reports...
Run Unit Tests
Run Unit Tests
Clone Kubernetes manifests
Clone Kubernetes man...
Clone Tests
Clone Tests
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /docs/images/pipeline-diagram-stage.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
Clone Kubernetes manifests
Clone Kubernetes man...
Gogs
Git Server
Gogs...
Run Tests in
STAGE
Run Tests in...
Clone Tests
Clone Tests
Deploy App to OpenShift STAGE
Deploy App to OpenSh...
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /docs/images/pipeline-viz.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siamaksade/tekton-cd-demo/7ae7ea58f310d744081b9373a9fb13a744e8488b/docs/images/pipeline-viz.png -------------------------------------------------------------------------------- /docs/images/pipelines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/siamaksade/tekton-cd-demo/7ae7ea58f310d744081b9373a9fb13a744e8488b/docs/images/pipelines.png -------------------------------------------------------------------------------- /docs/images/projects.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 |
OpenShift
OpenShift
demo-cicd
demo-cicd
demo-dev
demo-dev
Spring
PetClinic
Spring...
demo-stage
demo-stage
Spring
PetClinic
Spring...
SonarQube
SonarQube
Viewer does not support full SVG 1.1
-------------------------------------------------------------------------------- /docs/pipeline-diagram-dev.drawio: -------------------------------------------------------------------------------- 1 | 7Vxbc5s4FP41ntl9yA4Ig+HRsdNs2u4mjbdt0pcdGWSbBCNGiMTeX7+SAXMRwcTGXDrNi9FBEuKc71x0dMhAmaw31wR6q7+whZwBkKzNQJkOAJAlw2A/nLINKYYBQsKS2FbUKSHM7P9QPDKiBraF/ExHirFDbS9LNLHrIpNmaJAQ/JrttsBO9qkeXCKBMDOhI1K/2xZdhVRdlRL6n8heruIny1J0Zw3jzhHBX0ELv6ZIytVAmRCMaXi13kyQw5kX8yUc9+GNu/uFEeTSKgPAfEVH5g8NLi3z1n9+GT9c/LiI2ezTbfzGyGIMiJqY0BVeYhc6Vwn1kuDAtRCfVmKtpM9njD1GlBnxCVG6jaQJA4oZaUXXTnQXbWz6kLp+5FP9oUat6SaaedfYxg2Xku1DupEaxZvJsF1rP86Z77j+ggi1mVwZyQzIy275/PkiGyPO+jggJirjXQRHSJYoGvrkPD1KZHx5O7oZf9S+X7j/Kl/ifpyvqQdEQrpGeI3YelkHghxI7Zcs8GCE3+W+XyJidhFJ+T0Sl4+QeIZjvRJ/reIt7DdsS7w3HzCZaT54vL+YGt+m86+fJvYFKJWui93WFLhWSRS+e8cULZz3BTpB9KSJw9kPpAnzkoKYEplwpr6ubIpmHtzx5ZW51iz/F7bjTLCDyW6sYkGkL0xG9ynBzyh1RzN1NF+UcZ/bRbQp5Vd8V4t8eeTKldizvSaOUY5pq5RT1KRzsbgc7T+bLbOgv9qvXBC1JGnaZHKSooGKJq92RYuG3mGbLXkPOGOUxZuaw1H4PtGgdOSTm0ceHpgofGFhoh0m969TCabFAYDeGZgm0HxMI/MATBNkPmaAWQzTt5GZAXAhhmrDbaEghnXAdEwI3KY6eBw2/tso1qUM+GRNKgWrrhtl/dlFuIB6EWp0FKHyUQiV6zSkjSJU7QBCVeMQQvWy/icjtIyBqWjqGi/ZO7FHaw7j6OWcsKslv7q2+WJniKGTCLBmu3CPX5pbx2aAJYdjrXmI7M/zPQGaz8sd3m8DymZBgwM7yeohFshKQpHVahHW6GwRltJRw3Cc63qXYThe25WKcZTWTBylqtn4Bxhni3+KQTRqH0TnTB+UZX0OYkCpGwNV9b1w1ceoe6/2UDX69KpaLp/q1E+y4IrgOO+Rg6CPmLuEa+7r3LnPf8aeJwi/+0mJYX6T2H5SYti+tasxlj6026vmMs/t4pT4WCmCwXCUm6JqriA/kSppzfrK7uQKup2eH7blX4txM8xtooZyszHWUDDzM8rex2S0MRP+1rf9Hlp3RcmpdXx61Zp110Q+M+WiWw8V7kX/RptAZHy3N6F5lwpa34WOCplOvgRz8Ryl27zNA1qVhs3xtjDi707mrwl/U5Ds43/1bgxifTl7PvokwR9V+vFL8vVIvtUtYbzKlD29DGzHYqSbNa+HEtzYbzNww+5+hC/w9x6GEZomZ6xuo5vEwlKFX1F+RYXSRIUqZGjtVThvHCXv6/tiKElGdo764vzC9+ynu24AAGpbAGg6mS7uQKbIczB/t10KT2ICA9Kth9zZyl7wpU+vvvXQaBtGjtGtG+3y5HibtXVnNcxltXadSb/kwdJwiQ8AnbHLjSd96y6gqIq34n7Sifg6yUKINZ/XyEUEUp4duiP4iX+iAKR75DEB99Am59MX7dtkMe95H7h8I7OzDv8gnxe+5Lcz+aMv2+2tl5RlVc2IBIyMlkXSoarcztnCY0xfQU6hxPQ1EQJrubMOkINS5cLc/ExnPG0rY61gPe4QWWCyhq6JEisi/UxmQtHattwxXDOVCdwvFlf18Xu+TXH05P6k/A29ayl/MUoJUf/VtVNOsw2MC1wt4H3l4AQAvTmIFzNa7Ywn7GOK/e0zkypVV9qJzu8kyYthafzx16dgjoiLKOJmjnkYe9FTddNB9kMFoFU8Jj6funWn8uo96taI2hQEkR1UGzEei9Wmr05JB9mPJZTR+eIu1kz+nUAYIif/lEG5+h8= -------------------------------------------------------------------------------- /docs/pipeline-diagram-stage.drawio: -------------------------------------------------------------------------------- 1 | 5VhZc9owEP41PKZjW8bAIyGUnkNbMpPjpSPsxVYiLI8sc/TXV7LlCxOgKZQwfQHp064k73572C00mK9GHEfBV+YBbVmGt2qhm5ZlmUavJ/8Uss6QXs/KAJ8TTwuVwIT8glxTownxIK4JCsaoIFEddFkYgitqGOacLetiM0brp0bYhwYwcTFtonfEE0GGdttGiX8A4gf5yaahV+Y4F9ZAHGCPLSsQGrbQgDMmstF8NQCqjJfbJdN7/8JqcTEOoThEwZoGouM+Otj33HH8vOjfXz1e5WaOxTp/YvCkAfSUcREwn4WYDkv0mrMk9EBta8hZKfOFsUiCpgSfQIi19iZOBJNQIOZUr8KKiPvK+EFt9a6tZzcrvXM6WeeTUPD1fXVS0VLTUi2dFXp0mlp9AVwQ6VcJuQlfpNdX5zfNqC0bs4S7sMt2mo6Y+6BVn+jTg8H71+POx/4n5+4q/Im+53LKrpUDtJNGwOYg7ysFOFAsyKJOPKz56xdypYvlQHv5TzxuvsLjNYtdlPuP6t6tcvbbcm+27wLTRJ80oCwECX1OpsBDEDKbquwUkhnEIm6QofSucs8yIAImEU4ttZQpvu7JGaF0wCjjqS7yMHRnrsRjwdkzVFYctwvT2S5/qPiE1U4L5quOrim6pKA8wy7LBG3mWFBJzo5xKqNb/1VMeTgOips3XG0YjjMY/FXoWQeG3tEzq1b9xoi8ckG4XqfOt/YGj7Ln0UrVCryxj2nv2Sh74MZGKSeLxzmIplsLkWW/GZqW1HyorOyjacnMQutYNN3g0Gl5ax+Dpn3O8boiECnaxC+zuGvUyNdGxk6yorxR3y4vB9kFXsvQXQasVK8R81W9alkOlRa9nnI58tVoRNRlJyDZyRu0lr12pIbumhJJWL6/kk0zZn+ZFgB2n/2U7+NEyF1gX794eAGz6p5AZvuw+tU5Wf3qnD8xnLK/29WW7w1W9Kb6O9SIkB9JKIHbrJkzSLg1Wia3/dHwAns9e7P2nr/X654/Vi7i/ck+V3xtr2f2Rv2zzZM1X7vMseXF7PZC38MQqncIqGP+u9jcldIrNr6BiDJ1534UpZ8O5c84gnASkFnaP5wvLzYMvcUdB9vecrons72cll8ps3Aov/Wi4W8= -------------------------------------------------------------------------------- /docs/projects.drawio: -------------------------------------------------------------------------------- 1 | 7VnbcpswEP0aHtORkC/4sXac9iFN03qmSZ86MsigRCBGyDbu11eAZMCyc3HsOpOEzGS0RyshnbMr1uCgUZx/ETiNvvGAMMcFQe6gc8d1Bx5U/wtgVQHdvlcBoaBBBcEamNC/RINAo3MakKzlKDlnkqZt0OdJQnzZwrAQfNl2m3HWvmuKQ2IBEx8zG72hgYwq1OuCGv9KaBiZO0Oge2JsnDWQRTjgywaExg4aCc5l1YrzEWEFd4aXatzFjt71wgRJ5FMGeJerztXodoFufl2hP1c/70F+d6ZnWWA21xv+npJkEtGZ1KuWK0OF4PMkIMVswEHDZUQlmaTYL3qXSnuFRTJmyoKqmUnB78mIMy4UkvBEuQ1nlDEDOS4a94o/hTM8JeyaZ1RSnqg+X22JKKfhgghJlRiXGw4xDYJiWUPMaLh1xGfdIXmxsBlP5ETvBBq7ijXYUbZmQY0l+U564Vo0FeyEx0SKlXIxka5l1nG+ln1ZR023p7GoGTF9DWIdqeF66lpM1dB6PkNb19I2IDE/86kfvEzbXTK2NVc9vfLaR+Apl5LHTxc4wFlULh9q4xpL5Z+UiAvgYTSGsN8WuW+L7LrIFtmcggfXGG3XOCCLD4n3khj1waMSQ7glj48mcc+SeJIKmoROccL0mLr9cCpUKyxa10SOGE2of8jTW8kMyssOjIvy2jhRwYGkGGxk22DLkdq3legc60D1tidbJosa4iPd9tG4C/dNt2OJPHiv6dZFryzdoF2cvgGaoeu1afZOTbNdJ74FmtEGzSePZrtUm/AEix/z6QsfHq+D706bbwROzLfbfzysQ8VzunPz+pUCnhp38FxS1OPsU3eDFmg/3wAwXk1m3KNFol3HWMyoaWiakceDD2dp9dplRvMiYP9XND6guS1H8+fZllrieEzbxcQbZzo3WW0i+lTUux2b6SAk5iUQFzLioTp/2bhGh/5cLNY1b/sMrgdc8qI+Ll3uiJQrTSieS94WjORU3jbav4upFC+VdZ7rmUtjZYxEbf62aTRGFWY9rLTMuO3KFjveR1dFG58LnzzhEJFYhOShGascsCNFEIYlXbTXd/gwAO80A73TZ2D3IwOPmoGDJ2Zg42vDQTNQmfXXi7Kv8QkIjf8B -------------------------------------------------------------------------------- /pipelines/pipeline-deploy-dev.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Pipeline 3 | metadata: 4 | name: petclinic-deploy-dev 5 | spec: 6 | params: 7 | - name: APP_SOURCE_GIT 8 | type: string 9 | description: The application git repository 10 | default: https://github.com/siamaksade/spring-petclinic 11 | - name: APP_SOURCE_REVISION 12 | type: string 13 | description: The application git revision 14 | default: master 15 | - name: APP_CONFIG_GIT 16 | type: string 17 | description: The application configuration git repository 18 | default: https://github.com/siamaksade/spring-petclinic-config 19 | - name: APP_TESTS_GIT 20 | type: string 21 | description: The application test cases git repository 22 | default: https://github.com/siamaksade/spring-petclinic-gatling 23 | - name: APP_IMAGE 24 | type: string 25 | default: image-registry.openshift-image-registry.svc:5000/demo-dev/spring-petclinic 26 | description: The application image to build 27 | - name: APP_IMAGE_TAG 28 | type: string 29 | default: latest 30 | description: The application image tag to build 31 | workspaces: 32 | - name: workspace 33 | - name: maven-settings 34 | tasks: 35 | - name: source-clone 36 | taskRef: 37 | name: git-clone 38 | kind: ClusterTask 39 | workspaces: 40 | - name: output 41 | workspace: workspace 42 | params: 43 | - name: url 44 | value: $(params.APP_SOURCE_GIT) 45 | - name: revision 46 | value: $(params.APP_SOURCE_REVISION) 47 | - name: depth 48 | value: "0" 49 | - name: subdirectory 50 | value: spring-petclinic 51 | - name: deleteExisting 52 | value: "true" 53 | - name: unit-tests 54 | taskRef: 55 | name: maven 56 | runAfter: 57 | - source-clone 58 | workspaces: 59 | - name: source 60 | workspace: workspace 61 | - name: maven-settings 62 | workspace: maven-settings 63 | params: 64 | - name: GOALS 65 | value: ["package", "-f", "spring-petclinic"] 66 | - name: code-analysis 67 | taskRef: 68 | name: maven 69 | runAfter: 70 | - source-clone 71 | workspaces: 72 | - name: source 73 | workspace: workspace 74 | - name: maven-settings 75 | workspace: maven-settings 76 | params: 77 | - name: GOALS 78 | value: 79 | - install 80 | - sonar:sonar 81 | - -f 82 | - spring-petclinic 83 | - -Dsonar.host.url=http://sonarqube:9000 84 | - -Dsonar.userHome=/tmp/sonar 85 | - -DskipTests=true 86 | - name: dependency-report 87 | taskRef: 88 | name: dependency-report 89 | runAfter: 90 | - source-clone 91 | workspaces: 92 | - name: source 93 | workspace: workspace 94 | - name: maven-settings 95 | workspace: maven-settings 96 | params: 97 | - name: SOURCE_DIR 98 | value: spring-petclinic 99 | - name: release-app 100 | taskRef: 101 | name: maven 102 | runAfter: 103 | - code-analysis 104 | - dependency-report 105 | - unit-tests 106 | workspaces: 107 | - name: source 108 | workspace: workspace 109 | - name: maven-settings 110 | workspace: maven-settings 111 | params: 112 | - name: GOALS 113 | value: 114 | - deploy 115 | - -f 116 | - spring-petclinic 117 | - -DskipTests=true 118 | - -DaltDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-releases/ 119 | - -DaltSnapshotDeploymentRepository=nexus::default::http://nexus:8081/repository/maven-snapshots/ 120 | - name: build-image 121 | taskRef: 122 | name: s2i-java-11 123 | runAfter: 124 | - release-app 125 | params: 126 | - name: TLSVERIFY 127 | value: "false" 128 | - name: MAVEN_MIRROR_URL 129 | value: http://nexus:8081/repository/maven-public/ 130 | - name: PATH_CONTEXT 131 | value: spring-petclinic/target 132 | - name: IMAGE_NAME 133 | value: $(params.APP_IMAGE) 134 | - name: IMAGE_TAG 135 | value: $(params.APP_IMAGE_TAG) 136 | workspaces: 137 | - name: source 138 | workspace: workspace 139 | - name: config-clone 140 | taskRef: 141 | name: git-clone 142 | kind: ClusterTask 143 | workspaces: 144 | - name: output 145 | workspace: workspace 146 | runAfter: 147 | - build-image 148 | params: 149 | - name: url 150 | value: $(params.APP_CONFIG_GIT) 151 | - name: subdirectory 152 | value: spring-petclinic-config 153 | - name: deleteExisting 154 | value: "true" 155 | - name: tests-clone 156 | taskRef: 157 | name: git-clone 158 | kind: ClusterTask 159 | workspaces: 160 | - name: output 161 | workspace: workspace 162 | runAfter: 163 | - build-image 164 | params: 165 | - name: url 166 | value: $(params.APP_TESTS_GIT) 167 | - name: subdirectory 168 | value: spring-petclinic-gatling 169 | - name: deleteExisting 170 | value: "true" 171 | - name: deploy-dev 172 | taskRef: 173 | name: deploy-app 174 | runAfter: 175 | - config-clone 176 | - tests-clone 177 | params: 178 | - name: DEPLOYMENT_NAME 179 | value: spring-petclinic 180 | - name: CURRENT_IMAGE 181 | value: "quay.io/siamaksade/spring-petclinic:latest" 182 | - name: NEW_IMAGE_NAME 183 | value: $(params.APP_IMAGE) 184 | - name: NEW_IMAGE_TAG 185 | value: $(params.APP_IMAGE_TAG) 186 | - name: NEW_IMAGE_DIGEST 187 | value: $(tasks.build-image.results.IMAGE_DIGEST) 188 | - name: NAMESPACE 189 | value: demo-dev 190 | - name: KUSTOMIZE_OVERLAY_DIR 191 | value: environments/dev 192 | workspaces: 193 | - name: source 194 | workspace: workspace 195 | subPath: spring-petclinic-config 196 | - name: int-test 197 | taskRef: 198 | name: openshift-client 199 | kind: ClusterTask 200 | runAfter: 201 | - deploy-dev 202 | params: 203 | - name: SCRIPT 204 | value: | 205 | sleep $(($RANDOM % 40 + 20)) 206 | - name: perf-test 207 | taskRef: 208 | name: gatling 209 | runAfter: 210 | - deploy-dev 211 | params: 212 | - name: APP_URL 213 | value: "http://spring-petclinic.demo-dev.svc.cluster.local:8080" 214 | workspaces: 215 | - name: simulations 216 | workspace: workspace 217 | subPath: spring-petclinic-gatling -------------------------------------------------------------------------------- /pipelines/pipeline-deploy-stage.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Pipeline 3 | metadata: 4 | name: petclinic-deploy-stage 5 | spec: 6 | params: 7 | - name: APP_CONFIG_GIT 8 | type: string 9 | description: The application configuration git repository 10 | default: https://github.com/siamaksade/spring-petclinic-config 11 | - name: APP_TESTS_GIT 12 | type: string 13 | description: The application test cases git repository 14 | default: https://github.com/siamaksade/spring-petclinic-gatling 15 | - name: APP_IMAGE_NAME 16 | type: string 17 | default: image-registry.openshift-image-registry.svc:5000/demo-dev/spring-petclinic 18 | description: The application image to deploy to stage 19 | - name: APP_IMAGE_TAG 20 | type: string 21 | default: "latest" 22 | description: The application image tag to deploy to stage 23 | # - name: APP_IMAGE_DIGEST 24 | # type: string 25 | # default: "" 26 | # description: The application image digest to deploy to stage 27 | - name: STAGE_NAMESPACE 28 | type: string 29 | default: demo-stage 30 | description: The namespace for Stage environments 31 | workspaces: 32 | - name: workspace 33 | tasks: 34 | - name: config-clone 35 | taskRef: 36 | name: git-clone 37 | kind: ClusterTask 38 | workspaces: 39 | - name: output 40 | workspace: workspace 41 | params: 42 | - name: url 43 | value: $(params.APP_CONFIG_GIT) 44 | - name: subdirectory 45 | value: spring-petclinic-config 46 | - name: deleteExisting 47 | value: "true" 48 | - name: tests-clone 49 | taskRef: 50 | name: git-clone 51 | kind: ClusterTask 52 | workspaces: 53 | - name: output 54 | workspace: workspace 55 | runAfter: 56 | - config-clone 57 | params: 58 | - name: url 59 | value: $(params.APP_TESTS_GIT) 60 | - name: subdirectory 61 | value: spring-petclinic-gatling 62 | - name: deleteExisting 63 | value: "true" 64 | - name: deploy-stage 65 | taskRef: 66 | name: deploy-app 67 | runAfter: 68 | - config-clone 69 | params: 70 | - name: DEPLOYMENT_NAME 71 | value: spring-petclinic 72 | - name: CURRENT_IMAGE 73 | value: "quay.io/siamaksade/spring-petclinic:latest" 74 | - name: NEW_IMAGE_NAME 75 | value: $(params.APP_IMAGE_NAME) 76 | - name: NEW_IMAGE_TAG 77 | value: $(params.APP_IMAGE_TAG) 78 | - name: NAMESPACE 79 | value: $(params.STAGE_NAMESPACE) 80 | - name: KUSTOMIZE_OVERLAY_DIR 81 | value: environments/stage 82 | workspaces: 83 | - name: source 84 | workspace: workspace 85 | subPath: spring-petclinic-config 86 | - name: test-stage 87 | taskRef: 88 | name: gatling 89 | runAfter: 90 | - deploy-stage 91 | - tests-clone 92 | params: 93 | - name: APP_URL 94 | value: "http://spring-petclinic.$(params.STAGE_NAMESPACE).svc.cluster.local:8080" 95 | workspaces: 96 | - name: simulations 97 | workspace: workspace 98 | subPath: spring-petclinic-gatling -------------------------------------------------------------------------------- /runs/pipeline-deploy-dev-run.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: PipelineRun 3 | metadata: 4 | generateName: petclinic-deploy-dev- 5 | spec: 6 | pipelineRef: 7 | name: petclinic-deploy-dev 8 | workspaces: 9 | - name: workspace 10 | persistentVolumeClaim: 11 | claimName: petclinic-dev-workspace 12 | - name: maven-settings 13 | configMap: 14 | name: maven-settings -------------------------------------------------------------------------------- /runs/pipeline-deploy-stage-run.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: PipelineRun 3 | metadata: 4 | generateName: petclinic-deploy-stage- 5 | spec: 6 | pipelineRef: 7 | name: petclinic-deploy-stage 8 | workspaces: 9 | - name: workspace 10 | persistentVolumeClaim: 11 | claimName: petclinic-stage-workspace -------------------------------------------------------------------------------- /tasks/dependency-report-task.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: dependency-report 5 | annotations: 6 | tekton.dev/pipelines.minVersion: 0.12.1 7 | spec: 8 | params: 9 | - name: SOURCE_DIR 10 | description: The directory within the workspace where application source is located 11 | default: "." 12 | - name: REPORTS_REPO_HOST 13 | description: The reports repository host based on https://github.com/chmouel/openshift-django-uploader 14 | default: http://reports-repo:8080 15 | - name: REPORTS_REPO_USERNAME 16 | description: The reports repository username 17 | default: reports 18 | - name: REPORTS_REPO_PASSWORD 19 | description: The reports repository password 20 | default: reports 21 | - default: '' 22 | description: The Maven repository mirror url 23 | name: MAVEN_MIRROR_URL 24 | type: string 25 | - default: '' 26 | description: The username for the proxy server 27 | name: PROXY_USER 28 | type: string 29 | - default: '' 30 | description: The password for the proxy server 31 | name: PROXY_PASSWORD 32 | type: string 33 | - default: '' 34 | description: Port number for the proxy server 35 | name: PROXY_PORT 36 | type: string 37 | - default: '' 38 | description: Proxy server Host 39 | name: PROXY_HOST 40 | type: string 41 | - default: '' 42 | description: Non proxy server host 43 | name: PROXY_NON_PROXY_HOSTS 44 | type: string 45 | - default: http 46 | description: Protocol for the proxy ie http or https 47 | name: PROXY_PROTOCOL 48 | type: string 49 | workspaces: 50 | - description: The workspace consisting of maven project. 51 | name: source 52 | - description: The workspace consisting of the custom maven settings provided by the user. 53 | name: maven-settings 54 | steps: 55 | - image: 'registry.access.redhat.com/ubi8/ubi-minimal:latest' 56 | name: mvn-settings 57 | resources: {} 58 | script: > 59 | #!/usr/bin/env bash 60 | 61 | 62 | [[ -f $(workspaces.maven-settings.path)/settings.xml ]] && \ 63 | 64 | echo 'using existing $(workspaces.maven-settings.path)/settings.xml' && 65 | exit 0 66 | 67 | 68 | cat > $(workspaces.maven-settings.path)/settings.xml < 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | EOF 82 | 83 | 84 | xml="" 85 | 86 | if [ -n "$(params.PROXY_HOST)" -a -n "$(params.PROXY_PORT)" ]; then 87 | xml="\ 88 | genproxy\ 89 | true\ 90 | $(params.PROXY_PROTOCOL)\ 91 | $(params.PROXY_HOST)\ 92 | $(params.PROXY_PORT)" 93 | if [ -n "$(params.PROXY_USER)" -a -n "$(params.PROXY_PASSWORD)" ]; then 94 | xml="$xml\ 95 | $(params.PROXY_USER)\ 96 | $(params.PROXY_PASSWORD)" 97 | fi 98 | if [ -n "$(params.PROXY_NON_PROXY_HOSTS)" ]; then 99 | xml="$xml\ 100 | $(params.PROXY_NON_PROXY_HOSTS)" 101 | fi 102 | xml="$xml\ 103 | " 104 | sed -i "s||$xml|" $(workspaces.maven-settings.path)/settings.xml 105 | fi 106 | 107 | 108 | if [ -n "$(params.MAVEN_MIRROR_URL)" ]; then 109 | xml=" \ 110 | mirror.default\ 111 | $(params.MAVEN_MIRROR_URL)\ 112 | central\ 113 | " 114 | sed -i "s||$xml|" $(workspaces.maven-settings.path)/settings.xml 115 | fi 116 | - args: 117 | - -Dmaven.repo.local=$(workspaces.source.path)/.m2 118 | - -f 119 | - $(params.SOURCE_DIR) 120 | - -s 121 | - $(workspaces.maven-settings.path)/settings.xml 122 | - site 123 | - -DskipTests=true 124 | command: 125 | - /usr/bin/mvn 126 | image: gcr.io/cloud-builders/mvn 127 | name: mvn-goals 128 | resources: {} 129 | workingDir: $(workspaces.source.path) 130 | - name: archive-site 131 | workingDir: $(workspaces.source.path) 132 | image: registry.access.redhat.com/ubi8/ubi:latest 133 | env: 134 | - name: PIPELINERUN_NAME 135 | valueFrom: 136 | fieldRef: 137 | fieldPath: metadata.labels['tekton.dev/pipelineRun'] 138 | script: | 139 | #!/usr/bin/env bash 140 | 141 | for f in $(find $(params.SOURCE_DIR)/target/site -type f); do 142 | curl -u $(params.REPORTS_REPO_USERNAME):$(params.REPORTS_REPO_PASSWORD) -F path=$PIPELINERUN_NAME/${f} -X POST -F file=@${f} $(params.REPORTS_REPO_HOST)/upload; echo "" 143 | done -------------------------------------------------------------------------------- /tasks/deploy-app-task.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: deploy-app 5 | spec: 6 | params: 7 | - name: DEPLOYMENT_NAME 8 | description: The name of deployment 9 | type: string 10 | - name: CURRENT_IMAGE 11 | description: The current image repo/image:tag in the manifests for the deployment 12 | type: string 13 | - name: NEW_IMAGE_NAME 14 | description: The new image repo/image to be deployed 15 | type: string 16 | - name: NEW_IMAGE_TAG 17 | description: The new image tag to be deployed 18 | type: string 19 | default: "" 20 | - name: NEW_IMAGE_DIGEST 21 | description: The digest of the new image to get deployed 22 | type: string 23 | default: "" 24 | - name: NAMESPACE 25 | description: The namespace for the deployment 26 | type: string 27 | - name: KUSTOMIZE_OVERLAY_DIR 28 | description: The subdirectory in configs git repo for the kustomize overlay to be applied 29 | workspaces: 30 | - description: The workspace consisting of maven project. 31 | name: source 32 | steps: 33 | - name: apply-manifests 34 | workingDir: $(workspaces.source.path) 35 | image: image-registry.openshift-image-registry.svc:5000/openshift/cli 36 | script: | 37 | 38 | find $(workspaces.source.path) 39 | 40 | cat >> $(workspaces.source.path)/$(params.KUSTOMIZE_OVERLAY_DIR)/kustomization.yaml <<- EOF 41 | 42 | images: 43 | - name: quay.io/siamaksade/spring-petclinic:latest 44 | newName: $(params.NEW_IMAGE_NAME) 45 | newTag: $(params.NEW_IMAGE_TAG) 46 | digest: $(params.NEW_IMAGE_DIGEST) 47 | EOF 48 | 49 | [[ "x$(params.NEW_IMAGE_DIGEST)" == "x" ]] && sed -i "/digest/d" $(workspaces.source.path)/$(params.KUSTOMIZE_OVERLAY_DIR)/kustomization.yaml 50 | [[ "x$(params.NEW_IMAGE_TAG)" == "x" ]] && sed -i "/newTag/d" $(workspaces.source.path)/$(params.KUSTOMIZE_OVERLAY_DIR)/kustomization.yaml 51 | 52 | echo "########################" 53 | echo "## kustomization.yaml ##" 54 | echo "########################" 55 | 56 | cat $(workspaces.source.path)/$(params.KUSTOMIZE_OVERLAY_DIR)/kustomization.yaml 57 | 58 | echo "######## DRY RUN #######" 59 | oc apply -k $(params.KUSTOMIZE_OVERLAY_DIR) --dry-run=client -o yaml -n $(params.NAMESPACE) 60 | echo "########################" 61 | 62 | oc apply -k $(params.KUSTOMIZE_OVERLAY_DIR) -n $(params.NAMESPACE) 63 | oc rollout status deploy/$(params.DEPLOYMENT_NAME) -n $(params.NAMESPACE) 64 | -------------------------------------------------------------------------------- /tasks/gatling-task.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: gatling 5 | spec: 6 | params: 7 | - name: DURATION 8 | description: The duration of running simulations 9 | type: string 10 | default: "30" 11 | - name: CONCURRENT_USERS 12 | description: The number of concurrent users 13 | type: string 14 | default: "10" 15 | - name: APP_URL 16 | description: The application under test url 17 | type: string 18 | - name: REPORTS_REPO_HOST 19 | description: The reports repository host based on https://github.com/chmouel/openshift-django-uploader 20 | default: http://reports-repo:8080 21 | - name: REPORTS_REPO_USERNAME 22 | description: The reports repository username 23 | default: reports 24 | - name: REPORTS_REPO_PASSWORD 25 | description: The reports repository password 26 | default: reports 27 | workspaces: 28 | - description: The workspace consisting of maven project. 29 | name: simulations 30 | steps: 31 | - name: run-tests 32 | image: quay.io/siamaksade/gatling:latest 33 | env: 34 | - name: PIPELINERUN_NAME 35 | valueFrom: 36 | fieldRef: 37 | fieldPath: metadata.labels['tekton.dev/pipelineRun'] 38 | script: | 39 | #!/usr/bin/env bash 40 | 41 | # set simulation params 42 | export JAVA_OPTS="-DtestDuration=$(params.CONCURRENT_USERS) -DuserCount=$(params.DURATION) -Dserver=$(params.APP_URL)" 43 | 44 | # run simulation 45 | /opt/gatling/bin/gatling.sh -rd "Spring PetClinic Performance Test" -sf $(workspaces.simulations.path) 46 | 47 | # upload results 48 | REPORT=$(ls -td /opt/gatling/results/* | head -1) 49 | for f in $(find $REPORT/ -type f); do 50 | curl -u $(params.REPORTS_REPO_USERNAME):$(params.REPORTS_REPO_PASSWORD) -F path=$PIPELINERUN_NAME${f#/opt/gatling/results} -X POST -F file=@${f} $(params.REPORTS_REPO_HOST)/upload; echo "" 51 | done -------------------------------------------------------------------------------- /tasks/mvn-task.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | annotations: 5 | tekton.dev/pipelines.minVersion: 0.12.1 6 | tekton.dev/tags: build-tool 7 | name: maven 8 | labels: 9 | app.kubernetes.io/version: '0.1' 10 | operator.tekton.dev/provider-type: community 11 | spec: 12 | description: This Task can be used to run a Maven build. 13 | params: 14 | - default: gcr.io/cloud-builders/mvn:3.5.0-jdk-8 15 | description: Maven base image 16 | name: MAVEN_IMAGE 17 | type: string 18 | - default: 19 | - package 20 | description: maven goals to run 21 | name: GOALS 22 | type: array 23 | - default: '' 24 | description: The Maven repository mirror url 25 | name: MAVEN_MIRROR_URL 26 | type: string 27 | - default: '' 28 | description: The username for the proxy server 29 | name: PROXY_USER 30 | type: string 31 | - default: '' 32 | description: The password for the proxy server 33 | name: PROXY_PASSWORD 34 | type: string 35 | - default: '' 36 | description: Port number for the proxy server 37 | name: PROXY_PORT 38 | type: string 39 | - default: '' 40 | description: Proxy server Host 41 | name: PROXY_HOST 42 | type: string 43 | - default: '' 44 | description: Non proxy server host 45 | name: PROXY_NON_PROXY_HOSTS 46 | type: string 47 | - default: http 48 | description: Protocol for the proxy ie http or https 49 | name: PROXY_PROTOCOL 50 | type: string 51 | workspaces: 52 | - description: The workspace consisting of maven project. 53 | name: source 54 | - description: The workspace consisting of the custom maven settings provided by the user. 55 | name: maven-settings 56 | steps: 57 | - image: 'registry.access.redhat.com/ubi8/ubi-minimal:latest' 58 | name: mvn-settings 59 | resources: {} 60 | script: > 61 | #!/usr/bin/env bash 62 | 63 | 64 | [[ -f $(workspaces.maven-settings.path)/settings.xml ]] && \ 65 | 66 | echo 'using existing $(workspaces.maven-settings.path)/settings.xml' && 67 | exit 0 68 | 69 | 70 | cat > $(workspaces.maven-settings.path)/settings.xml < 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | EOF 84 | 85 | 86 | xml="" 87 | 88 | if [ -n "$(params.PROXY_HOST)" -a -n "$(params.PROXY_PORT)" ]; then 89 | xml="\ 90 | genproxy\ 91 | true\ 92 | $(params.PROXY_PROTOCOL)\ 93 | $(params.PROXY_HOST)\ 94 | $(params.PROXY_PORT)" 95 | if [ -n "$(params.PROXY_USER)" -a -n "$(params.PROXY_PASSWORD)" ]; then 96 | xml="$xml\ 97 | $(params.PROXY_USER)\ 98 | $(params.PROXY_PASSWORD)" 99 | fi 100 | if [ -n "$(params.PROXY_NON_PROXY_HOSTS)" ]; then 101 | xml="$xml\ 102 | $(params.PROXY_NON_PROXY_HOSTS)" 103 | fi 104 | xml="$xml\ 105 | " 106 | sed -i "s||$xml|" $(workspaces.maven-settings.path)/settings.xml 107 | fi 108 | 109 | 110 | if [ -n "$(params.MAVEN_MIRROR_URL)" ]; then 111 | xml=" \ 112 | mirror.default\ 113 | $(params.MAVEN_MIRROR_URL)\ 114 | central\ 115 | " 116 | sed -i "s||$xml|" $(workspaces.maven-settings.path)/settings.xml 117 | fi 118 | - args: 119 | - -Dmaven.repo.local=$(workspaces.source.path)/.m2 120 | - '-s' 121 | - $(workspaces.maven-settings.path)/settings.xml 122 | - $(params.GOALS) 123 | command: 124 | - /usr/bin/mvn 125 | image: $(params.MAVEN_IMAGE) 126 | name: mvn-goals 127 | resources: {} 128 | workingDir: $(workspaces.source.path) 129 | -------------------------------------------------------------------------------- /tasks/s2i-java-11-task.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: tekton.dev/v1beta1 2 | kind: Task 3 | metadata: 4 | name: s2i-java-11 5 | annotations: 6 | tekton.dev/displayName: s2i java 11 7 | tekton.dev/pipelines.minVersion: 0.11.3 8 | tekton.dev/tags: 's2i, java, workspace' 9 | spec: 10 | description: >- 11 | s2i-java-11 task clones a Git repository and builds and pushes a container 12 | image using S2I and a Java 11 builder image. 13 | params: 14 | - default: . 15 | description: The location of the path to run s2i from 16 | name: PATH_CONTEXT 17 | type: string 18 | - default: 'true' 19 | description: >- 20 | Verify the TLS on the registry endpoint (for push/pull to a non-TLS 21 | registry) 22 | name: TLSVERIFY 23 | type: string 24 | - default: '' 25 | description: Additional Maven arguments 26 | name: MAVEN_ARGS_APPEND 27 | type: string 28 | - default: 'false' 29 | description: Remove the Maven repository after the artifact is built 30 | name: MAVEN_CLEAR_REPO 31 | type: string 32 | - default: '' 33 | description: The base URL of a mirror used for retrieving artifacts 34 | name: MAVEN_MIRROR_URL 35 | type: string 36 | - description: Location of the repo where image has to be pushed 37 | name: IMAGE_NAME 38 | type: string 39 | - description: The tag of the image to be pushed 40 | name: IMAGE_TAG 41 | type: string 42 | default: "latest" 43 | 44 | results: 45 | - name: IMAGE_DIGEST 46 | description: Digest of the image just built. 47 | steps: 48 | - args: 49 | - |- 50 | echo "MAVEN_CLEAR_REPO=$(params.MAVEN_CLEAR_REPO)" > env-file 51 | 52 | [[ '$(params.MAVEN_ARGS_APPEND)' != "" ]] && 53 | echo "MAVEN_ARGS_APPEND=$(params.MAVEN_ARGS_APPEND)" >> env-file 54 | 55 | [[ '$(params.MAVEN_MIRROR_URL)' != "" ]] && 56 | echo "MAVEN_MIRROR_URL=$(params.MAVEN_MIRROR_URL)" >> env-file 57 | 58 | echo "Generated Env file" 59 | echo "------------------------------" 60 | cat env-file 61 | echo "------------------------------" 62 | command: 63 | - /bin/sh 64 | - '-c' 65 | image: >- 66 | registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8@sha256:562dbdac04ae9260e21d457585b3251fd8cc5310966f8fc544fb77dc544c92f8 67 | name: gen-env-file 68 | resources: {} 69 | volumeMounts: 70 | - mountPath: /env-params 71 | name: envparams 72 | workingDir: /env-params 73 | - command: 74 | - s2i 75 | - build 76 | - $(params.PATH_CONTEXT) 77 | - 'image-registry.openshift-image-registry.svc:5000/openshift/java:11' 78 | - '--image-scripts-url' 79 | - 'image:///usr/local/s2i' 80 | - '--as-dockerfile' 81 | - /gen-source/Dockerfile.gen 82 | - '--environment-file' 83 | - /env-params/env-file 84 | image: >- 85 | registry.redhat.io/ocp-tools-43-tech-preview/source-to-image-rhel8@sha256:562dbdac04ae9260e21d457585b3251fd8cc5310966f8fc544fb77dc544c92f8 86 | name: generate 87 | resources: {} 88 | volumeMounts: 89 | - mountPath: /gen-source 90 | name: gen-source 91 | - mountPath: /env-params 92 | name: envparams 93 | workingDir: $(workspaces.source.path) 94 | - command: 95 | - buildah 96 | - bud 97 | - '--storage-driver=vfs' 98 | - '--tls-verify=$(params.TLSVERIFY)' 99 | - '--layers' 100 | - '-f' 101 | - /gen-source/Dockerfile.gen 102 | - '-t' 103 | - $(params.IMAGE_NAME):$(params.IMAGE_TAG) 104 | - '-t' 105 | - $(params.IMAGE_NAME):latest 106 | - . 107 | image: >- 108 | registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 109 | name: build 110 | resources: {} 111 | volumeMounts: 112 | - mountPath: /var/lib/containers 113 | name: varlibcontainers 114 | - mountPath: /gen-source 115 | name: gen-source 116 | workingDir: /gen-source 117 | - command: 118 | - buildah 119 | - push 120 | - '--storage-driver=vfs' 121 | - '--tls-verify=$(params.TLSVERIFY)' 122 | - --digestfile 123 | - $(workspaces.source.path)/image-digest 124 | - $(params.IMAGE_NAME):$(params.IMAGE_TAG) 125 | - 'docker://$(params.IMAGE_NAME):$(params.IMAGE_TAG)' 126 | image: registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 127 | name: push-tag 128 | resources: {} 129 | volumeMounts: 130 | - mountPath: /var/lib/containers 131 | name: varlibcontainers 132 | - command: 133 | - buildah 134 | - push 135 | - '--storage-driver=vfs' 136 | - '--tls-verify=$(params.TLSVERIFY)' 137 | - --digestfile 138 | - $(workspaces.source.path)/image-digest 139 | - $(params.IMAGE_NAME):$(params.IMAGE_TAG) 140 | - 'docker://$(params.IMAGE_NAME):latest' 141 | image: registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 142 | name: push-latest 143 | resources: {} 144 | volumeMounts: 145 | - mountPath: /var/lib/containers 146 | name: varlibcontainers 147 | - name: digest-to-results 148 | image: registry.redhat.io/rhel8/buildah@sha256:180c4d9849b6ab0e5465d30d4f3a77765cf0d852ca1cb1efb59d6e8c9f90d467 149 | script: cat $(workspaces.source.path)/image-digest | tee /tekton/results/IMAGE_DIGEST 150 | volumes: 151 | - emptyDir: {} 152 | name: varlibcontainers 153 | - emptyDir: {} 154 | name: gen-source 155 | - emptyDir: {} 156 | name: envparams 157 | workspaces: 158 | - mountPath: /workspace/source 159 | name: source 160 | -------------------------------------------------------------------------------- /triggers/eventlistener.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: triggers.tekton.dev/v1alpha1 3 | kind: EventListener 4 | metadata: 5 | name: webhook 6 | spec: 7 | serviceAccountName: pipeline 8 | triggers: 9 | - name: petclinic-webhook 10 | interceptors: 11 | - cel: 12 | overlays: 13 | - key: short_sha 14 | expression: "body.after.truncate(7)" 15 | - key: branch_name 16 | expression: "body.ref.split('/')[2]" 17 | bindings: 18 | - ref: gogs-triggerbinding 19 | template: 20 | name: petclinic-trigger-template 21 | --- 22 | apiVersion: route.openshift.io/v1 23 | kind: Route 24 | metadata: 25 | name: webhook 26 | labels: 27 | app.kubernetes.io/managed-by: EventListener 28 | app.kubernetes.io/part-of: Triggers 29 | eventlistener: webhook 30 | spec: 31 | port: 32 | targetPort: 8080 33 | to: 34 | kind: "Service" 35 | name: el-webhook 36 | weight: 100 37 | -------------------------------------------------------------------------------- /triggers/gogs-triggerbinding.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: triggers.tekton.dev/v1alpha1 3 | kind: TriggerBinding 4 | metadata: 5 | name: gogs-triggerbinding 6 | spec: 7 | params: 8 | - name: gitrevision 9 | value: $(body.after) 10 | - name: gitshortsha 11 | value: $(body.short_sha) 12 | - name: gitbranchname 13 | value: $(body.branch_name) 14 | - name: gitrepositoryurl 15 | value: $(body.repository.clone_url) 16 | - name: contenttype 17 | value: $(header.Content-Type) -------------------------------------------------------------------------------- /triggers/triggertemplate.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: triggers.tekton.dev/v1alpha1 3 | kind: TriggerTemplate 4 | metadata: 5 | name: petclinic-trigger-template 6 | spec: 7 | params: 8 | - name: gitrevision 9 | description: The git revision 10 | default: master 11 | - name: gitshortsha 12 | description: The short commit sha 13 | default: master 14 | - name: gitbranchname 15 | description: The branch name 16 | default: master 17 | - name: gitrepositoryurl 18 | description: The git repository url 19 | - name: message 20 | description: The message to print 21 | default: This is the default message 22 | - name: contenttype 23 | description: The Content-Type of the event 24 | resourcetemplates: 25 | - apiVersion: tekton.dev/v1beta1 26 | kind: PipelineRun 27 | metadata: 28 | generateName: petclinic-deploy-dev- 29 | # name: petclinic-dev-$(tt.params.gitbranchname)-$(tt.params.gitshortsha) 30 | labels: 31 | tekton.dev/pipeline: petclinic-deploy-dev 32 | spec: 33 | pipelineRef: 34 | name: petclinic-deploy-dev 35 | params: 36 | - name: APP_SOURCE_GIT 37 | value: $(tt.params.gitrepositoryurl) 38 | - name: APP_SOURCE_REVISION 39 | value: $(tt.params.gitrevision) 40 | - name: APP_IMAGE_TAG 41 | value: $(tt.params.gitbranchname)-$(tt.params.gitshortsha) 42 | workspaces: 43 | - name: maven-settings 44 | configMap: 45 | name: maven-settings 46 | - name: workspace 47 | persistentVolumeClaim: 48 | claimName: petclinic-dev-workspace --------------------------------------------------------------------------------