Skip to content

Commit 814d0b5

Browse files
committed
Migration of tekton plugin tests
1 parent 01ac7ea commit 814d0b5

16 files changed

Lines changed: 3005 additions & 0 deletions
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
nodeLinker: node-modules
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { createEslintConfig } from "@red-hat-developer-hub/e2e-test-utils/eslint";
2+
3+
export default createEslintConfig(import.meta.dirname);
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
{
2+
"name": "tekton-e2e-tests",
3+
"version": "1.0.0",
4+
"private": true,
5+
"type": "module",
6+
"engines": {
7+
"node": ">=22",
8+
"yarn": ">=3"
9+
},
10+
"packageManager": "yarn@3.8.7",
11+
"description": "E2E tests for Tekton plugin",
12+
"scripts": {
13+
"test": "playwright test",
14+
"report": "playwright show-report",
15+
"test:ui": "playwright test --ui",
16+
"test:headed": "playwright test --headed",
17+
"lint:check": "eslint .",
18+
"lint:fix": "eslint . --fix",
19+
"prettier:check": "prettier --check .",
20+
"prettier:fix": "prettier --write .",
21+
"tsc:check": "tsc --noEmit",
22+
"check": "tsc --noEmit && yarn lint:check && yarn prettier:check"
23+
},
24+
"devDependencies": {
25+
"@eslint/js": "^9.39.2",
26+
"@playwright/test": "1.57.0",
27+
"@red-hat-developer-hub/e2e-test-utils": "1.1.18",
28+
"@types/node": "^24.10.1",
29+
"dotenv": "^16.4.7",
30+
"eslint": "^9.39.2",
31+
"eslint-plugin-check-file": "^3.3.1",
32+
"eslint-plugin-playwright": "^2.4.0",
33+
"prettier": "^3.7.4",
34+
"typescript": "^5.9.3",
35+
"typescript-eslint": "^8.50.0"
36+
}
37+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { defineConfig } from "@red-hat-developer-hub/e2e-test-utils/playwright-config";
2+
import dotenv from "dotenv";
3+
4+
dotenv.config({ path: `${import.meta.dirname}/.env` });
5+
6+
export default defineConfig({
7+
projects: [
8+
{
9+
name: "tekton",
10+
},
11+
],
12+
});
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
kubernetes:
2+
serviceLocatorMethod:
3+
type: multiTenant
4+
clusterLocatorMethods:
5+
- type: config
6+
clusters:
7+
- name: local-cluster
8+
url: https://kubernetes.default.svc
9+
authProvider: serviceAccount
10+
skipTLSVerify: true
11+
customResources:
12+
- apiVersion: "v1beta1"
13+
group: "tekton.dev"
14+
plural: "pipelines"
15+
- apiVersion: v1beta1
16+
group: tekton.dev
17+
plural: pipelineruns
18+
- apiVersion: v1beta1
19+
group: tekton.dev
20+
plural: taskruns
21+
catalog:
22+
locations:
23+
- type: url
24+
target: https://github.com/janus-qe/nationalparks-py/blob/master/catalog-info.yaml
25+
rules:
26+
- allow: [Component, API, Location, Resource, System, Template, User, Group]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
kind: ClusterRole
2+
apiVersion: rbac.authorization.k8s.io/v1
3+
metadata:
4+
name: rhdh-tekton-plugin
5+
rules:
6+
- apiGroups:
7+
- tekton.dev
8+
resources:
9+
- pipelines
10+
- pipelineruns
11+
- taskruns
12+
verbs:
13+
- get
14+
- list
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
plugins:
2+
- package: ./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic
3+
disabled: false
4+
- package: ./dynamic-plugins/dist/backstage-plugin-kubernetes
5+
disabled: false
6+
- package: ./dynamic-plugins/dist/backstage-community-plugin-tekton
7+
disabled: false
8+
pluginConfig:
9+
dynamicPlugins:
10+
frontend:
11+
backstage-community.plugin-tekton:
12+
mountPoints:
13+
- mountPoint: entity.page.ci/cards
14+
importName: TektonCI
15+
config:
16+
layout:
17+
gridColumn: 1 / -1
18+
if:
19+
allOf:
20+
- isTektonCIAvailable
Lines changed: 203 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
# Install Red Hat OpenShift Pipelines operator if not present
2+
set -e
3+
4+
wait_for_tekton_crds() {
5+
local timeout_sec=${1:-180} interval_sec=${2:-5}
6+
local cli="oc"
7+
command -v oc &>/dev/null || cli="kubectl"
8+
local -a crds=( "pipelines.tekton.dev" "pipelineruns.tekton.dev" )
9+
local deadline=$(( SECONDS + timeout_sec ))
10+
while (( SECONDS < deadline )); do
11+
local ok=1
12+
for crd in "${crds[@]}"; do
13+
if ! "${cli}" get crd "${crd}" &>/dev/null; then
14+
ok=0
15+
break
16+
fi
17+
done
18+
if (( ok )); then
19+
echo "Tekton CRDs are ready."
20+
return 0
21+
fi
22+
echo "Waiting for Tekton CRDs (${crds[*]})..."
23+
sleep "${interval_sec}"
24+
done
25+
echo "Timeout waiting for Tekton CRDs. Ensure OpenShift Pipelines operator is installed." >&2
26+
return 1
27+
}
28+
29+
wait_for_tekton_pipelines_webhook() {
30+
local namespace="openshift-pipelines"
31+
local selector="app=tekton-pipelines-webhook"
32+
local timeout="300s"
33+
34+
echo "[CI] Waiting for tekton-pipelines-webhook to be Ready..."
35+
36+
# Attempt to wait for the Ready condition
37+
if ! oc wait --for=condition=Ready pod -l "$selector" -n "$namespace" --timeout="$timeout"; then
38+
echo "[CI] ERROR: Webhook failed to become ready within $timeout"
39+
40+
echo "[CI] --- Pod Status ---"
41+
oc get pods -n "$namespace" -l "$selector"
42+
43+
echo "[CI] --- Pod Diagnosis (oc describe) ---"
44+
oc describe pod -l "$selector" -n "$namespace"
45+
46+
return 1
47+
fi
48+
49+
echo "[CI] Webhook is Ready!"
50+
return 0
51+
}
52+
53+
# Function to verify endpoints exist
54+
check_webhook_endpoints() {
55+
local namespace="openshift-pipelines"
56+
local svc="tekton-pipelines-webhook"
57+
58+
echo "[CI] Checking endpoints for $svc..."
59+
60+
local endpoints=$(oc get endpoints "$svc" -n "$namespace" --no-headers | awk '{print $2}')
61+
62+
if [[ -z "$endpoints" || "$endpoints" == "<none>" ]]; then
63+
echo "[CI] ERROR: No endpoints available for $svc"
64+
return 1
65+
fi
66+
67+
echo "[CI] Endpoints found: $endpoints"
68+
return 0
69+
}
70+
71+
# Wait for conversion webhook service so Pipeline/PipelineRun creation does not fail
72+
wait_for_tekton_webhook() {
73+
local timeout_sec=${1:-120} interval_sec=${2:-5}
74+
local -a namespaces=( "openshift-pipelines" "tekton-pipelines" )
75+
local deadline=$(( SECONDS + timeout_sec ))
76+
while (( SECONDS < deadline )); do
77+
for namespace in "${namespaces[@]}"; do
78+
if oc get service tekton-pipelines-webhook -n "${namespace}" &>/dev/null &&
79+
oc get endpoints tekton-pipelines-webhook -n "${namespace}" &>/dev/null; then
80+
echo "Tekton webhook service is ready (${namespace})."
81+
return 0
82+
fi
83+
done
84+
echo "Waiting for Tekton webhook service..."
85+
sleep "${interval_sec}"
86+
done
87+
echo "Timeout waiting for Tekton webhook service. Ensure Pipelines operator is installed." >&2
88+
echo "Diagnostics (what exists):" >&2
89+
for namespace in "${namespaces[@]}"; do
90+
if oc get namespace "${namespace}" &>/dev/null; then
91+
echo " Namespace ${namespace} exists. Services:" >&2
92+
oc get svc -n "${namespace}" 2>&1 | sed 's/^/ /' >&2
93+
echo " Endpoints:" >&2
94+
oc get endpoints -n "${namespace}" 2>&1 | sed 's/^/ /' >&2
95+
else
96+
echo " Namespace ${namespace} does not exist." >&2
97+
fi
98+
done
99+
return 1
100+
}
101+
102+
checkPipelineOperatorStatus() {
103+
local retries=${1:-10}
104+
local -a namespaces=( "openshift-operators" "tekton-pipelines" )
105+
local -a labels=( "openshift-pipelines-operator" "tekton-pipelines-webhook" )
106+
local idx=0
107+
while [[ "${retries}" -gt 0 ]]; do
108+
while [[ "${idx}" -lt "${#namespaces[@]}" ]]; do
109+
if oc wait --for=condition=ready pod -l app="${labels[$idx]}" -n "${namespaces[$idx]}" --timeout=300s 2>/dev/null &&
110+
oc wait --for=condition=Available deployment/${labels[$idx]} -n "${namespaces[$idx]}" --timeout=300s 2>/dev/null; then
111+
echo "Success: Pod and deployment are ready (${namespaces[$idx]})"
112+
return 0
113+
fi
114+
idx=$(( idx + 1 ))
115+
done
116+
echo "Retrying... (${retries} left)"
117+
retries=$(( retries - 1 ))
118+
sleep 5
119+
idx=0
120+
done
121+
echo "Failed to install Pipelines Operator - Pod timeout"
122+
return 1
123+
}
124+
125+
operator::install_pipelines() {
126+
local OPERATOR_NAMESPACE="openshift-operators"
127+
local display_name="Red Hat OpenShift Pipelines"
128+
129+
if oc get csv -n "${OPERATOR_NAMESPACE}" 2>/dev/null | grep -q "${display_name}"; then
130+
echo "Red Hat OpenShift Pipelines operator is already installed."
131+
checkPipelineOperatorStatus
132+
return $?
133+
fi
134+
135+
echo "Red Hat OpenShift Pipelines operator is not installed. Installing..."
136+
oc apply -f "$(dirname "${BASH_SOURCE[0]}")/pipeline-operator.yaml" -n "${OPERATOR_NAMESPACE}" || return 1
137+
checkPipelineOperatorStatus
138+
return $?
139+
}
140+
141+
# Install Tekton Pipelines (alternative to OpenShift Pipelines for Kubernetes)
142+
operator::install_tekton() {
143+
local display_name="tekton-pipelines-webhook"
144+
145+
if oc get pods -n "tekton-pipelines" 2>/dev/null | grep -q "${display_name}"; then
146+
echo "Tekton Pipelines are already installed."
147+
checkPipelineOperatorStatus
148+
return $?
149+
fi
150+
151+
echo "Tekton Pipelines is not installed. Installing..."
152+
kubectl apply -f https://storage.googleapis.com/tekton-releases/pipeline/latest/release.yaml || return 1
153+
kubectl get crd pipelineruns.tekton.dev -o jsonpath='{.spec.conversion.webhook.clientConfig.service}'
154+
checkPipelineOperatorStatus
155+
return $?
156+
}
157+
158+
# Wait for Active namespace, apply pipeline CRs, grant cluster-reader + rhdh-tekton-plugin to default SA.
159+
# ClusterRoleBinding names must differ: two bindings cannot share the same metadata.name.
160+
operator::grant_default_service_account_cluster_reader_and_tekton() {
161+
local namespace=$1
162+
local config_dir
163+
local phase
164+
local i
165+
166+
if [[ -z "${namespace}" ]]; then
167+
echo "operator::grant_default_service_account_cluster_reader_and_tekton: namespace argument required" >&2
168+
return 1
169+
fi
170+
171+
config_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
172+
173+
for i in $(seq 1 90); do
174+
phase=$(oc get namespace "${namespace}" -o jsonpath='{.status.phase}' 2>/dev/null || true)
175+
[[ "${phase}" == "Active" ]] && break
176+
if [[ "${phase}" == "Terminating" ]]; then
177+
echo "Namespace ${namespace} terminating, waiting for delete..."
178+
oc wait --for=delete "namespace/${namespace}" --timeout=60s 2>/dev/null || true
179+
fi
180+
echo "Waiting for namespace ${namespace} (phase=${phase:-unknown})..."
181+
sleep 2
182+
done
183+
oc wait --for=jsonpath='{.status.phase}=Active' "namespace/${namespace}" --timeout=30s
184+
185+
oc apply -f "${config_dir}/pipeline-tests.yaml" -n "${namespace}"
186+
187+
oc adm policy add-cluster-role-to-user cluster-reader -z default -n "${namespace}" 2>/dev/null \
188+
|| oc create clusterrolebinding "rhdh-${namespace}-cluster-reader-default" \
189+
--clusterrole=cluster-reader --serviceaccount="${namespace}:default" 2>/dev/null \
190+
|| true
191+
oc apply -f "${config_dir}/cluster-role.yaml"
192+
oc create clusterrolebinding "rhdh-${namespace}-tekton-plugin-default" \
193+
--clusterrole=rhdh-tekton-plugin --serviceaccount="${namespace}:default" 2>/dev/null || true
194+
}
195+
196+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
197+
operator::install_pipelines || operator::install_tekton
198+
wait_for_tekton_crds 180 6
199+
wait_for_tekton_webhook 120 5
200+
wait_for_tekton_pipelines_webhook
201+
check_webhook_endpoints
202+
operator::grant_default_service_account_cluster_reader_and_tekton "${1}"
203+
fi
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
apiVersion: operators.coreos.com/v1alpha1
2+
kind: Subscription
3+
metadata:
4+
name: openshift-pipelines-operator
5+
namespace: openshift-operators
6+
spec:
7+
channel: latest
8+
name: openshift-pipelines-operator-rh
9+
source: redhat-operators
10+
sourceNamespace: openshift-marketplace
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
apiVersion: tekton.dev/v1beta1
2+
kind: Pipeline
3+
metadata:
4+
name: hello-world-pipeline
5+
labels:
6+
backstage.io/kubernetes-id: developer-hub
7+
spec:
8+
tasks:
9+
- name: echo-hello-world
10+
taskSpec:
11+
steps:
12+
- name: echo-hello-world
13+
image: ubuntu
14+
script: |
15+
#!/usr/bin/env bash
16+
echo "Hello, World!"
17+
- name: echo-bye
18+
taskSpec:
19+
steps:
20+
- name: echo-goodbye
21+
image: ubuntu
22+
script: |
23+
#!/usr/bin/env bash
24+
echo "Good Bye!"
25+
---
26+
apiVersion: tekton.dev/v1beta1
27+
kind: PipelineRun
28+
metadata:
29+
name: hello-world-pipeline-run
30+
labels:
31+
backstage.io/kubernetes-id: developer-hub
32+
spec:
33+
pipelineRef:
34+
name: hello-world-pipeline

0 commit comments

Comments
 (0)