This commit is contained in:
Med Mouine 2024-04-18 10:23:04 -04:00
parent aab6410176
commit 089a1cd890
19385 changed files with 147197 additions and 230 deletions

View File

@ -4,5 +4,4 @@
node_modules
packages/*/src
packages/*/node_modules
plugins
*.local.yaml

4
.husky/post-checkout Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
./.husky/scripts/sync-node-modules

4
.husky/post-merge Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
./.husky/scripts/sync-node-modules

4
.husky/post-rewrite Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
./.husky/scripts/sync-node-modules

4
.husky/pre-commit Executable file
View File

@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npm run lint-staged

View File

@ -0,0 +1,18 @@
#!/bin/bash
#
# Copyright (c) 2023 Red Hat, Inc.
# This program and the accompanying materials are made
# available under the terms of the Eclipse Public License 2.0
# which is available at https://www.eclipse.org/legal/epl-2.0/
#
# SPDX-License-Identifier: EPL-2.0
#
# script to perform yarn install if package.json has changed
# triggered by post-checkout, post-merge, post-rewrite hooks
#shellcheck disable=SC1083
changed_files="$(git diff-tree -r --name-only --no-commit-id HEAD@{1} HEAD)"
if [[ $changed_files == *"package.json"* ]]; then
eval "yarn install"
fi

6
.ibm/OWNERS Normal file
View File

@ -0,0 +1,6 @@
reviewers:
- josephca
- rnapoles-rh
approvers:
- josephca
- rnapoles-rh

82
.ibm/images/Dockerfile Normal file
View File

@ -0,0 +1,82 @@
FROM mcr.microsoft.com/playwright:v1.40.0-jammy
ENV CI=1 \
QT_X11_NO_MITSHM=1 \
_X11_NO_MITSHM=1 \
_MITSHM=0 \
NODE_PATH=/usr/local/lib/node_modules
# Define Helm and OpenShift CLI (oc) versions
ENV HELM_VERSION="v3.12.3"
ENV OC_VERSION="4.14.3"
ARG CI_XBUILD
# should be root user
RUN echo "whoami: $(whoami)" \
# command "id" should print:
# uid=0(root) gid=0(root) groups=0(root)
# which means the current user is root
&& id \
&& npm install -g typescript \
# give every user read access to the "/root" folder where the binary is cached
# we really only need to worry about the top folder, fortunately
&& ls -la /root \
&& chmod 755 /root \
# always grab the latest Yarn
# otherwise the base image might have old versions
# NPM does not need to be installed as it is already included with Node.
&& npm i -g yarn@latest \
# Show where Node loads required modules from
&& node -p 'module.paths'
# plus Electron and bundled Node versions
RUN echo " node version: $(node -v) \n" \
"npm version: $(npm -v) \n" \
"yarn version: $(yarn -v) \n" \
"typescript version: $(tsc -v) \n" \
"debian version: $(cat /etc/debian_version) \n" \
"user: $(whoami) \n"
RUN curl -fsSL https://clis.cloud.ibm.com/install/linux | sh && \
curl -sLO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl && \
chmod +x kubectl && \
mv kubectl /usr/local/bin/ && \
apt-get update -y && \
apt-get install -y sshpass jq colorized-logs && \
rm -rf /var/lib/apt/lists/*
# Set Go version and the expected SHA256 hash for verification
ENV GO_VERSION 1.19
ENV GO_SHA256 464b6b66591f6cf055bc5df90a9750bf5fbc9d038722bb84a9d56a2bea974be6
# Install Go
RUN apt-get update && \
apt-get install -y curl && \
curl -LO "https://golang.org/dl/go${GO_VERSION}.linux-amd64.tar.gz" && \
echo "${GO_SHA256} go${GO_VERSION}.linux-amd64.tar.gz" | sha256sum -c - && \
tar -C /usr/local -xzf go${GO_VERSION}.linux-amd64.tar.gz && \
rm go${GO_VERSION}.linux-amd64.tar.gz && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# Install Helm
RUN curl -fsSL -o /tmp/helm.tar.gz "https://get.helm.sh/helm-${HELM_VERSION}-linux-amd64.tar.gz" \
&& tar -xzvf /tmp/helm.tar.gz -C /tmp \
&& mv /tmp/linux-amd64/helm /usr/local/bin/helm \
&& rm -rf /tmp/*
# Install OpenShift CLI (oc)
RUN curl -fsSL -o /tmp/openshift-client-linux.tar.gz "https://mirror.openshift.com/pub/openshift-v4/clients/ocp/${OC_VERSION}/openshift-client-linux-${OC_VERSION}.tar.gz" \
&& tar -xzvf /tmp/openshift-client-linux.tar.gz -C /usr/local/bin oc kubectl \
&& rm -rf /tmp/*
# Set environment variables to make Go work correctly
ENV GOPATH /go
ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH
RUN go install github.com/kadel/pr-commenter@latest && \
ibmcloud plugin install -f cloud-object-storage && \
ibmcloud plugin install -f kubernetes-service
WORKDIR /tmp/

1
.ibm/images/README Normal file
View File

@ -0,0 +1 @@
This Dockerfile creates an image to be used by the IBM Cloud pipelines

View File

@ -0,0 +1,29 @@
kind: Secret
apiVersion: v1
metadata:
name: rhdh-secrets
data:
# the followings are place holders with dummy values that will be overwritten by CI
GITHUB_APP_APP_ID: Mzc2ODY2
GITHUB_APP_CLIENT_ID: SXYxLjdiZDNlZDFmZjY3MmY3ZDg=
GITHUB_APP_PRIVATE_KEY: dGVtcA==
GITHUB_APP_CLIENT_SECRET: dGVtcA==
GITHUB_APP_WEBHOOK_URL: aHR0cHM6Ly9zbWVlLmlvL0NrRUNLYVgwNzhyZVhobEpEVzA=
GITHUB_APP_WEBHOOK_SECRET: dGVtcA==
GITHUB_URL: aHR0cHM6Ly9naXRodWIuY29t
GITHUB_ORG: amFudXMtcWU=
K8S_CLUSTER_NAME: Y2k1aGp2ZmYwMG8yZzY2OXZxOGc=
K8S_CLUSTER_API_SERVER_URL: aHR0cHM6Ly9jMTE0LWUuZXUtZGUuY29udGFpbmVycy5jbG91ZC5pYm0uY29tOjMxNTA2
K8S_SERVICE_ACCOUNT_TOKEN: dGVtcA==
OCM_CLUSTER_URL: aHR0cHM6Ly9jMTE1LWUuZXUtZGUuY29udGFpbmVycy5jbG91ZC5pYm0uY29tOjMxODM2
OCM_CLUSTER_TOKEN: dGVtcA==
KEYCLOAK_BASE_URL: aHR0cHM6Ly9rZXljbG9hay1rZXljbG9hay5iYWNrc3RhZ2Utb3MtMi1ldS1kZS0yLWJ4LWM3NGIzZWQ0NGNlODY5NDlmNTAxYWVmYjJkYjgwNjUyLTAwMDAuZXUtZGUuY29udGFpbmVycy5hcHBkb21haW4uY2xvdWQ=
KEYCLOAK_LOGIN_REALM: bXlyZWFsbQ==
KEYCLOAK_REALM: bXlyZWFsbQ==
KEYCLOAK_CLIENT_ID: bXljbGllbnQ=
KEYCLOAK_CLIENT_SECRET: dGVtcA==
ACR_SECRET: dGVtcA==
DH_TARGET_URL: aHR0cDovL3Rlc3QtYmFja3N0YWdlLWN1c3RvbWl6YXRpb24tcHJvdmlkZXItc2hvd2Nhc2UuYmFja3N0YWdlLW9zLTItZXUtZGUtMi1ieC1jNzRiM2VkNDRjZTg2OTQ5ZjUwMWFlZmIyZGI4MDY1Mi0wMDAwLmV1LWRlLmNvbnRhaW5lcnMuYXBwZG9tYWluLmNsb3Vk
GOOGLE_CLIENT_ID: dGVtcA==
GOOGLE_CLIENT_SECRET: dGVtcA==
type: Opaque

View File

@ -0,0 +1,7 @@
apiVersion: v1
kind: Secret
metadata:
name: rhdh-k8s-plugin-secret
annotations:
kubernetes.io/service-account.name: rhdh-k8s-plugin
type: kubernetes.io/service-account-token

View File

@ -0,0 +1,70 @@
# Save the logs from the file passed as parameter #1
# and send a message to GitHub PR using parameter #2 as name of test
#
# Env vars:
# IBM_RESOURCE_GROUP: Resource group of the Cloud ObjectStorage
# IBM_COS: Cloud Object Storage containing the bucket on which to save logs
# IBM_BUCKET: Bucket name on which to save logs
save_logs() {
LOGFILE="$1"
NAME="$2"
RESULT="$3"
ansi2html <"/tmp/${LOGFILE}" >"/tmp/${LOGFILE}.html"
# Create a tarball of the playwright-report directory
tar -czvf /tmp/${LOGFILE}-report.tar.gz playwright-report/
CRN=$(ibmcloud resource service-instance ${IBM_COS} --output json | jq -r .[0].guid)
ibmcloud cos config crn --crn "${CRN}"
ibmcloud cos upload --bucket "${IBM_BUCKET}" --key "${LOGFILE}.html" --file "/tmp/${LOGFILE}.html" --content-type "text/html; charset=UTF-8"
ibmcloud cos upload --bucket "${IBM_BUCKET}" --key "${LOGFILE}-report.tar.gz" --file "/tmp/${LOGFILE}-report.tar.gz" --content-type "application/gzip"
# Loop through each file in the e2e-tests/playwright-report directory
find playwright-report -type f | while read FILE; do
# Extract the file path relative to the directory to maintain the structure in COS
RELATIVE_PATH=${FILE#$DIRECTORY_TO_UPLOAD}
# Upload the file
ibmcloud cos upload --bucket "${IBM_BUCKET}" --key "${LOGFILE}-report/${RELATIVE_PATH}" --file "${FILE}"
done
BASE_URL="https://s3.${IBM_REGION}.cloud-object-storage.appdomain.cloud/${IBM_BUCKET}"
if [[ $RESULT == "0" ]]; then
STATUS="successfully"
else
STATUS="with errors"
fi
cat <<EOF | pr-commenter -key-from-env-var ROBOT_KEY -application-id=${GITHUB_APP_PR_COMMENTER_ID} -pr-comment=${GIT_PR_NUMBER} -repository=${GITHUB_REPOSITORY_NAME} -org=${GITHUB_ORG_NAME}
${NAME} on commit ${GIT_COMMIT} finished **${STATUS}**.
View [test log](${BASE_URL}/${LOGFILE}.html)
View [Playwright report](${BASE_URL}/${LOGFILE}-report/playwright-report/index.html)
Download [Playwright report](${BASE_URL}/${LOGFILE}-report.tar.gz)
EOF
}
skip_if_only() {
echo "Checking if tests need to be executed..."
NAMES=$(git diff --merge-base --name-only main)
for change in ${NAMES}; do
skip $change
if [[ $? == 0 ]]; then
return
fi
done
echo " => Skipping the tests."
exit 0
}
skip() {
SKIP_IF_ONLY="docs/ CONTRIBUTING.md OWNERS README.md USAGE_DATA.md scripts/ .github/ .threatmodel/ ui/"
change=$1
for skip in ${SKIP_IF_ONLY}; do
if [[ "${change}" == "${skip}"* ]]; then
echo " - ${change} is ${skip}*"
return 1
fi
done
echo " - $change not in $SKIP_IF_ONLY"
return 0
}

View File

@ -0,0 +1,108 @@
#!/bin/bash
LOGFILE="pr-${GIT_PR_NUMBER}-kubernetes-tests-${BUILD_NUMBER}"
echo "Log file: ${LOGFILE}"
# source ./.ibm/pipelines/functions.sh
# install the latest ibmcloud cli on Linux
install_ibmcloud() {
if [[ -x "$(command -v ibmcloud)" ]]; then
echo "ibmcloud is already installed."
else
curl -fsSL https://clis.cloud.ibm.com/install/linux | sh
echo "the latest ibmcloud cli installed successfully."
fi
}
# Call the function to install oc
install_ibmcloud
ibmcloud version
ibmcloud config --check-version=false
ibmcloud plugin install -f container-registry
ibmcloud plugin install -f kubernetes-service
ibmcloud login -r "${IBM_REGION}" -g "${IBM_RSC_GROUP}" --apikey "${SERVICE_ID_API_KEY}"
ibmcloud ks cluster config --cluster "${IKS_CLUSTER_ID}"
install_kubectl() {
if [[ -x "$(command -v kubectl)" ]]; then
echo "kubectl is already installed."
else
# install kubectl
curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" \
&& chmod +x kubectl \
&& mv kubectl /usr/local/bin/
echo "kubectl installed successfully."
fi
}
# Call the function to install kubectl
install_kubectl
kubectl version
kubectl config current-context
install_helm() {
if [[ -x "$(command -v helm)" ]]; then
echo "Helm is already installed."
else
echo "Installing Helm 3 client"
WORKING_DIR=$(pwd)
mkdir ~/tmpbin && cd ~/tmpbin
HELM_INSTALL_DIR=$(pwd)
curl -sL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash -f
export PATH=${HELM_INSTALL_DIR}:$PATH
cd $WORKING_DIR
echo "helm client installed successfully."
fi
}
install_helm
# check installed helm version
helm version
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add backstage https://backstage.github.io/charts
helm repo add janus-idp https://janus-idp.github.io/helm-backstage
helm repo update
helm upgrade -i backstage backstage/backstage -n backstage -f ./helm/values-k8s-ingress.yaml --wait
echo "Waiting for backstage deployment..."
sleep 45
kubectl get pods -n backstage
kubectl port-forward -n backstage svc/backstage 7007:7007 &
# Store the PID of the background process
PID=$!
sleep 15
# Check if Backstage is up and running
BACKSTAGE_URL="http://localhost:7007"
BACKSTAGE_URL_RESPONSE=$(curl -Is "$BACKSTAGE_URL" | head -n 1)
echo "$BACKSTAGE_URL_RESPONSE"
cd $WORKING_DIR/e2e-tests
yarn install
Xvfb :99 &
export DISPLAY=:99
# yarn cypress run --headless --browser chrome
yarn run cypress:run
pkill Xvfb
cd $WORKING_DIR
# Send Ctrl+C to the process
kill -INT $PID
helm uninstall backstage -n backstage
rm -rf ~/tmpbin

View File

@ -0,0 +1,6 @@
#!/bin/sh
# fail if some commands fails
set -e
# show commands
set -x
echo "Place holder to run openshift-ci-tests"

271
.ibm/pipelines/openshift-tests.sh Executable file
View File

@ -0,0 +1,271 @@
#!/bin/sh
set -e
LOGFILE="pr-${GIT_PR_NUMBER}-openshift-tests-${BUILD_NUMBER}"
TEST_NAME="backstage-showcase Tests"
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cleanup() {
echo "Cleaning up before exiting"
# leave the namespace for debugging purpose. A new PR will refresh the namespace anyways.
# helm uninstall ${RELEASE_NAME} -n ${NAME_SPACE}
# oc delete namespace ${NAME_SPACE}
rm -rf ~/tmpbin
}
trap cleanup EXIT
add_helm_repos() {
helm version
declare -a repos=("bitnami=https://charts.bitnami.com/bitnami" "backstage=https://backstage.github.io/charts" "rhdh-chart=https://redhat-developer.github.io/rhdh-chart")
for repo in "${repos[@]}"; do
key="${repo%%=*}"
value="${repo##*=}"
if ! helm repo list | grep -q "^$key"; then
helm repo add "$key" "$value"
else
echo "Repository $key already exists - updating repository instead."
fi
done
helm repo update
}
install_ibmcloud() {
if [[ -x "$(command -v ibmcloud)" ]]; then
echo "ibmcloud is already installed."
else
curl -fsSL https://clis.cloud.ibm.com/install/linux | sh
echo "the latest ibmcloud cli installed successfully."
fi
}
install_oc() {
if [[ -x "$(command -v oc)" ]]; then
echo "oc is already installed."
else
curl -LO https://mirror.openshift.com/pub/openshift-v4/clients/oc/latest/linux/oc.tar.gz
tar -xf oc.tar.gz
mv oc /usr/local/bin/
rm oc.tar.gz
echo "oc installed successfully."
fi
}
install_helm() {
if [[ -x "$(command -v helm)" ]]; then
echo "Helm is already installed."
else
echo "Installing Helm 3 client"
mkdir ~/tmpbin && cd ~/tmpbin
HELM_INSTALL_DIR=$(pwd)
curl -sL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash -f
export PATH=${HELM_INSTALL_DIR}:$PATH
echo "helm client installed successfully."
fi
}
uninstall_helmchart() {
if helm list -n ${NAME_SPACE} | grep -q ${RELEASE_NAME}; then
echo "Chart already exists. Removing it before install."
helm uninstall ${RELEASE_NAME} -n ${NAME_SPACE}
fi
}
configure_namespace() {
if oc get namespace ${NAME_SPACE} >/dev/null 2>&1; then
echo "Namespace ${NAME_SPACE} already exists! refreshing namespace"
oc delete namespace ${NAME_SPACE}
fi
oc create namespace ${NAME_SPACE}
oc config set-context --current --namespace=${NAME_SPACE}
}
apply_yaml_files() {
local dir=$1
# Update namespace and other configurations in YAML files
local files=("$dir/resources/service_account/service-account-rhdh.yaml"
"$dir/resources/cluster_role_binding/cluster-role-binding-k8s.yaml"
"$dir/resources/cluster_role_binding/cluster-role-binding-ocm.yaml"
"$dir/resources/deployment/deployment-test-app-component.yaml"
"$dir/auth/secrets-rhdh-secrets.yaml")
for file in "${files[@]}"; do
sed -i "s/namespace:.*/namespace: $NAME_SPACE/g" "$file"
done
sed -i "s/backstage.io\/kubernetes-id:.*/backstage.io\/kubernetes-id: $K8S_PLUGIN_ANNOTATION/g" "$dir/resources/deployment/deployment-test-app-component.yaml"
for key in GITHUB_APP_APP_ID GITHUB_APP_CLIENT_ID GITHUB_APP_PRIVATE_KEY GITHUB_APP_CLIENT_SECRET GITHUB_APP_WEBHOOK_URL GITHUB_APP_WEBHOOK_SECRET KEYCLOAK_CLIENT_SECRET OCM_CLUSTER_TOKEN ACR_SECRET GOOGLE_CLIENT_ID GOOGLE_CLIENT_SECRET; do
sed -i "s/$key:.*/$key: ${!key}/g" "$dir/auth/secrets-rhdh-secrets.yaml"
done
oc apply -f $dir/resources/service_account/service-account-rhdh.yaml --namespace=${NAME_SPACE}
oc apply -f $dir/auth/service-account-rhdh-secret.yaml --namespace=${NAME_SPACE}
oc apply -f $dir/auth/secrets-rhdh-secrets.yaml --namespace=${NAME_SPACE}
oc apply -f $dir/resources/deployment/deployment-test-app-component.yaml --namespace=${NAME_SPACE}
oc new-app https://github.com/janus-qe/test-backstage-customization-provider --namespace=${NAME_SPACE}
oc expose svc/test-backstage-customization-provider --namespace=${NAME_SPACE}
oc apply -f $dir/resources/cluster_role/cluster-role-k8s.yaml
oc apply -f $dir/resources/cluster_role_binding/cluster-role-binding-k8s.yaml
oc apply -f $dir/resources/cluster_role/cluster-role-ocm.yaml
oc apply -f $dir/resources/cluster_role_binding/cluster-role-binding-ocm.yaml
# obtain K8S_SERVICE_ACCOUNT_TOKEN, K8S_CLUSTER_NAME, K8S_CLUSTER_API_SERVER_URL and add them to secrets-rhdh-secrets.yaml
oc get secret rhdh-k8s-plugin-secret -o yaml >$dir/auth/service-account-rhdh-token.yaml
TOKEN=$(grep 'token:' $dir/auth/service-account-rhdh-token.yaml | awk '{print $2}')
sed -i "s/K8S_SERVICE_ACCOUNT_TOKEN:.*/K8S_SERVICE_ACCOUNT_TOKEN: $TOKEN/g" $dir/auth/secrets-rhdh-secrets.yaml
sed -i "s/K8S_CLUSTER_API_SERVER_URL:.*/K8S_CLUSTER_API_SERVER_URL: $ENCODED_API_SERVER_URL/g" $dir/auth/secrets-rhdh-secrets.yaml
sed -i "s/K8S_CLUSTER_NAME:.*/K8S_CLUSTER_NAME: $ENCODED_CLUSTER_NAME/g" $dir/auth/secrets-rhdh-secrets.yaml
# Cleanup temp file
rm $dir/auth/service-account-rhdh-token.yaml
# oc apply -f $dir/auth/rhdh-quay-pull-secret.yaml --namespace=${NAME_SPACE}
# re-apply with the updated cluster service account token
oc apply -f $dir/auth/secrets-rhdh-secrets.yaml --namespace=${NAME_SPACE}
oc apply -f $dir/resources/config_map/configmap-app-config-rhdh.yaml --namespace=${NAME_SPACE}
oc apply -f $dir/resources/config_map/configmap-rbac-policy-rhdh.yaml --namespace=${NAME_SPACE}
# pipelines (required for tekton)
sleep 20 # wait for Pipeline Operator to be ready
oc apply -f "$dir"/resources/pipeline-run/hello-world-pipeline.yaml
oc apply -f "$dir"/resources/pipeline-run/hello-world-pipeline-run.yaml
}
run_tests() {
cd $DIR/../../e2e-tests
yarn install
yarn playwright install
Xvfb :99 &
export DISPLAY=:99
(
set -e
echo Using PR container image: ${TAG_NAME}
yarn test
) |& tee "/tmp/${LOGFILE}"
RESULT=${PIPESTATUS[0]}
pkill Xvfb
save_logs "${LOGFILE}" "${TEST_NAME}" ${RESULT}
exit ${RESULT}
}
check_backstage_running() {
local url="https://${RELEASE_NAME}-backstage-${NAME_SPACE}.${K8S_CLUSTER_ROUTER_BASE}"
# Maximum number of attempts to check URL
local max_attempts=30
# Time in seconds to wait
local wait_seconds=30
echo "Checking if Backstage is up and running at $url" | tee "/tmp/${LOGFILE}"
for ((i=1; i<=max_attempts; i++)); do
# Get the status code
local http_status=$(curl --insecure -I -s "$url" | grep HTTP | awk '{print $2}')
# Check if the status code is 200
if [[ $http_status -eq 200 ]]; then
echo "Backstage is up and running!"
export BASE_URL=$url
echo "######## BASE URL ########"
echo "$BASE_URL"
return 0
else
echo "Attempt $i of $max_attempts: Backstage not yet available (HTTP Status: $http_status)" | tee -a "/tmp/${LOGFILE}"
sleep $wait_seconds
fi
done
echo "Failed to reach Backstage at $BASE_URL after $max_attempts attempts." | tee -a "/tmp/${LOGFILE}"
save_logs "${LOGFILE}" "${TEST_NAME}" 1
return 1
}
# Required for tekton plugin
# Red Hat OpenShift Pipelines is a cloud-native continuous integration and delivery (CI/CD)
# Solution for building pipelines using Tekton.
installPipelinesOperator() {
local dir=$1
DISPLAY_NAME="Red Hat OpenShift Pipelines"
if oc get csv -n "openshift-operators" | grep -q "$DISPLAY_NAME"; then
echo "Red Hat OpenShift Pipelines operator is already installed."
else
echo "Red Hat OpenShift Pipelines operator is not installed. Installing..."
oc apply -f "$dir"/resources/pipeline-run/pipelines-operator.yaml
fi
}
main() {
echo "Log file: ${LOGFILE}"
source ./.ibm/pipelines/functions.sh
skip_if_only
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
install_ibmcloud
ibmcloud version
ibmcloud config --check-version=false
ibmcloud plugin install -f container-registry
ibmcloud plugin install -f kubernetes-service
ibmcloud login -r "${IBM_REGION}" -g "${IBM_RSC_GROUP}" --apikey "${SERVICE_ID_API_KEY}"
ibmcloud oc cluster config --cluster "${OPENSHIFT_CLUSTER_ID}"
install_oc
oc version --client
oc login --token=${K8S_CLUSTER_TOKEN} --server=${K8S_CLUSTER_URL}
API_SERVER_URL=$(oc whoami --show-server)
K8S_CLUSTER_ROUTER_BASE=$(oc get route console -n openshift-console -o=jsonpath='{.spec.host}' | sed 's/^[^.]*\.//')
# Encode in Base64
ENCODED_API_SERVER_URL=$(echo "$API_SERVER_URL" | base64)
ENCODED_CLUSTER_NAME=$(echo "my-cluster" | base64)
configure_namespace
installPipelinesOperator $DIR
install_helm
uninstall_helmchart
cd $DIR
apply_yaml_files $DIR
add_helm_repos
echo "Tag name : ${TAG_NAME}"
helm upgrade -i ${RELEASE_NAME} -n ${NAME_SPACE} rhdh-chart/backstage --version ${CHART_VERSION} -f $DIR/value_files/${HELM_CHART_VALUE_FILE_NAME} --set global.clusterRouterBase=${K8S_CLUSTER_ROUTER_BASE} --set upstream.backstage.image.tag=${TAG_NAME}
check_backstage_running
backstage_status=$?
echo "Display pods for verification..."
oc get pods -n ${NAME_SPACE}
if [ $backstage_status -ne 0 ]; then
echo "Backstage is not running. Exiting..."
exit 1
fi
run_tests
}
main

View File

@ -0,0 +1,86 @@
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rhdh-k8s-plugin
rules:
# Base for Kubernetes plugin
- apiGroups:
- ''
resources:
- pods
- pods/log
- services
- configmaps
- limitranges
verbs:
- get
- watch
- list
- apiGroups:
- route.openshift.io
resources:
- routes
verbs:
- get
- list
- apiGroups:
- metrics.k8s.io
resources:
- pods
verbs:
- get
- watch
- list
- apiGroups:
- apps
resources:
- daemonsets
- deployments
- replicasets
- statefulsets
verbs:
- get
- watch
- list
- apiGroups:
- autoscaling
resources:
- horizontalpodautoscalers
verbs:
- get
- watch
- list
- apiGroups:
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- watch
- list
- apiGroups:
- batch
resources:
- jobs
- cronjobs
verbs:
- get
- watch
- list
- apiGroups:
- org.eclipse.che
resources:
- checlusters
verbs:
- get
- list
# Additional permissions for the @janus-idp/backstage-plugin-tekton
- apiGroups:
- tekton.dev
resources:
- pipelines
- pipelineruns
- taskruns
verbs:
- get
- list

View File

@ -0,0 +1,21 @@
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: rhdh-k8s-plugin-ocm
rules:
- apiGroups:
- cluster.open-cluster-management.io
resources:
- managedclusters
verbs:
- get
- watch
- list
- apiGroups:
- internal.open-cluster-management.io
resources:
- managedclusterinfos
verbs:
- get
- watch
- list

View File

@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: rhdh-k8s-plugin
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: rhdh-k8s-plugin
subjects:
- kind: ServiceAccount
name: rhdh-k8s-plugin
namespace: janus-idp-prod

View File

@ -0,0 +1,12 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: rhdh-k8s-plugin-ocm
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: rhdh-k8s-plugin-ocm
subjects:
- kind: ServiceAccount
name: rhdh-k8s-plugin
namespace: janus-idp-prod

View File

@ -0,0 +1,111 @@
kind: ConfigMap
apiVersion: v1
metadata:
name: app-config-rhdh
data:
app-config-rhdh.yaml: |
app:
title: Red Hat Developer Hub
backend:
auth:
keys:
- secret: temp
integrations:
# Plugin: GitHub
github:
- host: github.com
apps:
- appId: ${GITHUB_APP_APP_ID}
clientId: ${GITHUB_APP_CLIENT_ID}
clientSecret: ${GITHUB_APP_CLIENT_SECRET}
webhookUrl: ${GITHUB_APP_WEBHOOK_URL}
webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET}
privateKey: |
${GITHUB_APP_PRIVATE_KEY}
bitbucketServer:
- host: bitbucket.com
apiBaseUrl: temp
username: temp
password: temp
gitlab:
- host: gitlab.com
token: temp
auth:
# see https://backstage.io/docs/auth/ to learn about auth providers
environment: development
providers:
# Plugin: GitHub
github:
development:
clientId: ${GITHUB_APP_CLIENT_ID}
clientSecret: ${GITHUB_APP_CLIENT_SECRET}
google:
development:
clientId: ${GOOGLE_CLIENT_ID}
clientSecret: ${GOOGLE_CLIENT_SECRET}
proxy:
skipInvalidProxies: true
# endpoints: {}
endpoints:
# Other Proxies
# customize developer hub instance
'/developer-hub':
target: ${DH_TARGET_URL}
changeOrigin: true
# Change to "false" in case of using self hosted cluster with a self-signed certificate
secure: false
'/acr/api':
target: 'https://rhdhqetest.azurecr.io/acr/v1/'
changeOrigin: true
headers:
# If you use Bearer Token for authorization, please replace the 'Basic' with 'Bearer' in the following line.
Authorization: '${ACR_SECRET}'
# Change to "false" in case of using self hosted artifactory instance with a self-signed certificate
secure: false
catalog:
import:
entityFilename: catalog-info.yaml
# pullRequestBranchName: rhdh-integration
pullRequestBranchName: backstage-integration
rules:
- allow: [API, Component, Group, Location, Resource, System, Template]
locations:
- type: url
target: https://github.com/janus-idp/backstage-showcase/blob/main/catalog-entities/all.yaml
- type: url
target: https://github.com/redhat-developer/red-hat-developer-hub-software-templates/blob/main/templates.yaml
- type: url
target: https://github.com/janus-qe/acr-catalog/blob/main/catalog-info.yaml
- type: url
target: https://github.com/janus-qe/rhdh-test/blob/main/user.yml
rules:
- allow: [User]
- type: url
target: https://github.com/backstage/backstage/blob/master/packages/catalog-model/examples/acme-corp.yaml
rules:
- allow: [User, Group]
dynatrace:
baseUrl: temp
argocd:
appLocatorMethods:
- type: 'config'
instances:
- name: argoInstance1
url: temp
token: temp
- name: argoInstance2
url: temp
token: temp
permission:
enabled: false # Disabling the permission until we can use RBAC to test the pages using login as Guest.
rbac:
policies-csv-file: './rbac/rbac-policy.csv'
admin:
users:
- name: user:default/rhdh-qe

View File

@ -0,0 +1,20 @@
kind: ConfigMap
apiVersion: v1
metadata:
name: rbac-policy
data:
rbac-policy.csv: |
p, role:default/guests, catalog.entity.create, create, allow
p, role:default/team_a, catalog-entity, read, allow
g, user:xyz/user, role:xyz/team_a
p, role:xyz/team_a, catalog-entity, read, allow
p, role:xyz/team_a, catalog.entity.create, create, allow
p, role:xyz/team_a, catalog.location.create, create, allow
p, role:xyz/team_a, catalog.location.read, read, allow
p, role:default/rbac_admin, kubernetes.proxy, use, allow
p, role:default/rbac_admin, catalog-entity, read, allow
p, role:default/rbac_admin, catalog.entity.create, create, allow
p, role:default/rbac_admin, catalog.location.create, create, allow
p, role:default/rbac_admin, catalog.location.read, read, allow

View File

@ -0,0 +1,29 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: test-app
annotations:
app.openshift.io/vcs-uri: "https://github.com/janus-qe/test-bs-nodejs"
app.openshift.io/vcs-ref: main
labels:
backstage.io/kubernetes-id: developer-hub
app.openshift.io/runtime: perl
spec:
replicas: 2
selector:
matchLabels:
app: test-app
template:
metadata:
labels:
app: test-app
backstage.io/kubernetes-id: developer-hub
spec:
containers:
- name: ubuntu
image: ubuntu
command:
- /bin/sh
args:
- -c
- "tail -f /dev/null"

View File

@ -0,0 +1,10 @@
apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
name: hello-world-pipeline-run
labels:
# this should match https://github.com/janus-qe/nationalparks-py/blob/master/catalog-info.yaml#L10
backstage.io/kubernetes-id: developer-hub
spec:
pipelineRef:
name: hello-world-pipeline

View File

@ -0,0 +1,25 @@
apiVersion: tekton.dev/v1beta1
kind: Pipeline
metadata:
name: hello-world-pipeline
labels:
# this should match https://github.com/janus-qe/nationalparks-py/blob/master/catalog-info.yaml#L10
backstage.io/kubernetes-id: developer-hub
spec:
tasks:
- name: echo-hello-world
taskSpec:
steps:
- name: echo-hello-world
image: ubuntu
script: |
#!/usr/bin/env bash
echo "Hello, World!"
- name: echo-bye
taskSpec:
steps:
- name: echo-goodbye
image: ubuntu
script: |
#!/usr/bin/env bash
echo "Good Bye!"

View File

@ -0,0 +1,10 @@
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: openshift-pipelines-operator
namespace: openshift-operators
spec:
channel: latest
name: openshift-pipelines-operator-rh
source: redhat-operators
sourceNamespace: openshift-marketplace

View File

@ -0,0 +1,5 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: rhdh-k8s-plugin
namespace: janus-idp-prod

View File

@ -0,0 +1,290 @@
global:
dynamic:
# -- Array of YAML files listing dynamic plugins to include with those listed in the `plugins` field.
# Relative paths are resolved from the working directory of the initContainer that will install the plugins (`/opt/app-root/src`).
includes:
# -- List of dynamic plugins included inside the `janus-idp/backstage-showcase` container image, some of which are disabled by default.
# This file ONLY works with the `janus-idp/backstage-showcase` container image.
- 'dynamic-plugins.default.yaml'
# -- List of dynamic plugins, possibly overriding the plugins listed in `includes` files.
# Every item defines the plugin `package` as a [NPM package spec](https://docs.npmjs.com/cli/v10/using-npm/package-spec),
# an optional `pluginConfig` with plugin-specific backstage configuration, and an optional `disabled` flag to disable/enable a plugin
# listed in `includes` files. It also includes an `integrity` field that is used to verify the plugin package [integrity](https://w3c.github.io/webappsec-subresource-integrity/#integrity-metadata-description).
plugins:
- package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic
disabled: false
pluginConfig:
catalog:
providers:
github:
my-test-org:
organization: janus-qe
catalogPath: '/catalog-info.yaml'
schedule:
frequency:
minutes: 1
timeout:
minutes: 1
initialDelay:
seconds: 15
- package: ./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-org-dynamic
disabled: false
- package: ./dynamic-plugins/dist/backstage-plugin-github-issues
disabled: false
- package: ./dynamic-plugins/dist/roadiehq-backstage-plugin-github-pull-requests
disabled: false
- package: ./dynamic-plugins/dist/backstage-plugin-github-actions
disabled: false
- package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-quay
disabled: false
- package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-keycloak-backend-dynamic
disabled: false
- package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-tekton
disabled: false
- package: ./dynamic-plugins/dist/backstage-plugin-kubernetes
disabled: false
- package: ./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic
disabled: false
pluginConfig:
kubernetes:
clusterLocatorMethods:
- clusters:
- authProvider: serviceAccount
name: 'my-cluster'
serviceAccountToken: ${K8S_SERVICE_ACCOUNT_TOKEN}
url: ${K8S_CLUSTER_API_SERVER_URL}
type: config
customResources:
# Add for tekton
- apiVersion: 'v1beta1'
group: 'tekton.dev'
plural: 'pipelines'
- apiVersion: v1beta1
group: tekton.dev
plural: pipelineruns
- apiVersion: v1beta1
group: tekton.dev
plural: taskruns
# Add for topology plugin
- apiVersion: 'v1'
group: 'route.openshift.io'
plural: 'routes'
# Add to view topology code decorators
- group: 'org.eclipse.che'
apiVersion: 'v2'
plural: 'checlusters'
serviceLocatorMethod:
type: multiTenant
# Enable OCM plugins.
- package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-ocm-backend-dynamic
disabled: false
pluginConfig:
catalog:
providers:
ocm:
default:
name: testCluster # Can be any arbitrary name supported by kubernetes
url: ${OCM_CLUSTER_URL}
serviceAccountToken: ${OCM_CLUSTER_TOKEN}
skipTLSVerify: true
owner: janus-authors
- package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-ocm
disabled: false
# Enable tech-radar plugin.
- package: ./dynamic-plugins/dist/backstage-plugin-tech-radar
disabled: false
- package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-acr
disabled: false
- package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-rbac
disabled: true
# this value will be overriden by 'helm install .... --set global.clusterRouterBase=value'
# -- Shorthand for users who do not want to specify a custom HOSTNAME. Used ONLY with the DEFAULT upstream.backstage.appConfig value and with OCP Route enabled.
clusterRouterBase: apps.example.com
# -- Custom hostname shorthand, overrides `global.clusterRouterBase`, `upstream.ingress.host`, `route.host`, and url values in `upstream.backstage.appConfig`
host: ''
# -- Enable service authentication within Backstage instance
auth:
# -- Backend service to service authentication
# <br /> Ref: https://backstage.io/docs/auth/service-to-service-auth/
backend:
# -- Enable backend service to service authentication, unless configured otherwise it generates a secret value
enabled: true
# -- Instead of generating a secret value, refer to existing secret
existingSecret: ''
# -- Instead of generating a secret value, use fo;lowing value
value: ''
# -- Upstream Backstage [chart configuration](https://github.com/backstage/charts/blob/main/charts/backstage/values.yaml)
# @default -- Use Openshift compatible settings
upstream:
nameOverride: backstage
commonLabels:
backstage.io/kubernetes-id: developer-hub
backstage:
image:
pullPolicy: Always
pullSecrets:
- rhdh-pull-secret
# using test image from https://quay.io/repository/janus-idp/backstage-showcase
registry: quay.io
repository: janus-idp/backstage-showcase
tag: next
command: []
# FIXME (tumido): USE POSTGRES_PASSWORD and POSTGRES_USER instead of POSTGRES_ADMIN_PASSWORD
# This is a hack. In {fedora,rhel}/postgresql images, regular user is forbidden
# from creating DBs in runtime. A single DB can be created ahead of time via
# POSTGRESQL_DATABASE env variable (in this case via
# upstream.postgresql.primary.extraEnvVars value), but this doesn't allow us to
# create multiple DBs. Since Backstage requires by default 5 different DBs, we
# can't accommodate that properly.
appConfig:
app:
# Please update to match host in case you don't want to configure hostname via `global.clusterRouterBase` or `global.host`.
baseUrl: 'https://{{- include "janus-idp.hostname" . }}'
backend:
baseUrl: 'https://{{- include "janus-idp.hostname" . }}'
cors:
origin: 'https://{{- include "janus-idp.hostname" . }}'
database:
connection:
password: ${POSTGRESQL_ADMIN_PASSWORD}
user: postgres
auth:
keys:
- secret: ${BACKEND_SECRET}
readinessProbe:
failureThreshold: 3
httpGet:
path: /healthcheck
port: 7007
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 2
timeoutSeconds: 2
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthcheck
port: 7007
scheme: HTTP
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 2
extraEnvVars:
- name: BACKEND_SECRET
valueFrom:
secretKeyRef:
key: backend-secret
name: '{{ include "janus-idp.backend-secret-name" $ }}'
- name: POSTGRESQL_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
key: postgres-password
name: '{{ .Release.Name }}-postgresql'
args:
# This additional `app-config`` file is generated by the initContainer below, and contains the merged configuration of installed dynamic plugins.
- '--config'
- dynamic-plugins-root/app-config.dynamic-plugins.yaml
extraVolumeMounts:
# The initContainer below will install dynamic plugins in this volume mount.
- name: dynamic-plugins-root
mountPath: /opt/app-root/src/dynamic-plugins-root
- name: rbac-policy
mountPath: /opt/app-root/src/rbac
extraVolumes:
# -- Ephemeral volume that will contain the dynamic plugins installed by the initContainer below at start.
# To have more control on underlying storage, the [emptyDir](https://docs.openshift.com/container-platform/4.13/storage/understanding-ephemeral-storage.html)
# could be changed to a [generic ephemeral volume](https://docs.openshift.com/container-platform/4.13/storage/generic-ephemeral-vols.html#generic-ephemeral-vols-procedure_generic-ephemeral-volumes).
- name: dynamic-plugins-root
emptyDir: {}
- name: rbac-policy
configMap:
defaultMode: 420
name: rbac-policy
# Volume that will expose the `dynamic-plugins.yaml` file from the `dynamic-plugins` config map.
# The `dynamic-plugins` config map is created by the helm chart from the content of the `global.dynamic` field.
- name: dynamic-plugins
configMap:
defaultMode: 420
name: dynamic-plugins
optional: true
# Optional volume that allows exposing the `.npmrc` file (through a `dynamic-plugins-npmrc` secret)
# to be used when running `npm pack` during the dynamic plugins installation by the initContainer.
- name: dynamic-plugins-npmrc
secret:
defaultMode: 420
optional: true
secretName: dynamic-plugins-npmrc
initContainers:
- name: install-dynamic-plugins
# -- Image used by the initContainer to install dynamic plugins into the `dynamic-plugins-root` volume mount.
# It could be replaced by a custom image based on this one.
# @default -- `quay.io/janus-idp/backstage-showcase:latest`
image: '{{ include "backstage.image" . }}'
command:
- python
- install-dynamic-plugins.py
- /dynamic-plugins-root
env:
- name: NPM_CONFIG_USERCONFIG
value: /opt/app-root/src/.npmrc.dynamic-plugins
imagePullPolicy: Always
volumeMounts:
- mountPath: /dynamic-plugins-root
name: dynamic-plugins-root
- mountPath: /opt/app-root/src/dynamic-plugins.yaml
name: dynamic-plugins
readOnly: true
subPath: dynamic-plugins.yaml
- mountPath: /opt/app-root/src/.npmrc.dynamic-plugins
name: dynamic-plugins-npmrc
readOnly: true
subPath: .npmrc
workingDir: /opt/app-root/src
installDir: /opt/app-root/src
podAnnotations:
checksum/dynamic-plugins: >-
{{- include "common.tplvalues.render" ( dict "value"
.Values.global.dynamic "context" $) | sha256sum }}
extraAppConfig:
- configMapRef: app-config-rhdh
filename: app-config-rhdh.yaml
extraEnvVarsSecrets:
- rhdh-secrets
postgresql:
enabled: true
postgresqlDataDir: /var/lib/pgsql/data/userdata
image:
registry: quay.io
repository: fedora/postgresql-15
tag: latest
auth:
secretKeys:
adminPasswordKey: postgres-password
userPasswordKey: password
primary:
securityContext:
enabled: false
podSecurityContext:
enabled: false
containerSecurityContext:
enabled: false
persistence:
enabled: true
size: 1Gi
mountPath: /var/lib/pgsql/data
extraEnvVars:
- name: POSTGRESQL_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
key: postgres-password
name: '{{ .Release.Name }}-postgresql'
ingress:
host: '{{ .Values.global.host }}'

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-use-17.5.0-1fae45638828a338291efa0f0c61862db7ee6442-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-utils-4.11.3-232bd86c4ea81dab714f21edad70b7fdf0253942-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-transition-group-4.4.5-e53d4e3f3344da8521489fbef8f2581d42becdd1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-syntax-highlighter-15.5.0-4b3eccc2325fa2ec8eff1e2d6c18fa4a9e07ab20-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-transition-group-4.4.5-e53d4e3f3344da8521489fbef8f2581d42becdd1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-table-core-3.2.5-37b3c665bed3ded6c147ad74adb330bf49efb213-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-nano-css-5.6.1-964120cb1af6cccaa6d0717a473ccd876b34c197-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-styles-4.11.5-19f84457df3aafd956ac863dbe156b1d88e2bbfb-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-core-4.12.4-4ac17488e8fcaf55eb6a7f5efb2a131e10138a73-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-virtualized-auto-sizer-1.0.24-3ebdc92f4b05ad65693b3cc8e7d8dd54924c0227-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@radix-ui-react-slot-1.0.2-a9ff4423eade67f501ffb32ec22064bc9d3099ab-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@rjsf-utils-5.17.1-ad85d503dd15cc9fc49b5d6870534fa2ed8103b0-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-utils-4.11.3-232bd86c4ea81dab714f21edad70b7fdf0253942-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-types-5.1.0-efa1c7a0b0eaa4c7c87ac0390445f0f88b0d88f2-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-transition-group-4.4.5-e53d4e3f3344da8521489fbef8f2581d42becdd1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-linkify-react-4.1.3-461d348b4bdab3fcd0452ae1b5bbc22536395b97-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-transition-group-4.4.5-e53d4e3f3344da8521489fbef8f2581d42becdd1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-universal-interface-0.6.2-5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-version-bridge-1.0.7-8eb52f998d0aef9ceba53fd6dca80a7fa1703534-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-core-plugin-api-1.9.1-3ad8b7ee247198bb59fcd3b146092e4f9512a5de-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-lab-4.0.0-alpha.61-9bf8eb389c0c26c15e40933cc114d4ad85e3d978-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-version-bridge-1.0.7-8eb52f998d0aef9ceba53fd6dca80a7fa1703534-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-utils-4.11.3-232bd86c4ea81dab714f21edad70b7fdf0253942-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-styles-4.11.5-19f84457df3aafd956ac863dbe156b1d88e2bbfb-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-transition-group-4.4.5-e53d4e3f3344da8521489fbef8f2581d42becdd1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-styles-4.11.5-19f84457df3aafd956ac863dbe156b1d88e2bbfb-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@babel-plugin-syntax-top-level-await-7.14.5-c1cfdadc35a646240001f06138247b741c34d94c-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@svgr-babel-preset-6.5.1-b90de7979c8843c5c580c7e2ec71f024b49eb828-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-theme-0.5.2-7908830507a472fca8d6fa8b76362bdb08797bb7-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@mui-types-7.2.14-8a02ac129b70f3d82f2f9b76ded2c8d48e3fc8c9-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-utils-4.11.3-232bd86c4ea81dab714f21edad70b7fdf0253942-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-integration-react-1.1.25-2849e063799b3c2915809ce9785253aefd4dd471-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-universal-interface-0.6.2-5e8d438a01729a4dbbcbeeceb0b86be146fe2b3b-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-double-scrollbar-0.0.15-e915ab8cb3b959877075f49436debfdb04288fe4-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-table-core-3.2.5-37b3c665bed3ded6c147ad74adb330bf49efb213-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-rc-util-5.39.1-7bca4fb55e20add0eef5c23166cd9f9e5f51a8a1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-markdown-8.0.7-c8dbd1b9ba5f1c5e7e5f2a44de465a3caafdf89b-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-transition-group-4.4.5-e53d4e3f3344da8521489fbef8f2581d42becdd1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-utils-4.11.3-232bd86c4ea81dab714f21edad70b7fdf0253942-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-ramda-adjunct-4.1.1-085ca9a7bf19857378eff648f9852b15136dc66f-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-nano-css-5.6.1-964120cb1af6cccaa6d0717a473ccd876b34c197-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-express-promise-router-4.1.1-8fac102060b9bcc868f84d34fbb12fd8fa494291-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-utils-4.11.3-232bd86c4ea81dab714f21edad70b7fdf0253942-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-transition-group-4.4.5-e53d4e3f3344da8521489fbef8f2581d42becdd1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-rc-progress-3.5.1-a3cdfd2fe04eb5c3d43fa1c69e7dd70c73b102ae-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-helmet-6.1.0-a750d5165cb13cf213e44747502652e794468726-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-icons-4.11.3-b0693709f9b161ce9ccde276a770d968484ecff1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-icons-4.11.3-b0693709f9b161ce9ccde276a770d968484ecff1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-icons-4.11.3-b0693709f9b161ce9ccde276a770d968484ecff1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-theme-0.5.2-7908830507a472fca8d6fa8b76362bdb08797bb7-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-core-components-0.14.3-3de6ebe04d31ef6dc53b127b12d76490c7bba749-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-lab-4.0.0-alpha.61-9bf8eb389c0c26c15e40933cc114d4ad85e3d978-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-node-fetch-2.7.0-d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-ts-api-utils-1.3.0-4b490e27129f1e8e686b45cc4ab63714dc60eea1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@mui-types-7.2.14-8a02ac129b70f3d82f2f9b76ded2c8d48e3fc8c9-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-icons-4.11.3-b0693709f9b161ce9ccde276a770d968484ecff1-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@radix-ui-react-primitive-1.0.3-d49ea0f3f0b2fe3ab1cb5667eb03e8b843b914d0-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-nano-css-5.6.1-964120cb1af6cccaa6d0717a473ccd876b34c197-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-core-plugin-api-1.9.1-3ad8b7ee247198bb59fcd3b146092e4f9512a5de-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-react-syntax-highlighter-15.5.0-4b3eccc2325fa2ec8eff1e2d6c18fa4a9e07ab20-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@mui-types-7.2.14-8a02ac129b70f3d82f2f9b76ded2c8d48e3fc8c9-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-core-plugin-api-1.9.1-3ad8b7ee247198bb59fcd3b146092e4f9512a5de-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@emotion-styled-11.11.5-0c5c8febef9d86e8a926e663b2e5488705545dfb-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-core-components-0.14.3-3de6ebe04d31ef6dc53b127b12d76490c7bba749-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-frontend-plugin-api-0.6.3-12a1909fec657eee8a90534fd0b5e3520d719bdb-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-utils-4.11.3-232bd86c4ea81dab714f21edad70b7fdf0253942-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@emotion-react-11.11.4-3a829cac25c1f00e126408fab7f891f00ecc3c1d-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@backstage-version-bridge-1.0.7-8eb52f998d0aef9ceba53fd6dca80a7fa1703534-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-pg-8.11.5-e722b0a5f1ed92931c31758ebec3ddf878dd4128-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-utils-4.11.3-232bd86c4ea81dab714f21edad70b7fdf0253942-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@emotion-use-insertion-effect-with-fallbacks-1.0.1-08de79f54eb3406f9daaf77c76e35313da963963-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@mui-material-5.15.15-e3ba35f50b510aa677cec3261abddc2db7b20b59-integrity

View File

@ -0,0 +1 @@
../../../../Library/Caches/Yarn/v6/npm-@material-ui-styles-4.11.5-19f84457df3aafd956ac863dbe156b1d88e2bbfb-integrity

Some files were not shown because too many files have changed in this diff Show More