Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
a7855dc
Add Cypress E2E tests and Jenkinsfile for Renovate Bot evidence colle…
Feb 17, 2026
2368bb0
Update Cypress test environment variables and fix JSON output for Jen…
Feb 17, 2026
3013b90
Add debug logging for environment variables in Renovate Bot tests
Feb 18, 2026
dbcbcd8
Refactor Renovate Bot tests to use template variables for Bitbucket c…
Feb 19, 2026
ef67b09
Update Renovate Bot tests to use string interpolation for Bitbucket c…
Feb 19, 2026
0f921d3
Refactor Renovate Bot tests to use hardcoded credentials for Bitbucke…
Feb 19, 2026
876507a
Fix artifact archiving for Cypress test reports by copying to a new f…
Feb 19, 2026
0888229
Refactor Renovate Bot tests to use environment variables for Bitbucke…
Feb 19, 2026
5a87735
Refactor Renovate Bot tests to use updated environment variable names…
Feb 19, 2026
bba11d5
Update artifact archiving in Jenkinsfile to store Cypress test report…
Feb 19, 2026
8c4b182
Remove hardcoded Bitbucket credentials from steps.yml and update test…
Feb 19, 2026
a11177a
Add Cypress video and screenshot archiving to Jenkins pipeline
Feb 19, 2026
0e64c8a
Refactor Renovate Bot acceptance tests to use Bitbucket Web UI for ve…
Feb 19, 2026
1daa109
Improve PR existence check in Renovate Bot acceptance tests to assert…
Feb 19, 2026
1c9622a
Refactor artifact paths in Jenkinsfile to use 'artifacts/' directory …
Feb 19, 2026
aeb177d
Refactor Renovate Bot tests and streamline evidence upload process in…
Feb 19, 2026
7efdddb
Update Cypress test descriptions and file references in steps.yml for…
Feb 19, 2026
49927b0
Improve visibility check for Renovate CronJob in OpenShift Console ac…
Feb 20, 2026
4072128
Add stage for packaging evidence in Jenkins pipeline and update accep…
Feb 23, 2026
582c03e
Rename Cypress test reports zip file to 'cypress-evidence.zip' in ste…
Feb 23, 2026
a3d331a
Disable Cypress video recording and update evidence packaging in Jenk…
Feb 23, 2026
951057d
Merge branch 'master' into chore/renovate-evidences
Feb 23, 2026
7fd3949
Updated CHANGELOG.md
Feb 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Changelog

## Unreleased
- Add renovate bot functional test evidences ([1146](https://github.com/opendevstack/ods-quickstarters/pull/1149))
- Add renovate bot ([1146](https://github.com/opendevstack/ods-quickstarters/pull/1146))
- Update Quickstarter Tests to Support New Framework Test Capabilities ([#1144](https://github.com/opendevstack/ods-quickstarters/pull/1144))
### Added
Expand Down
117 changes: 117 additions & 0 deletions renovate/testdata/fixtures/renovate-cypress/Jenkinsfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
@Library("ods-jenkins-shared-library@4.x") _

node {
dockerRegistry = env.DOCKER_REGISTRY
cypressRecordKey = env.CYPRESS_RECORD_KEY
agentImageTag = "4.x"
}

odsComponentPipeline(
podContainers: [
containerTemplate(
name: 'jnlp',
image: "${dockerRegistry}/ods/jenkins-agent-nodejs22:${agentImageTag}",
workingDir: '/tmp',
envVars: [
envVar(key: 'CYPRESS_RECORD_KEY', value: cypressRecordKey)
],
resourceRequestCpu: '100m',
resourceLimitCpu: '300m',
resourceRequestMemory: '1Gi',
resourceLimitMemory: '2Gi',
alwaysPullImage: true,
args: '${computer.jnlpmac} ${computer.name}'
)
],
branchToEnvironmentMapping: [
'master': 'dev',
]
) { context ->

def targetDirectory = "${context.projectId}/${context.componentId}/${context.gitBranch.replaceAll('/', '-')}/${context.buildNumber}"

stageInstall(context)
stageTypeCheck(context)
stageTest(context)
odsComponentStageScanWithSonar(context)
stagePackageEvidences(context)

odsComponentStageUploadToNexus(context,
[
distributionFile: 'artifacts/cypress-evidence.zip',
repository: 'leva-documentation',
repositoryType: 'raw',
targetDirectory: "${targetDirectory}"
]
)
}


def stageInstall(def context) {
stage('Install dependencies') {
sh 'npm ci'
}
}

def stageTypeCheck(def context) {
stage('Check types') {
sh 'npx tsc --noEmit'
}
}

def stageTest(def context) {
stage('Functional Tests') {
def bitbucketBaseUrl = env.BITBUCKET_URL ?: "https://bitbucket-${context.projectId}-cd.apps.us-test.ocp.aws.boehringer.com"

withEnv([
"TAGVERSION=${context.tagversion}",
"NEXUS_HOST=${context.nexusHost}",
"OPENSHIFT_PROJECT=${context.targetProject}",
"OPENSHIFT_APP_DOMAIN=${context.getOpenshiftApplicationDomain()}",
"COMMIT_INFO_SHA=${context.gitCommit}",
"BUILD_NUMBER=${context.buildNumber}",
"CYPRESS_VIDEO=false",
"CYPRESS_BITBUCKET_BASE_URL=${bitbucketBaseUrl}",
"CYPRESS_PROJECT_ID=${context.projectId}",
"CYPRESS_OC_CONSOLE_CRONJOB_URL=https://console-openshift-console.${context.getOpenshiftApplicationDomain()}/k8s/ns/${context.targetProject}/cronjobs/renovate-qs/",
"OC_NAMESPACE=${context.targetProject}",
"CRONJOB_NAME=renovate-qs",
]) {
withCredentials([
usernamePassword(credentialsId: "${context.projectId}-cd-cd-user-with-password", passwordVariable: 'CYPRESS_BITBUCKET_PASSWORD', usernameVariable: 'CYPRESS_BITBUCKET_USERNAME')
]) {
sh 'mkdir -p artifacts'
def status = sh(script: 'npm run e2e', returnStatus: true)
sh 'npm run combine:reports'
junit(testResults:'build/test-results/*.xml')
stash(name: "installation-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/installation-junit.xml', allowEmpty: true)
stash(name: "integration-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/integration-junit.xml', allowEmpty: true)
stash(name: "acceptance-test-reports-junit-xml-${context.componentId}-${context.buildNumber}", includes: 'build/test-results/acceptance-junit.xml', allowEmpty: true)

sh 'npm run generate:pdf'

if (status != 0) {
unstable "Some tests have failed or encountered errors. Please check the logs for more details."
}
}
}
}
}

def stagePackageEvidences(def context) {
stage('Package Evidences') {
sh '''
mkdir -p artifacts/evidence
if [ -d build/test-results/mochawesome/pdf ]; then
cp -r build/test-results/mochawesome/pdf artifacts/evidence/test-reports-pdf
fi
if [ -d build/test-results/screenshots ]; then
cp -r build/test-results/screenshots artifacts/evidence/screenshots
fi
find . -name "sonarqube-report-*.pdf" -exec cp {} artifacts/evidence/ \\; 2>/dev/null || true
cd artifacts && zip -r cypress-evidence.zip evidence
rm -f artifacts/sonarqube-report-*.pdf
'''
archiveArtifacts artifacts: 'artifacts/cypress-evidence.zip', fingerprint: true
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/**
* Acceptance Tests for Renovate Bot
*
* Risk: The framework shall, upon execution of the Renovate Bot CronJob,
* automatically scan the consuming project's repositories for outdated
* dependencies and create corresponding Pull Requests in Bitbucket to update them.
*
* These tests navigate the Bitbucket Web UI and the OpenShift Console to verify:
* - The Renovate CronJob is deployed in the -cd namespace (OC Console)
* - A Pull Request was created by the Renovate Bot in the target repository
* - The PR contains the expected onboarding description
* - The PR state is OPEN
* - The PR metadata is correct (branch prefix, target branch, etc.)
* - The renovate.json configuration file is visible in the PR diff
*
* Each test captures a screenshot as visual evidence.
*/

describe('Renovate Bot Acceptance Tests - Pull Request Creation Verification', () => {
const bitbucketBaseUrl = "{{.BITBUCKET_URL}}";
const projectId = "{{.ProjectID}}";
const username = Cypress.env("BITBUCKET_USERNAME");
const password = Cypress.env("BITBUCKET_PASSWORD");
const targetRepo = `${projectId}-python-test-renovate`;
const repoUrl = `${bitbucketBaseUrl}/projects/${projectId}/repos/${targetRepo}`;

beforeEach(() => {
cy.session('bitbucket-login', () => {
cy.request({
method: 'POST',
url: `${bitbucketBaseUrl}/login`,
form: true,
body: {
j_username: username,
j_password: password,
},
followRedirect: true,
});
});
});

it('Should show the Renovate CronJob in the OpenShift Console', () => {
const ocNamespace = Cypress.env("OC_NAMESPACE") || `${projectId}-cd`;
const cronJobName = Cypress.env("CRONJOB_NAME") || "renovate-qs";
cy.exec(`oc get cronjob ${cronJobName} -n ${ocNamespace} -o json`, { failOnNonZeroExit: false }).then(({ code, stdout, stderr }) => {
expect(code).to.eq(0);
const cronjob = JSON.parse(stdout);
expect(cronjob).to.have.property('metadata');
expect(cronjob.metadata.name).to.eq(cronJobName);
cy.writeFile('build/test-results/screenshots/renovate-acceptance.spec.cy.ts/acceptance-01-oc-cronjob.json', JSON.stringify(cronjob, null, 2));
});
});

it('Should navigate to the Pull Requests page and see at least one PR', () => {
cy.visit(`${repoUrl}/pull-requests`);
cy.url().should('include', '/pull-requests');
cy.get('#content', { timeout: 15000 }).should('be.visible');
cy.get('#content a[href*="/pull-requests/"]:visible', { timeout: 15000 })
.its('length')
.should('be.greaterThan', 0);
cy.screenshot('acceptance-02-pull-requests-exist');
});

it('Should verify the Pull Request contains the Renovate activation message', () => {
cy.visit(`${repoUrl}/pull-requests/1/overview`);
cy.get('#content', { timeout: 15000 }).should('be.visible');
cy.contains('To activate Renovate, merge this Pull Request', { timeout: 15000 }).should('be.visible');
cy.screenshot('acceptance-03-pr-activate-renovate-message');
});

it('Should navigate to the PR diff and show the renovate.json configuration file', () => {
cy.visit(`${repoUrl}/pull-requests/1/diff#renovate.json`);
cy.url().should('include', '/diff');
cy.get('#content', { timeout: 30000 }).should('be.visible');
cy.contains('renovate.json', { timeout: 30000 }).should('be.visible');
cy.wait(2000);
cy.screenshot('acceptance-04-pr-diff-renovate-json');
});

it('Should navigate to branches and verify a renovate/ branch exists', () => {
cy.visit(`${repoUrl}/branches`);
cy.get('#content', { timeout: 15000 }).should('be.visible');
cy.contains('master', { timeout: 15000 }).should('be.visible');
cy.contains('renovate/', { timeout: 15000 }).should('be.visible');
cy.screenshot('acceptance-05-branches-with-renovate');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* Installation Tests for Renovate Bot
*
* Risk: The framework shall automatically create a dedicated Bitbucket repository
* within the consuming project upon provisioning of the Renovate Bot component,
* including the configuration files and predefined configuration settings.
*
* These tests verify through the Bitbucket API that:
* - The renovate-qs repository exists in the project
* - The repository contains the expected configuration files
* - The configmap with Renovate settings was applied
*/

describe('Renovate Bot Installation Tests - Bitbucket Repository Verification', () => {
const bitbucketBaseUrl = "{{.BITBUCKET_URL}}";
const projectId = "{{.ProjectID}}";
const username = Cypress.env("BITBUCKET_USERNAME");
const password = Cypress.env("BITBUCKET_PASSWORD");

const authHeader = `Basic ${btoa(`${username}:${password}`)}`;
const apiBase = `${bitbucketBaseUrl}/rest/api/1.0/projects/${projectId}`;


it('Should have the renovate-qs repository created in the project', () => {
const requestUrl = `${apiBase}/repos/${projectId}-renovate-qs`;
cy.request({
method: 'GET',
url: requestUrl,
headers: { Authorization: authHeader },
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.eq(200);
expect(response.body.slug).to.eq(`${projectId}-renovate-qs`.toLowerCase());
cy.screenshot('installation-01-repository-exists');
});
});

it('Should have the python-test-renovate repository created for testing', () => {
const requestUrl = `${apiBase}/repos/${projectId}-python-test-renovate`;
cy.request({
method: 'GET',
url: requestUrl,
headers: { Authorization: authHeader },
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.eq(200);
expect(response.body.slug).to.eq(`${projectId}-python-test-renovate`.toLowerCase());
cy.screenshot('installation-02-python-test-repo-exists');
});
});

it('Should have the Jenkinsfile in the renovate-qs repository', () => {
const requestUrl = `${apiBase}/repos/${projectId}-renovate-qs/browse/Jenkinsfile`;
cy.request({
method: 'GET',
url: requestUrl,
headers: { Authorization: authHeader },
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.eq(200);
const content = response.body.lines?.map((l: any) => l.text).join('\n') || '';
expect(content).to.contain('odsComponentPipeline');
cy.screenshot('installation-03-jenkinsfile-present');
});
});

it('Should have the sonar-project.properties in the renovate-qs repository', () => {
const requestUrl = `${apiBase}/repos/${projectId}-renovate-qs/browse/sonar-project.properties`;
cy.request({
method: 'GET',
url: requestUrl,
headers: { Authorization: authHeader },
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.eq(200);
cy.screenshot('installation-04-sonar-properties-present');
});
});

it('Should have the chart templates directory in the renovate-qs repository', () => {
const requestUrl = `${apiBase}/repos/${projectId}-renovate-qs/browse/chart/templates`;
cy.request({
method: 'GET',
url: requestUrl,
headers: { Authorization: authHeader },
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.eq(200);
cy.screenshot('installation-05-chart-templates-directory');
});
});

it('Should have the configmap.yaml with Renovate configuration', () => {
const requestUrl = `${apiBase}/repos/${projectId}-renovate-qs/browse/chart/templates/configmap.yaml`;
cy.request({
method: 'GET',
url: requestUrl,
headers: { Authorization: authHeader },
failOnStatusCode: false,
}).then((response) => {
expect(response.status).to.eq(200);
const content = response.body.lines?.map((l: any) => l.text).join('\n') || '';
expect(content).to.contain('renovateconfigjs');
expect(content).to.contain('repositories');
cy.screenshot('installation-06-configmap-content');
});
});
});
Loading