I'm making my first steps in the Jenkins workflow (Jenkins ver 1.609.1)
I need to read a file, line by line, and then run regex on each line.
I'm interested in the regex "grouping" type, however "project" and "status" variables (the code below) get null value in Jenkins . Any suggestions what is wrong and how to fix it ?
def line = readFile (file)
def resultList = line.tokenize()
for(item in resultList ){
(item =~ /(\w+)=(\w+)$/).each { whole, project, status ->
println (whole)
println (project)
println (status)
}
}
each with a closure will not work: JENKINS-26481
If something using advanced language features works in standalone Groovy but not in Workflow, try just encapsulating it in a method marked #NonCPS. This will effectively run it as a “native” method. Only do this for code you are sure will run quickly and not block on I/O, since it will not be able to survive a Jenkins restart.
Well,
After checking out some other regex options I came around with the following solution that seems working :
def matcher = item =~ /(?<proj>\w+)=(?<status>\w+)/
if( matcher.matches() ) { etc...}
Related
I've got a Node module file containing about 100 exported methods, which looks something like this:
exports.methodOne = async user_id => {
// other method contents
};
exports.methodTwo = async user_id => {
// other method contents
fooMethod();
};
exports.methodThree = async user_id => {
// other method contents
fooMethod();
};
Goal: What I'd like to do is figure out how to grab the name of any method which contains a call to fooMethod, and return the correct method names: methodTwo and methodThree. I wrote a regex which gets kinda close:
exports\.(\w+).*(\n.*?){1,}fooMethod
Problem: using my example code from above, though, it would effectively match methodOne and methodThree because it finds the first instance of export and then the first instance of fooMethod and goes on from there. Here's a regex101 example.
I suspect I could make use of lookaheads or lookbehinds, but I have little experience with those parts of regex, so any guidance would be much appreciated!
Edit: Turns out regex is poorly-suited for this type of task. #ctcherry advised using a parser, and using that as a springboard, I was able to learn about Abstract Syntax Trees (ASTs) and the recast tool which lets you traverse the tree after using various tools (acorn and others) to parse your code into tree form.
With these tools in hand, I successfully built a script to parse and traverse my node app's files, and was able to find all methods containing fooMethod as intended.
Regex isn't the best tool to tackle all the parts of this problem, ideally we could rely on something higher level, a parser.
One way to do this is to let the javascript parse itself during load and execution. If your node module doesn't include anything that would execute on its own (or at least anything that would conflict with the below), you can put this at the bottom of your module, and then run the module with node mod.js.
console.log(Object.keys(exports).filter(fn => exports[fn].toString().includes("fooMethod(")));
(In the comments below it is revealed that the above isn't possible.)
Another option would be to use a library like https://github.com/acornjs/acorn (there are other options) to write some other javascript that parses your original target javascript, then you would have a tree structure you could use to perform your matching and eventually return the function names you are after. I'm not an expert in that library so unfortunately I don't have sample code for you.
This regex matches (only) the method names that contain a call to fooMethod();
(?<=exports\.)\w+(?=[^{]+\{[^}]+fooMethod\(\)[^}]+};)
See live demo.
Assuming that all methods have their body enclosed within { and }, I would make an approach to get to the final regex like this:
First, find a regex to get the individual methods. This can be done using this regex:
exports\.(\w+)(\s|.)*?\{(\s|.)*?\}
Next, we are interested in those methods that have fooMethod in them before they close. So, look for } or fooMethod.*}, in that order. So, let us name the group searching for fooMethod as FOO and the name of the method calling it as METH. When we iterate the matches, if group FOO is present in a match, we will use the corresponding METH group, else we will reject it.
exports\.(?<METH>\w+)(\s|.)*?\{(\s|.)*?(\}|(?<FOO>fooMethod)(\s|.)*?\})
Explanation:
exports\.(?<METH>\w+): Till the method name (you have already covered this)
(\s|.)*?\{(\s|.)*?: Some code before { and after, non-greedy so that the subsequent group is given preference
(\}|(?<FOO>fooMethod)(\s|.)*?\}): This has 2 parts:
\}: Match the method close delimiter, OR
(?<FOO>fooMethod)(\s|.)*?\}): The call to fooMethod followed by optional code and method close delimiter.
Here's a JavaScript code that demostrates this:
let p = /exports\.(?<METH>\w+)(\s|.)*?\{(\s|.)*?(\}|(?<FOO>fooMethod)(\s|.)*?\})/g
let input = `exports.methodOne = async user_id => {
// other method contents
};
exports.methodTwo = async user_id => {
// other method contents
fooMethod();
};
exports.methodThree = async user_id => {
// other method contents
fooMethod();
};';`
let match = p.exec( input );
while( match !== null) {
if( match.groups.FOO !== undefined ) console.log( match.groups.METH );
match = p.exec( input )
}
I have an archetype and I am trying to add a new requiredProperty which should only allow one of two possible values: "hibernate" and "hibernate-reactive". In the archetype-metadata.xml, I have defined the property as shown below:
<requiredProperty key="quarkus_orm_selection">
<validationRegex><![CDATA[^(hibernate|hibernate-reactive)$]]></validationRegex>
</requiredProperty>
In jshell and in other Java programs, I have verified that the regular expression works properly, but in the archetype when I test using a value like hibernate-ree the archetype proceeds without an error!
I proved out the regex as follows in JShell:
jshell> String[] examples = {"hibernate", "hibernate-reactive", "hibernate-re", "hibernate-ree", "testing", "reactive"}
examples ==> String[6] { "hibernate", "hibernate-reactive", "h ... ", "testing", "reactive" }
jshell> Pattern regex = Pattern.compile("^(hibernate|hibernate-reactive)$")
regex ==> ^(hibernate|hibernate-reactive)$
jshell> Arrays.asList(examples).stream().filter(i -> regex.matcher(i).matches()).forEach(System.out::println)
hibernate
hibernate-reactive
Can anyone suggest what I might be doing wrong?
I am using Maven Archetype Plugin version 3.2.0
As far as I can tell maven archetypes only validates reg-ex's if you pass in the property in interactive mode.
I created a archetype-post-generate.groovy script (see below)
src/main/resources/META-INF/archetype-post-generate.groovy:
String ormSelector = request.getProperties().get("quarkus_orm_selection")
def pattern = "^(hibernate|hibernate-reactive)\$" // the \$ is important!
final match = ormSelector.matches(pattern)
if (!match) {
println "[ERROR] ormSelector: $ormSelector is not valid"
println "[ERROR] please provide an ormSelector that follows this pattern: '$pattern'"
throw new RuntimeException("OrmSelector: $ormSelector is not valid")
}
Helo!
I've a groovy script with one argument. The argument has to be a regex pattern. I want to use an * in the argument, but always got: The syntax of the command is incorrect.
This is an example (opt.p is the pattern getting from the arg):
def map1 = [e:'pine___apple', f:'pineapple']
map1.each { entry ->
entry.value.find(~/$opt.p/) { match -> println entry.value}
}
I want to use the script from the command line in this way:
groovy test -p pine_*a
And I expect that the result will be:
pine___apple
pineapple
I tried these solutions and more, but nothing works:
pine_*a
"pine_*a"
'pine_*a'
pine_\*a
'pine_\*a'
"pine_\*a"
pine_'\*'a
pine_"\*"a
pine_'\\*'a
pine_"\\*"a
Somebody knows how to solve this problem?
Thanks a lot!
EDIT:
I use:
Groovy Version: 2.4.6 JVM: 1.7.0_45 Vendor: Oracle Corporation OS: Windows 7 And I also use CliBuilder:
def cli = new CliBuilder()
cli.with
{
p('pattern', args: 1, required: false)
}
def opt = cli.parse(args)
The following groovy script:
def map = [e:'pine___apple', f:'pineapple']
map.each { k, v ->
v.find(~/${args[0]}/) { println "key: $k, value: $v -> ${v.find(args[0])}" }
}
prints the following on invocation:
$ groovy test.groovy pine_*a
Checking key: e, value: pine___apple -> pine___a
Checking key: f, value: pineapple -> pinea
or to exclude one of the map entries:
$ groovy test.groovy "pine_{1,9}a"
key: e, value: pine___apple -> pine___a
Not sure what the issue with your script is. Maybe the handling of opts.p like one of the comments suggests.
edit 1:
an alternative CliBuilder syntax to the one mentioned by Tim Yates in his answer:
def opt = new CliBuilder().with {
p longOpt: 'pattern', args: 1
parse(args)
}
edit 2: solution
as this is marked as the accepted answer, I will add what ended up being the solution here (I have a comment on this below, but comments are not immediately obvious when browsing for the solution).
This issue was caused by a bug in the windows groovy distribution startgroovy.bat file (see separate stackoverflow thread) which is used to launch groovy. The problem is with windows execution and parameter handling and it occurs before the groovy program even starts executing. There is a fair chance this has been fixed in later versions of groovy so it might be worth a try to upgrade to the latest version. If not, the answer in the above thread should make it possible to fix startgroovy.bat.
Think it's the way you're capturing your opt
I assume you're using the CliBuilder
And I suspect you've missed the args: 1 from the definition of the p parameter
def opt = new CliBuilder().with {
it.p('pattern', args: 1)
parse(args)
}
def map1 = [e:'pine___apple', f:'pineapple']
map1.each { entry ->
entry.value.find(~/$opt.p/) { match -> println entry.value}
}
Works as you describe it should for me...
I'm facing a thing that is confusing me. I have this groovy code:
def static extractTaskIdsFromLine(String orderName, String line) {
print("comment line = \"" + line + "\"")
def pattern = ~/${orderName}-[0-9]+/
return line != null ? line.findAll(pattern) : new ArrayList<>()
}
On my local machine everything looks fine and all tests pass. But with the same conditions this code on Team City with the same input gives no one matches. Both encodings and input parameters are the same.
Do you have any ideas?
I am currently rewriting some custom perl-code used in the OTRS-ticketing-system, which is used to create SQL-like queries. Yes, there are probably better ways of escaping input, but let's not go into this...
$Param{PostMasterSearch} contains an email-adress like test'test#domain.tld (Note the ').
my $PostMasterSearch = $Param{PostMasterSearch};
$PostMasterSearch =~ s/'//gms;
$Self->{LogObject}->Log(
Priority => 'error',
Message => "XXXXX: $PostMasterSearch",
);
$SQLExt .= " $Field LIKE '$PostMasterSearch'";
So my expectation would be, that I'll find a log-message saying XXXXX: testtest#domain.tld and part of a SQL-query that goes like Email LIKE 'testtest#domain.tld'.
But in reality, I only get the log-message - the SQL-query-string is for whatever reason Email LIKE 'test'test#domain.tld'.
Screwing with the last line of the code to be like
$SQLExt .= " $Field LIKE '$PostMasterSearch' X";
doesn't make any sense - but returns the string Email LIKE 'testtest#domain.tld' X.
Any hints on why $PostMasterSearch is still containing that ' that should have been long gone? Or a hint on how to concatenate the $SQLExt with the '-less version of $PostMasterSearch?
OK, now this is the part where it gets embarrassing...
Turns out, that this script contains the very same code multiple times and executes it multiple times...
So the code posted above actually works and doesn't return any error (like it should). The error-message is caused by the next occurence of the code, that hasn't been patched yet.
tl;dr: I probably should trash that script and rewrite it from scratch.