Skip to content

Commit 6bd1dea

Browse files
committed
[TRTLLM-11861][infra] Support wildcard in bot stage-list/extra-stage commands
Add wildcard '*' support for --stage-list and --extra-stage bot commands. Users can now specify patterns like "*PerfSanity*" to match all stages containing "PerfSanity" instead of listing each stage individually. Signed-off-by: Abby Wei <mengzew@nvidia.com>
1 parent ce71620 commit 6bd1dea

3 files changed

Lines changed: 44 additions & 9 deletions

File tree

.github/workflows/bot-command.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,14 +52,14 @@ jobs:
5252
"`--disable-reuse-test ` *(OPTIONAL)* : Explicitly prevent the pipeline from reusing build artifacts and skipping successful test stages from a previous pipeline. Ensure that all builds and tests are run regardless of previous successes.\n\n" +
5353
"`--disable-fail-fast ` *(OPTIONAL)* : Disable fail fast on build/tests/infra failures.\n\n" +
5454
"`--skip-test ` *(OPTIONAL)* : Skip all test stages, but still run build stages, package stages and sanity check stages. Note: Does **NOT** update GitHub check status.\n\n" +
55-
"`--stage-list \"A10-PyTorch-1, xxx\"` *(OPTIONAL)* : Only run the specified test stages. Examples: \"A10-PyTorch-1, xxx\". Note: Does **NOT** update GitHub check status.\n\n" +
55+
"`--stage-list \"A10-PyTorch-1, xxx\"` *(OPTIONAL)* : Only run the specified test stages. Supports wildcard `*` for pattern matching (e.g., `\"*PerfSanity*\"` matches all stages containing PerfSanity). Examples: \"A10-PyTorch-1, xxx\", \"*PerfSanity*\". Note: Does **NOT** update GitHub check status.\n\n" +
5656
"`--gpu-type \"A30, H100_PCIe\"` *(OPTIONAL)* : Only run the test stages on the specified GPU types. Examples: \"A30, H100_PCIe\". Note: Does **NOT** update GitHub check status.\n\n" +
5757
"`--test-backend \"pytorch, cpp\"` *(OPTIONAL)* : Skip test stages which don't match the specified backends. Only support [pytorch, cpp, tensorrt, triton]. Examples: \"pytorch, cpp\" (does not run test stages with tensorrt or triton backend). Note: Does **NOT** update GitHub pipeline status.\n\n" +
5858
"`--only-multi-gpu-test ` *(OPTIONAL)* : Only run the multi-GPU tests. Note: Does **NOT** update GitHub check status.\n\n" +
5959
"`--disable-multi-gpu-test ` *(OPTIONAL)* : Disable the multi-GPU tests. Note: Does **NOT** update GitHub check status.\n\n" +
6060
"`--add-multi-gpu-test ` *(OPTIONAL)* : Force run the multi-GPU tests in addition to running L0 pre-merge pipeline.\n\n" +
6161
"`--post-merge ` *(OPTIONAL)* : Run the L0 post-merge pipeline instead of the ordinary L0 pre-merge pipeline.\n\n" +
62-
"`--extra-stage \"H100_PCIe-TensorRT-Post-Merge-1, xxx\"` *(OPTIONAL)* : Run the ordinary L0 pre-merge pipeline and specified test stages. Examples: --extra-stage \"H100_PCIe-TensorRT-Post-Merge-1, xxx\".\n\n" +
62+
"`--extra-stage \"H100_PCIe-TensorRT-Post-Merge-1, xxx\"` *(OPTIONAL)* : Run the ordinary L0 pre-merge pipeline and specified test stages. Supports wildcard `*` for pattern matching. Examples: --extra-stage \"H100_PCIe-TensorRT-Post-Merge-1, xxx\", --extra-stage \"*Post-Merge*\".\n\n" +
6363
"`--detailed-log ` *(OPTIONAL)* : Enable flushing out all logs to the Jenkins console. This will significantly increase the log volume and may slow down the job.\n\n" +
6464
"`--debug ` *(OPTIONAL)* : **Experimental feature**. Enable access to the CI container for debugging purpose. Note: Specify exactly one stage in the `stage-list` parameter to access the appropriate container environment. Note: Does **NOT** update GitHub check status.\n\n" +
6565
"`--high-priority ` *(OPTIONAL)* : Run the pipeline with high priority. This option is restricted to authorized users only and will route the job to a high-priority queue.\n\n" +

jenkins/L0_MergeRequest.groovy

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1295,6 +1295,8 @@ def launchStages(pipeline, reuseBuild, testFilter, enableFailFast, globalVars)
12951295
if (env.JOB_NAME ==~ /.*PostMerge.*/ && !GEN_POST_MERGE_BUILDS_ONLY) {
12961296
stages += dockerBuildJob
12971297
}
1298+
// Only trigger the special Build-Docker-Images handling on an exact match,
1299+
// not on wildcard patterns (e.g., "*Build*") that happen to match it.
12981300
if (!GEN_POST_MERGE_BUILDS_ONLY && (testFilter[(TEST_STAGE_LIST)]?.contains("Build-Docker-Images") || testFilter[(EXTRA_STAGE_LIST)]?.contains("Build-Docker-Images"))) {
12991301
stages += dockerBuildJob
13001302
testFilter[(TEST_STAGE_LIST)]?.remove("Build-Docker-Images")

jenkins/L0_Test.groovy

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1378,6 +1378,31 @@ def trimForStageList(stageNameList)
13781378
return trimedList
13791379
}
13801380

1381+
// Check if a stage key matches a pattern.
1382+
// Supports exact match and wildcard '*' for substring matching.
1383+
// Examples: "A10-PyTorch-1" (exact), "*PerfSanity*" (contains), "A10-*" (prefix).
1384+
def stageMatchesPattern(String key, String pattern) {
1385+
if (!pattern.contains('*')) {
1386+
return key == pattern
1387+
}
1388+
def parts = pattern.split('\\*', -1)
1389+
if (parts[0] && !key.startsWith(parts[0])) return false
1390+
if (parts[-1] && !key.endsWith(parts[-1])) return false
1391+
int idx = 0
1392+
for (part in parts) {
1393+
if (!part) continue
1394+
int found = key.indexOf(part, idx)
1395+
if (found < 0) return false
1396+
idx = found + part.length()
1397+
}
1398+
return true
1399+
}
1400+
1401+
// Check if a stage key matches any pattern in the list.
1402+
def stageMatchesAnyPattern(String key, List patterns) {
1403+
return patterns.any { pattern -> stageMatchesPattern(key, pattern) }
1404+
}
1405+
13811406
// Test filter flags
13821407
@Field
13831408
def REUSE_TEST = "reuse_test"
@@ -3021,10 +3046,18 @@ def runPackageSanityCheck(pipeline, wheel_path, reinstall_dependencies=false, cp
30213046

30223047
def checkStageNameSet(stageNames, jobKeys, paramName) {
30233048
echo "Validate stage names for the passed GitLab bot params [${paramName}]."
3024-
invalidStageName = stageNames.findAll { !(it in jobKeys) }
3025-
if (invalidStageName) {
3049+
def unmatchedNames = stageNames.findAll { pattern ->
3050+
if (pattern.contains('*')) {
3051+
// Wildcard pattern: check that it matches at least one stage
3052+
!jobKeys.any { key -> stageMatchesPattern(key, pattern) }
3053+
} else {
3054+
// Exact name: check that it exists
3055+
!(pattern in jobKeys)
3056+
}
3057+
}
3058+
if (unmatchedNames) {
30263059
def sortedJobKeys = jobKeys.sort()
3027-
throw new Exception("Cannot find the stage names [${invalidStageName}] from the passed params [${paramName}]. Available stage names (${sortedJobKeys.size()} total):\n${sortedJobKeys.collect { " ${it}" }.join('\n')}")
3060+
throw new Exception("Cannot find the stage names [${unmatchedNames}] from the passed params [${paramName}]. Available stage names (${sortedJobKeys.size()} total):\n${sortedJobKeys.collect { " ${it}" }.join('\n')}")
30283061
}
30293062
}
30303063

@@ -3788,17 +3821,17 @@ def launchTestJobs(pipeline, testFilter)
37883821
}
37893822
}
37903823

3791-
// Check --stage-list, only run the stages in stage-list.
3824+
// Check --stage-list, only run the stages in stage-list. Supports wildcard '*'.
37923825
if (testFilter[TEST_STAGE_LIST] != null) {
37933826
echo "Use TEST_STAGE_LIST for filtering. Stages: ${testFilter[(TEST_STAGE_LIST)]}."
3794-
parallelJobsFiltered = parallelJobs.findAll {it.key in testFilter[(TEST_STAGE_LIST)]}
3827+
parallelJobsFiltered = parallelJobs.findAll { stageMatchesAnyPattern(it.key, testFilter[(TEST_STAGE_LIST)]) }
37953828
println parallelJobsFiltered.keySet()
37963829
}
37973830

3798-
// Check --extra-stage, add the stages in extra-stage.
3831+
// Check --extra-stage, add the stages in extra-stage. Supports wildcard '*'.
37993832
if (testFilter[EXTRA_STAGE_LIST] != null) {
38003833
echo "Use EXTRA_STAGE_LIST for filtering. Stages: ${testFilter[(EXTRA_STAGE_LIST)]}."
3801-
parallelJobsFiltered += parallelJobs.findAll {it.key in testFilter[(EXTRA_STAGE_LIST)]}
3834+
parallelJobsFiltered += parallelJobs.findAll { stageMatchesAnyPattern(it.key, testFilter[(EXTRA_STAGE_LIST)]) }
38023835
println parallelJobsFiltered.keySet()
38033836
}
38043837

0 commit comments

Comments
 (0)