Jenkins declarative pipeline using regex 101 - regex

I'm new to declarative pipeline and exploring its features. I tried to use regex. The following example is the result of trial and error. Is there a nicer solution out there? I'm looking for a new shiny declarative pipeline way, if there is any.
What I do not get is, why do I have to use the script{}-Enviroment and why do I have to use a local variable (def matcherX)?
working example followed by first attemts:
Working Example:
pipeline {
environment {
dummyText = 'aaa123aaa'
transfare = ''
}
agent any
stages {
stage('regex') {
steps{
script{
def matcherX = dummyText =~ /(\d+)/
transfare = matcherX[0][0]
echo transfare // results in 123
}
}
}
}
}
Error: without a script{}
/*
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 11: Expected a step # line 11, column 21.
def matcherX = dummyText =~ /(\d+)/
^
WorkflowScript: 12: Expected a step # line 12, column 21.
transfare = matcherX[0][0]
*/
Error: with script but with a global variable
//script{
// transfare = dummyText =~ /(\d+)/
/*
// No line displayed where error occured???
an exception which occurred:
in field org.jenkinsci.plugins.pipeline.modeldefinition.withscript.WithScriptScript.script
in object org.jenkinsci.plugins.pipeline.modeldefinition.agent.impl.LabelScript#192ebed
in field groovy.lang.Closure.delegate
in object org.jenkinsci.plugins.workflow.cps.CpsClosure2#31fd6bc8
in field groovy.lang.Closure.delegate
in object org.jenkinsci.plugins.workflow.cps.CpsClosure2#609aa9b5
in field org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.closures
in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup#3e51c1c3
in object org.jenkinsci.plugins.workflow.cps.CpsThreadGroup#3e51c1c3
Caused: java.io.NotSerializableException: java.util.regex.Matcher
at org.jboss.marshalling.river.RiverMarshaller.doWriteObject(RiverMarshaller.java:860)
at org.jboss.marshalling.river.BlockMarshaller.doWriteObject(BlockMarshaller.java:65)
at org.jboss.marshalling.river.BlockMarshaller.writeObject(BlockMarshaller.java:56)
*/

The script block indicates departure from the pure declarative syntax. Ideally builds (just as any other process) could take advantage of a pure declarative syntax to avoid implicit dependencies between steps.
The global variable of a matcher type fails to serialize which is needed to pass it between the Jenkins master and the slave (I guess).

Related

Making complex Terraform output optional?

I have an unenviable situation where I have to pass some unnecessary information into a module to make one thing (a Private Hosted R53 Zone), but not a bunch of others.
tl;dr, I'm trying to suppress outputs. If I didn't need to expose this output, my plan would behave as I expect. Outputs that produce strings or tuples were fine with me using the same condition to decide whether or not they would be evaluated, but the one below is still evaluating the attributes of the object:
output endpoint_dns_entries {
value = contains(local.de_dupe_phz_names, var.service["phz_name"]) ? {empty = [""]
emptyalso = [""]} : {
dns_names = aws_vpc_endpoint.endpoint.*.dns_entry[*].dns_name
hosted_zone_ids = aws_vpc_endpoint.endpoint.*.dns_entry[*].hosted_zone_id
}
}
yields errors:
Error: Unsupported attribute
on ../../endpoint-with-phz/outputs.tf line 12, in output "endpoint_dns_entries":
12: dns_names = aws_vpc_endpoint.endpoint.*.dns_entry[*].dns_name
This value does not have any attributes.
Error: Unsupported attribute
on ../../endpoint-with-phz/outputs.tf line 13, in output "endpoint_dns_entries":
13: hosted_zone_ids = aws_vpc_endpoint.endpoint.*.dns_entry[*].hosted_zone_id
This value does not have any attributes.
Any ideas on how to make this output optional?

Raku grammar action throwing "Cannot bind attributes in a Nil type object. Did you forget a '.new'?" error when using "make"

I have this method in a class that's throwing a Cannot bind attributes in a Nil type object. Did you forget a '.new'?
method parse() {
grammar FindHeaders {
token TOP { [<not-header> | <header>]+ $ }
token not-header { ^^ <![#]> \N* \n }
token header { ^^ '#'{ 1 .. 6 } <content> \n }
token content { \N+ }
}
class HeaderActions {
method content($match) {
return if $match ~~ m/^^\#\s+<[A..Z]>+e*s/ || $match !~~ m/<[a..z]>/;
return if $match ~~ m/\|/ && ( $match ~~ m:i/project/ || $match ~~ m:i/\+\w/ );
my $tc = Lingua::EN::Titlecase.new($match);
my $new_title = $tc.title;
make($new_title);
}
}
my $t = $!content;
FindHeaders.parse($t, actions => HeaderActions.new);
}
As far as I can tell, this code matches what's in the official documentation. So not sure why I'm getting this error. I have no idea what attribute or Nil object the compiler is referring to. If I comment out the line with the make method, everything works fine.
method content($match) {
There's a reason that action methods typically use $/ as the argument name: because the make function looks for $/ in order to associate the provided object to it. You can use $match, but then need to call the make method on that instead:
$match.make($new_title);
The mention of Nil is because the failed match earlier in the action method resulted in $/ being set to Nil.
I guess you avoided the more idiomatic $/ as the parameter of the action method because it gets in the way of doing further matching in the action method. Doing further matching in action methods means that the text is being parsed twice (once in the grammar and again the action), which is not so efficient, and usually best avoided (by moving the parsing work into the grammar).
As a final style point, declaring grammars and action classes in a method is neat encapsulation if they are only used there, but it would be wise to my scope them (my grammar FindHeaders { ... }), otherwise they shall end up installed in the nearest enclosing package anyway.
Err - bit of a guess here but looks like this error is generated during creation of a new object. That points to the line my $tc = Lingua::EN::Titlecase.new($match). I wonder if you want to pass a Str into this function call e.g. with "$match" or ~$match...

Pester unit testing function with Mandatory=True

I'm learning slowly using the wonderful Pester unit testing for Powershell for a while now. I'm kind of stuck around the usage of checking if my function can run "if not supplied any mandatory input into a function." which is giving me a red light here and wanted to achieve a green test result and move on coding.
So I have a function as follows.
function Code()
{
param(
[parameter(Mandatory=$true)]
[string]$SourceLocation)
return "Hello from $SourceLocation"
}
my test script is executed with the following checks
...
$moduleName = 'Code';
Describe $moduleName {
Context "$Function - Returns a result " {
It "does something useful with just $Function function name" {
$true | Should Be $true
}
}
Context "$Function - Returns with no input " {
It "with no input returns Mandatory value expected" {
Code | Should Throw
}
}
Context "$Function - Returns some output" {
It "with a name returns the standard phrase with that name" {
Code "Venus" | Should Be "Hello from Venus"
}
It "with a name returns something that ends with name" {
Code "Mars" | Should Match ".*Mars"
}
}
} #End Describe
my output from AppVeyor shows this outcome which the [+] are green colours and [-] is a red colour which is what I'm avoiding the best I can.
Describing Code
Context Code - Returns a result
[+] does something useful with just Code function name 16ms
Context Code - Returns with no input
[-] with no input returns Mandatory value expected 49ms
Cannot process command because of one or more missing mandatory parameters: SourceLocation.
at <ScriptBlock>, C:\projects\code\Code.Tests.ps1: line 117
117: Code | Should Throw
Context Code - Returns some output
[+] with a name returns the standard phrase with that name 23ms
[+] with a name returns something that ends with name 11ms
Any help is appreciated as I would like a green condition there as I'm not sure how to overcome certain types of message responses from Powershell and translate this into unit tests...
Per the comment from TessellatingHeckler, your code isn't working because in order to test for Throw you need to pipe the Should cmdlet a scriptblock { }:
{Code} | Should Throw
It's worth noting however that (when testing for a mandatory parameter) this works OK in AppVeyor because PowerShell is running in a non-interactive console (PowerShell.exe -noninteractive). If you try to run your Pester tests locally, your tests will seemingly be interrupted as you get prompted for input.
There's a couple of ways around this, one is to just run your tests locally using PowerShell in noninteractive mode:
PowerShell.exe -noninteractive {Invoke-Pester}
Another is to pass the parameter an explicit $null or empty value (with the caveat that you can actually have a mandatory string parameter that accepts $null and this solution won't work necessarily with all other parameter types):
It "with no input returns Mandatory value expected" {
{Code $null} | Should Throw
}
However it is worth noting that these two solutions throw different exception messages, and you should further test for an explicit message for the Throw so that your test doesn't pass if the code is failing for some other reason. E.g:
Running with -noninteractive
It "with no input returns Mandatory value expected" {
{Code} | Should Throw 'Cannot process command because of one or more missing mandatory parameters: SourceLocation.'
}
Passing it $null
It "with no input returns Mandatory value expected" {
{Code $null} | Should Throw "Cannot bind argument to parameter 'SourceLocation' because it is an empty string."
}
In summary this is only a complex issue for this specific scenario because your parameter is mandatory and you're testing for its absence.
Testing for exceptions is generally a simple process of:
{ some code } | should Throw 'message'
And works fine in both an interactive and non-interactive console.

Unparsable MOF Query When Trying to Register Event

Update 2
I accepted an answer and asked a different question elsewhere, where I am still trying to get to the bottom of this.
I don't think that one-lining this query is the answer, as I am still not getting the required results (and multi-lining queries is allowed in .mof, as shown in the URLs in comments to the answer ...
Update
I rewrote the query as a one-liner as suggested, but still got the same error! As it was still talking about lines 11-19 I knew there must be another issue. After saving a new file with the change, I reran mofcomp and it appears to have loaded, but the event which I have subscribed to simply does not work.
I really feel that there is not enough documentation on this topic and it is hard to work out how I am meant to debug this - any help on this would be much appreciated, even if this means using a different more appropriate method.
I have the following .mof file, which I would like to use to register an event on my system :
#pragma namespace("\\\\.\\root\\subscription")
instance of __EventFilter as $EventFilter
{
Name = "Event Filter Instance Name";
Query = "Select * from __InstanceCreationEvent within 1 "
"where targetInstance isa \"Cim_DirectoryContainsFile\" "
"and targetInstance.GroupComponent = \"Win32_Directory.Name=\"c:\\\\test\"\"";
QueryLanguage = "WQL";
EventNamespace = "Root\\Cimv2";
};
instance of ActiveScriptEventConsumer as $Consumer
{
Name = "TestConsumer";
ScriptingEngine = "VBScript";
ScriptText =
"Set objFSO = CreateObject(\"Scripting.FileSystemObject\")\n"
"Set objFile = objFSO.OpenTextFile(\"c:\\test\\Log.txt\", 8, True)\n"
"objFile.WriteLine Time & \" \" & \" File Created\"\n"
"objFile.Close\n";
// Specify any other relevant properties.
};
instance of __FilterToConsumerBinding
{
Filter = $EventFilter;
Consumer = $Consumer;
};
But whenever I run the command mfcomp myfile.mof I am getting this error:
Parsing MOF file: myfile.mof
MOF file has been successfully parsed
Storing data in the repository...
An error occurred while processing item 1 defined on lines 11 - 19 in file myfile.mof:
Error Number: 0x80041058, Facility: WMI
Description: Unparsable query.
Compiler returned error 0x80041058
This error appears to be caused by incorrect syntax in the query, but I don't understand where I have gone wrong with this - is anyone able to advise?
There are no string concatenation or line continuation characters being used in building "Query". To keep it simple, you could put the entire query on one line.

jenkins workflow regex

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...}