Skip to content

Commit 62b986a

Browse files
committed
ci: filter test suites to run based on file changes
Signed-off-by: Saw-jan <[email protected]>
1 parent 565a7d2 commit 62b986a

File tree

3 files changed

+190
-12
lines changed

3 files changed

+190
-12
lines changed

.drone.star

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -585,14 +585,14 @@ def e2eTestsOnPlaywright(ctx):
585585

586586
steps += ocisService()
587587

588-
steps += [{
588+
steps.append({
589589
"name": "e2e-tests-playwright",
590590
"image": OC_CI_NODEJS_IMAGE,
591591
"environment": environment,
592592
"commands": [
593593
"pnpm test:e2e:playwright --project=chromium",
594594
],
595-
}]
595+
})
596596

597597
pipelines.append({
598598
"kind": "pipeline",
@@ -682,6 +682,16 @@ def e2eTests(ctx):
682682
"FEDERATED_BASE_URL_OCIS": "federation-ocis:9200",
683683
}
684684

685+
if "suites" in matrix:
686+
environment["TEST_SUITES"] = ",".join(params["suites"])
687+
steps += filterTestSuitesToRun(ctx, params["suites"])
688+
elif "features" in matrix:
689+
environment["FEATURE_FILES"] = ",".join(params["features"])
690+
steps += filterTestSuitesToRun(ctx, params["features"])
691+
else:
692+
print("Error: No suites or features defined for e2e test suite '%s'" % suite)
693+
return []
694+
685695
steps += restoreBuildArtifactCache(ctx, "pnpm", ".pnpm-store") + \
686696
installPnpm() + \
687697
restoreBrowsersCache() + \
@@ -711,22 +721,17 @@ def e2eTests(ctx):
711721
steps += (tikaService() if params["tikaNeeded"] else []) + \
712722
ocisService(params["extraServerEnvironment"])
713723

714-
command = "bash run-e2e.sh "
715-
if "suites" in matrix:
716-
command += "--suites %s" % ",".join(params["suites"])
717-
elif "features" in matrix:
718-
command += "%s" % " ".join(params["features"])
719-
else:
720-
print("Error: No suites or features defined for e2e test suite '%s'" % suite)
721-
return []
722-
723724
steps += [{
724725
"name": "e2e-tests",
725726
"image": OC_CI_NODEJS_IMAGE,
726727
"environment": environment,
727728
"commands": [
729+
"cat %s/tests/drone/suites.env" % dir["web"],
730+
"source %s/tests/drone/suites.env || true" % dir["web"],
728731
"cd tests/e2e",
729-
command,
732+
"echo $TEST_SUITES",
733+
"echo $FEATURE_FILES",
734+
"bash run-e2e.sh",
730735
],
731736
}] + \
732737
uploadTracingResult(ctx) + \
@@ -2009,3 +2014,21 @@ def restoreBrowsersCache():
20092014
],
20102015
},
20112016
]
2017+
2018+
def filterTestSuitesToRun(ctx, suites = []):
2019+
if "full-ci" in ctx.build.title.lower() and ctx.build.event == "cron":
2020+
return []
2021+
if len(suites) and "cucumber/" in suites[0]:
2022+
ENV = "FEATURE_FILES="
2023+
else:
2024+
ENV = "TEST_SUITES="
2025+
return [
2026+
{
2027+
"name": "filter-suites-to-run",
2028+
"image": OC_CI_NODEJS_IMAGE,
2029+
"commands": [
2030+
"node %s/tests/drone/filterTestSuitesToRun.js %s" % (dir["web"], ",".join(suites)),
2031+
"cat %s/tests/drone/suites.env" % dir["web"],
2032+
],
2033+
},
2034+
]
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { execSync } from 'child_process'
2+
import fs from 'fs'
3+
import path from 'path'
4+
5+
const targetBranch = process.env.DRONE_TARGET_BRANCH || 'master'
6+
7+
// INFO: 1 and 2 elements are node and script name respectively
8+
const scriptDir = path.dirname(process.argv[1])
9+
const suitesToCheck = process.argv[2]
10+
11+
const pacToTests = {
12+
'web-app-activities': [],
13+
'web-app-admin-settings': ['admin-settings', 'keycloak', 'smoke', 'user-settings'],
14+
'web-app-app-store': ['app-store'],
15+
'web-app-epub-reader': [],
16+
'web-app-external': ['app-provider'],
17+
'web-app-files': [
18+
'a11y',
19+
'admin-settings',
20+
'app-provider',
21+
'app-store',
22+
'file-action',
23+
'journeys',
24+
'keycloak',
25+
'navigation',
26+
'ocm',
27+
'oidc',
28+
'search',
29+
'shares',
30+
'smoke',
31+
'spaces',
32+
'user-settings'
33+
],
34+
'web-app-ocm': ['ocm'],
35+
'web-app-password-protected-folders': ['file-action'],
36+
'web-app-pdf-viewer': [],
37+
'web-app-preview': ['spaces', 'shares', 'file-action', 'navigation', 'ocm'],
38+
'web-app-search': [
39+
'a11y',
40+
'admin-settings',
41+
'app-provider',
42+
'app-store',
43+
'file-action',
44+
'journeys',
45+
'keycloak',
46+
'navigation',
47+
'ocm',
48+
'oidc',
49+
'search',
50+
'shares',
51+
'smoke',
52+
'spaces',
53+
'user-settings'
54+
],
55+
'web-app-text-editor': ['keycloak', 'oidc'],
56+
'web-app-webfinger': []
57+
}
58+
59+
// get test suites
60+
const testSuitesDir = `${scriptDir}/../e2e/cucumber/features`
61+
const testSuites = fs
62+
.readdirSync(testSuitesDir)
63+
.filter((entry) => fs.statSync(path.join(testSuitesDir, entry)).isDirectory())
64+
65+
function getChangedFiles() {
66+
const changedFiles = execSync(`git diff --name-only origin/${targetBranch} HEAD`).toString()
67+
console.log('[INFO] Changed files:\n', changedFiles)
68+
return [...new Set([...changedFiles.split('\n')])].filter((file) => file)
69+
}
70+
71+
function getPackageFromFile(file) {
72+
if (!file.startsWith('packages/')) {
73+
return
74+
}
75+
const packages = Object.keys(pacToTests)
76+
for (const pkg of packages) {
77+
if (file.startsWith(`packages/${pkg}`)) {
78+
return pkg
79+
}
80+
}
81+
}
82+
83+
function getAffectedTestSuites(changedFiles) {
84+
const affectedSuites = new Set()
85+
for (const file of changedFiles) {
86+
if (
87+
file.startsWith('tests/e2e/') ||
88+
file.startsWith('tests/drone/') ||
89+
file === '.drone.star' ||
90+
file === 'package.json'
91+
) {
92+
// run all test suites
93+
return testSuites
94+
}
95+
const packageName = getPackageFromFile(file)
96+
if (packageName && packageName in pacToTests) {
97+
pacToTests[packageName].forEach((suite) => affectedSuites.add(suite))
98+
}
99+
}
100+
return Array.from(affectedSuites)
101+
}
102+
103+
function createSuitesToRunEnvFile(suites = []) {
104+
const envContent = ['TEST_SUITES', suites.join(',')]
105+
if (suites[0].startsWith('cucumber/')) {
106+
envContent[0] = ['FEATURE_FILES']
107+
}
108+
// create suites.env file in the same directory as the script
109+
fs.writeFileSync(`${scriptDir}/suites.env`, envContent.join('='))
110+
}
111+
112+
function main() {
113+
const changedFiles = getChangedFiles()
114+
if (changedFiles.length === 0) {
115+
console.log('[INFO] No changes detected.')
116+
process.exit(78) // Skip the pipeline
117+
}
118+
const affectedTestSuites = getAffectedTestSuites(changedFiles)
119+
if (affectedTestSuites.length === 0) {
120+
console.log('[INFO] No affected test suites to run.')
121+
process.exit(78) // Skip the pipeline
122+
}
123+
if (suitesToCheck) {
124+
const suitesToRun = suitesToCheck.split(',').filter((suite) => {
125+
suite = suite.trim()
126+
if (suite.startsWith('cucumber/')) {
127+
suite = suite.replace('cucumber/features/', '').split('/').shift()
128+
}
129+
return affectedTestSuites.includes(suite)
130+
})
131+
if (suitesToRun.length === 0) {
132+
console.log(
133+
'[INFO] The following test suites are not affected and will be skipped:',
134+
suitesToCheck.split(',').join('\n')
135+
)
136+
process.exit(78) // Skip the pipeline
137+
}
138+
createSuitesToRunEnvFile(suitesToRun)
139+
return
140+
}
141+
createSuitesToRunEnvFile(affectedTestSuites)
142+
}
143+
144+
main()

tests/e2e/run-e2e.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ Available options:
3232
--total-parts - total number of groups to divide into
3333
e.g.: --total-parts 4 (suites will be divided into 4 groups)
3434
--help, -h - show cli options
35+
36+
Available env variables:
37+
TEST_SUITES - Comma separated list of suites to run. (Will be ignored if --suites is provided)
38+
FEATURE_FILES - Comma separated list of feature files to run. (Will be ignored if feature paths are provided)
3539
"
3640

3741
function log() {
@@ -146,6 +150,13 @@ function buildSuitesPattern() {
146150
GLOB_FEATURE_PATHS="$FEATURES_DIR/$suites/**/*.feature"
147151
}
148152

153+
if [[ -n $TEST_SUITES ]] && [[ -z "$FILTER_SUITES" ]]; then
154+
FILTER_SUITES=$(echo "$TEST_SUITES" | sed -E "s/,/\n/g")
155+
fi
156+
if [[ -n $FEATURE_FILES ]] && [[ -z "$FEATURE_PATHS_FROM_ARG" ]]; then
157+
FEATURE_PATHS_FROM_ARG=$(echo "$FEATURE_FILES" | sed -E "s/,/ /g")
158+
fi
159+
149160
# 1. [RUN E2E] run features from provided paths
150161
if [[ -n $FEATURE_PATHS_FROM_ARG && "$SKIP_RUN_PARTS" == true ]]; then
151162
getFeaturePaths "$FEATURE_PATHS_FROM_ARG"

0 commit comments

Comments
 (0)