Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added dynamic macros into Jenkins config #20

Merged
merged 6 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ final public class HelpMessage {
" Another type of arguments you can use are dynamic arguments. They are used\n" +
" for further filtering the jobs/builds to compare by any value in their config\n" +
" files.\n" +
" First, you must define the value to look for in a config file. The general syntax is:\n" +
" You must define the value to look for in a config file. The general syntax is:\n" +
" --X \"configFileName:whatAreYouLookingFor:queryToFindIt\"\n" +
" Instead of --X, you use one of these arguments:\n" +
" " + ArgumentsDeclaration.buildConfigFindArg.getName() + ArgumentsDeclaration.buildConfigFindArg.getUsage() + "\n" +
Expand All @@ -76,8 +76,8 @@ final public class HelpMessage {
" queryToFindIt is the query, to find the value in the config file. Currently,\n" +
" XPath is supported for XML files, Json Query for JSON files and plain value\n" +
" for properties files.\n" +
" After defining the value, you can proceed to the filtering itself. For that, you\n" +
" use the whatAreYouLooking part from the definition as an argument and this syntax:\n" +
" Now, you can proceed to the filtering itself. For that, you use the whatAreYouLooking\n" +
" part from the definition as an argument and this syntax:\n" +
" It either takes RegEx to match the value with or multiple RegExes\n" +
" in curly brackets, separated by commas. (e.g. {nvr1.*,nvr2.*})\n" +
" Example:\n" +
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ final public class Constants {
public static final String REPORT_TESTS_LIST_JSON = "tests-list.json";
public static final String IRRELEVANT_GLOB_STRING = "report-{runtime,devtools,compiler}.xml.gz";
public static final double VAGUE_QUERY_THRESHOLD = 0.5;

public static final int VAGUE_QUERY_LENGTH_THRESHOLD = 4;
public static final String ESCAPE_DIRECTORY_REGEX = "((\\.\\./)+.*(\\.\\./)*.*)|((\\.\\./)*.*(\\.\\./)+.*)";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isnt better to simply check, that the fully resolved filename, the final abs path (java have methods for that), is simply still in desired workspace/cwd/app dir?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wil merge this as it is. But the rework of shoudl be needed.
Again,. from my own experiments, checking input like this may be missleading.

eg correctdir/correctdir/../fileInFirstCorrectDir is pretty correct
Eg I'm checking the bash injection in the CGI wrapper by checking for "|" and thus literally killing this tool. Btrw, any ideas how to fix that "|" (https://github.com/jenkinsci/report-jtreg-plugin/blob/master/report-jtreg-service/src/main/java/io/jenkins/plugins/report/jtreg/main/web/ContextExecutingHandler.java#L114)

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import io.jenkins.plugins.report.jtreg.model.*;

import java.io.File;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
Expand Down Expand Up @@ -78,17 +79,17 @@ private String parseQueryToText(String spliterator, String query) {

String converted = query;

// finds %{X} in the query from Jenkins config and replaces it with corresponding part of job name
Pattern p = Pattern.compile("%\\{(N?[+-]?[0-9]+|N|S|SPLIT)\\}");
// finds %{X} in the query from Jenkins config and replaces it with corresponding part of job name or value from config
Pattern p = Pattern.compile("%\\{[a-zA-Z0-9+-]+}");
Matcher m = p.matcher(converted);

while (m.find()) {
String insideBrackets = converted.substring(m.start() + 1 + 1, m.end() - 1); // get just the inside of the brackets

String replacement;
String replacement = "";
if (insideBrackets.equals("S") || insideBrackets.equals("SPLIT")) {
replacement = spliterator;
} else {
} else if (insideBrackets.matches("N?[+-]?[0-9]+|N")) {
int number;
if (insideBrackets.charAt(0) == 'N' && insideBrackets.length() > 1) {
number = splitJob.length + Integer.parseInt(insideBrackets.substring(1));
Expand All @@ -104,6 +105,30 @@ private String parseQueryToText(String spliterator, String query) {
}

replacement = splitJob[number];
} else {
List<ConfigItem> configItems = JenkinsReportJckGlobalConfig.getGlobalConfigItems();
boolean found = false;
for (ConfigItem item : configItems) {
if (item.getWhatToFind().equals(insideBrackets)) {
found = true;

// get path of Jenkins home
String jenkinsHome = System.getProperty("jenkins_home");
if (jenkinsHome == null) {
jenkinsHome = System.getenv("JENKINS_HOME");
}

File configFile = getFile(item, jenkinsHome);

replacement = new ConfigFinder(configFile, item.getWhatToFind(), item.getFindQuery()).findInConfig();
break;
}
}

if (!found) {
System.err.println("WARNING: Cannot find a config item corresponding with \""+ insideBrackets + "\", please set it first!");
return "Cannot find \"" + insideBrackets + "\" config item!";
}
}

converted = m.replaceFirst(replacement);
Expand All @@ -113,6 +138,23 @@ private String parseQueryToText(String spliterator, String query) {
return converted;
}

private File getFile(ConfigItem item, String jenkinsHome) {
String path = jenkinsHome + "/jobs/" + job + "/";

// check if it is looking into job or build directory and add the correct path
if (item.getConfigLocation().equals("build")) {
path = path + "builds/" + getBuildNumber();
} else if (!item.getConfigLocation().equals("job")){
throw new RuntimeException("Invalid location of config file, only job or build directories are allowed.");
}

File configFile = new File(path, item.getConfigFileName());
if (!configFile.exists()) {
throw new RuntimeException("The file " + path + item.getConfigFileName() + " was not found.");
}
return configFile;
}

private String getDiffUrlStub(){
return urlsProvider.getDiffServer() + "?generated-part=+-view%3Ddiff-list+++-view%3Ddiff-summary+++-view%3Ddiff-summary-suites+++-view%3Dinfo-problems+++-view%3Dinfo-summary+++-output%3Dhtml++-fill++&custom-part=";//+job+numbers //eg as above;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ public class ConfigItem extends AbstractDescribableImpl<ConfigItem> {

@DataBoundConstructor
public ConfigItem(String configFileName, String whatToFind, String findQuery, String configLocation) {
// check if the user is trying to escape the current directory with ../
if (configFileName.matches(Constants.ESCAPE_DIRECTORY_REGEX)) {
throw new RuntimeException("Cannot escape from the directory with config file to its parent directory.");
}

this.configFileName = configFileName;
this.whatToFind = whatToFind;
this.findQuery = findQuery;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
</f:entry>
</f:section>

<f:section title="Comparator links">
<f:section title="Comparator Links">
<div>
<p>
This section is used for generating automatic links to the comparator tool with prefilled arguments.
Expand Down Expand Up @@ -48,7 +48,8 @@
<p>
This section is used for automatically generating "<code>--build-config-find</code>" and "<code>--job-config-find</code>"
arguments into the link to comparator, that are above, since writing it manually can clutter the field
very easily. Each of these will generate the arguments into EVERY link specified above.
very easily. Each of these will generate the arguments into EVERY link specified above. After specifying them,
you can also use them as a macro in the arguments field in the <i>comparator links</i> section.
</p>
<p>
<i>Each field in the form below has a help button describing what should be filled in.</i>
Expand All @@ -62,8 +63,8 @@
<f:entry title="The directory with the config file" field="configLocation"
help="/descriptor/io.jenkins.plugins.report.jtreg.JenkinsReportJckGlobalConfig/help/configLocation">
<select name="configLocation">
<option value="build">Build directory</option>
<option value="job">Job directory</option>
<option value="build" selected="${instance.ConfigLocation.equals('build') ? 'true' : null}">Build directory</option>
<option value="job" selected="${instance.ConfigLocation.equals('job') ? 'true' : null}">Job directory</option>
</select>
</f:entry>
<f:entry field="whatToFind" title="Name of the item to find"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
<p>
On top of the normal arguments, there is also a type of <b>macro system</b>. This macro system is powerful and
can be used for making the link dynamic. These macros represent each part of the split job name (split by the
spliterator) and when loading the report page, they are replaced by it.
spliterator) or a value from config defined in the <i>config items</i> section, and when loading the report
page, they are replaced by it.
</p>
<i>The macros have this syntax:</i><br>
<ul>
Expand All @@ -20,20 +21,27 @@

<li>"<code>%{S}</code>" or "<code>%{SPLIT}</code>" will be replaced with the spliterator specified in the field
above.</li>

<li>"<code>%{dynamic}</code>", where you replace <code>dynamic</code> with a name of an item specified in the
<i>config items</i> section (specifically the name from the <i>Name of the item to find</i> field).
It will be replaced by a value from the corresponding config file from the current job and build.</li>
</ul>
<p>
<i>Example of the macros:</i><br>
For the job name "<code>jtreg~full-jp11-ojdk11~rpms-f36.x86_64-fastdebug.sdk-f36.x86_64.testfarm-x11.defaultgc.legacy.lnxagent.jfroff</code>",<br>
and spliterator set to "<code>[.-]</code>", the macros "<code>%{2}%{S}%{N-1}_something_%{N}</code>" will be
replaced with "<code>jp11[.-]lnxagent_something_jfroff</code>".
There is a job with the job name "<code>jtreg~full-jp11-ojdk11~rpms-f36.x86_64-fastdebug.sdk-f36.x86_64.testfarm-x11.defaultgc.legacy.lnxagent.jfroff</code>",<br>
spliterator set to "<code>[.-]</code>" and a config item with the <i>Name of the item to find</i> field set
to "<code>nvr</code>" and its evaluation in the config file being "<code>java-17-openjdk-17.0.6.0.9-0.4.ea.el8</code>".
</p>
<p>
The macros "<code>%{2}%{S}%{N-1}_something_%{N} - %{nvr}</code>" will be
replaced with "<code>jp11[.-]lnxagent_something_jfroff - java-17-openjdk-17.0.6.0.9-0.4.ea.el8</code>".
</p>
<p>
<i>So an example of the whole prompt with arguments can look like this:</i><br>
<code>
--compare<br>
--history 5<br>
--build-config-find changelog.xml:nvr:/build/nvr<br>
--nvr ".*"<br>
--nvr "%{nvr}"<br>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it maybe worthy to keep also the --nvr ".*" example. Otherwise users may fell to assumption, that it is the final form, and no xtensions possible

--formatting html<br>
--regex %{1}%{S}%{2}%{S}%{3}%{S}.*%{S}%{5}%{S}%{6}%{S}%{7}%{S}.*%{S}%{9}%{S}%{10}%{S}%{11}%{S}%{12}%{S}%{13}%{S}%{14}%{S}%{15}<br>
</code>
Expand Down