Im new to Groovy and Im working on a Grails app. I need to make a SOAP call so Im using the wslite package, but the following code doesn't appear to do anything:
def client = new SOAPClient(apiEndpoint)
println "SOAP client is ${client.dump()}"
try {
def response = client.send(SOAPAction: 'GetService') {
body {
"Request" {
"Username"(credentials.userId)
"Password"(credentials.password)
"Param1"(code)
"Param2"(location)
"Items" {
"Item" {
"ItemParam1"("some data")
"ItemParam2"(some more data)
}
}
}
}
}
}
} catch (SOAPFaultException sfe) {
println "${sfe.dump()}"
} catch (SOAPClientException sce) {
println "${sce.dump()}"
}
println "${response.dump()}"
The first println works but then nothing after that.
By adding a catch all for exceptions I was able to see the problem in the markup.
Related
I would like to make a resilient slack notification class for my Jenkins instance.
Currently I just call the slackSend function from the Jenkins slack plugin. However if the call to slack fails, so does my build. This means I have a very hard dependency on Slack that I am not ok with.
I have managed to get the code to work but it is rather ugly and I would like to know if there is a better way to do this.
Firstly I have class defined in src/something/slack/slackHandler.groovy
The code looks a little like this:
package something.slack
public class slackHandler {
private String threadId = ""
private String channelName = ""
private Boolean silent = false
private Closure sender
private Logger logger
public silence(Boolean trigger) {
this.silent = trigger
}
public sendMessage(String msg) {
if (threadId == "") {
def (slackResponse, ok) = this.sendMessageTo(this.channelName, msg)
if (!ok) {
// We have tried to send a on channel. But the send failed so we can not determine the threadId.
// We should at this point store the messages and try send it again on the next call to slack.
return
}
this.setThreadId(slackResponse.threadId)
} else {
def (slackResponse, ok) = this.sendMessageTo(this.threadId, msg)
if (!ok){
// We tried to send on a threadId, it failed. We have the threadId so we can leave the slackResponse alone.
// We should at this point store the messages and try send it again on the next call to slack.
return
}
}
}
public sendMessageTo(String channel, String msg) {
return this.trySend(channel, msg)
}
private trySend(String to, String msg) {
if (this.silent) {
return [[threadId: "nothing"], true]
}
try {
return [sender(to, msg), true]
} catch (e) {
// These do not work :(
println("There wasn an error sending the slack message. Error $e")
println("Message being sent: $msg")
return [null, false]
}
}
}
This is the part I'm not happy about. To use the above code I need to create and pass a closure to send the messages to slack because the slackSend function is not available inside my class. I can not find out how to give it the ability to use this function or access the slack class. The println calls are also not showing up in the Jenkins console which is a problem for this class as the fallback is to log to the console. This makes me think that I am missing some sort of context that I need to give my class.
This is how I currently use the class:
def slackSender = new slackHandler(
[
channelName:"rd-bots",
sender: {to, msg -> return slackSend(channel: to, message: msg)}
]
)
slackSender.sendMessage("Hello :wave:")
Can someone please tell me if the is a way to pass on the context or if what I have done is the only way? Also why don't the println calls appear in the Jenkins log?
You can include a try-catch in your pipeline code around your call to your slack handler.
Here's the documentation for catchError: https://www.jenkins.io/doc/pipeline/steps/workflow-basic-steps/#catcherror-catch-error-and-set-build-result-to-failure
I think it should look something like this in a pipeline:
#Library('shared-lib#main')_
pipeline{
agent any
options {
timestamps()
}
environment {
Custom_Variables = 'stuff'
}
stages{
stage ('blah') {
steps {
catchError{
def slackSender = new slackHandler(
[
channelName:"rd-bots",
sender: {to, msg -> return slackSend(channel: to, message: msg)}
]
)
slackSender.sendMessage("Hello :wave:")
}
}
}
}
}
After a bit of digging and looking at different questions for other things where context is needed I managed to find an answer.
When running in Jenkins the this value will give the context of your running environment. You can pass that on to something else.
Code updated to look like this:
public class slackHandler {
private String threadId = ""
private String channelName = ""
private Boolean silent = false
private ctx
public silence(Boolean trigger) {
this.silent = trigger
}
public setThreadId(String id) {
this.threadId = id
}
public sendMessage(String msg) {
if (threadId == "") {
def (slackResponse, ok) = this.sendMessageTo(this.channelName, msg)
if (!ok) {
// We have tried to send a on channel. But the send failed so we can not determine the threadId.
// We should at this point store the messages and try send it again on the next call to slack.
return
}
this.setThreadId(slackResponse.threadId)
} else {
def (slackResponse, ok) = this.sendMessageTo(this.threadId, msg)
if (!ok){
// We tried to send on a threadId, it failed. We have the threadId so we can leave the slackResponse alone.
// We should at this point store the messages and try send it again on the next call to slack.
return
}
}
}
public sendMessageTo(String channel, String msg) {
return this.trySend(channel, msg)
}
private trySend(String to, String msg) {
if (this.silent) {
return [[threadId: "nothing"], true]
}
def slackResponse = ctx.slackSend(channel: to, message: msg)
if (slackResponse != null) {
return [slackResponse, true]
} else {
ctx.echo("There was an error sending slack message sent: $msg")
return [null, false]
}
}
}
Used like this:
import com.proquoai.slack.slackHandler
def slackSender = new slackHandler(
[
channelName:"trashroom10120123",
ctx: this
]
)
node ('docker') {
stage('Send Slack Messages') {
slackSender.sendMessage("Hello :wave:")
slackSender.sendMessage("It's running :go_dance:")
}
stage('Send out of band messages') {
slackSender.sendMessageTo("rd-bots", ":ship-it:")
}
}
As a side note, the slackSend function appears to swallow the error and simply doesn't return a slackResponse. Therefore using a try/catch block didn't actually help in determining if slack sending failed.
I have a hidden parameter in Jenkins called platformType. I want to display choices based on the parameter platformType. I created the following groovy script but it doesn't work
if (platformType.equals("android")) {
return ['7.0', '6.0']
} else (platformType.equals("ios")) {
return ['10.0', '9.0']
}
Pls see the screenshot below
quite sure you did not specify the platformType as a parameter to platformVersion or you have other error in your code..
without error handling you just don't see it.
in your script you can catch the exception like this:
try {
if (platformType.equals("android")) {
return ['7.0', '6.0']
} else if(platformType.equals("ios")) {
return ['10.0', '9.0']
}
}catch(e){ return [e.toString()] }
in this case you'll see the error in your choice field
Looks you are missing if in the else part.
It is supposed to be:
if ('android' == platformType) {
return ['7.0', '6.0']
} else if ('ios' == platformType) {
return ['10.0', '9.0']
} else return []
Following the tutorial on DartWatch blog on using Google OAuth library. The question is how to handle: 'Access denied' error from Google ?
Here is my code example:
class Client
{
GoogleOAuth2 _auth;
Client()
{
_auth = new GoogleOAuth2(
'5xxxxxxxxxxxxxx.apps.googleusercontent.com', // Client ID
['openid', 'email', 'profile'],
tokenLoaded:oauthReady);
}
void doLogin()
{
// _auth.logout();
// _auth.token = null;
try
{
_auth.login();
}
on AuthException {
print('Access denied');
}
on Exception catch(exp)
{
print('Exception $exp occurred');
}
}
void oauthReady(Token token)
{
print('Token is: $token');
}
}
but I never hit catch block on any (!) exception. What I'm doing wrong ?
I'm using:
Dart Editor version 0.5.0_r21823
Dart SDK version 0.5.0.1_r21823
You never hit the catch block because auth.login is an asynchronous operation which returns a Future.
There is a great article on Future error handling on the dartlang.org website.
auth.login returns a Future immediately, but the work it does happens after control returns to the event loop (see my answer to another question for more on the event loop.)
Your code should look more like:
/// Returns a Future that completes to whether the login was successful.
Future<boolean> doLogin()
{
_auth.login()
.then((_) {
print("Success!");
return true;
}.catchError((e) {
print('Exception $e occurred.');
return false; // or throw the exception again.
}
}
I get an exception when i try to upgrade my indexedDB database with a higher version then the browser currently has,
but the funny part abort is that, it gets upgraded. Is this by design or have i done something wrong.
I got very inspired from the dart sample Todo, so my code ended up looking like this.
void open_db(String DB_name, int Version, String Store_Name){
var request = window.indexedDB.open(DB_name, Version);
request.on.success.add((e) => _onDbOpened(request.result));
request.on.error.add((e) => print("Error opening db"));
request.on.upgradeNeeded.add((e) => _onUpgradeNeeded(request.transaction, Store_Name));
}
void _onDbOpened(IDBDatabase db){
_db = db;
print("DB opened");
}
void _onUpgradeNeeded(IDBTransaction changeVersionTransaction, String Store_Name){
changeVersionTransaction.on.error.add((e) => print("Error upgrading db"));
changeVersionTransaction.on.complete.add((e) => print("Success upgrading db"));
changeVersionTransaction.db.createObjectStore(Store_Name);
}
When I run this with version=4 and the browser only have version=3, then it jumps to _onUpgradeNeeded as expected, but I get an IDBDatabaseException with message: "ConstraintError: DOM IDBDatabase Exception 4".
So where is it I go wrong?
Thanks for your question!
You may need to check if the store exists first.
if (db.objectStoreNames.indexOf(storeName) == -1) {
db.createObjectStore(storeName);
}
Here is some code to update your IndexedDB database, using Dart. Note, this compensates for the two ways to upgrade (an old way that Chrome used, and the new way that Firefox and newer versions of Chrome use)
_openDb(afterOpen()) {
var request = window.indexedDB.open(DB_NAME, VERSION);
if (request is IDBOpenDBRequest) {
// New upgrade protocol. FireFox 15, Chrome 24, hopefully IE10.
request.on.success.add(expectAsync1((e) {
db = e.target.result;
afterOpen();
}));
request.on.upgradeNeeded.add((e) {
guardAsync(() {
_createObjectStore(e.target.result);
});
});
request.on.error.add(fail('open'));
} else {
// Legacy setVersion upgrade protocol. Chrome < 23.
request.on.success.add(expectAsync1((e) {
db = e.target.result;
if (db.version != '$VERSION') {
var setRequest = db.setVersion('$VERSION');
setRequest.on.success.add(
expectAsync1((e) {
_createObjectStore(db);
var transaction = e.target.result;
transaction.on.complete.add(
expectAsync1((e) => afterOpen()));
transaction.on.error.add(fail('Upgrade'));
}));
setRequest.on.error.add(fail('setVersion error'));
} else {
afterOpen();
}
}));
request.on.error.add(fail('open'));
}
}
_createObjectStore(db) {
try {
// Nuke object store if it already exists.
db.deleteObjectStore(STORE_NAME);
}
on IDBDatabaseException catch(e) { } // Chrome
on DOMException catch(e) { } // Firefox
db.createObjectStore(STORE_NAME);
}
Note, this code is from this test: http://code.google.com/p/dart/source/browse/trunk/dart/tests/html/indexeddb_3_test.dart
I have the included grails script that I found in some random place on the internet and it works pretty well for firing up scripts in a bootstrapped grails env. The only thing it doesn't seem to do is kick off my conf/*Bootstrap.groovy scripts like when I do run-app.
Is there another function like loadApp() and configureApp() that will do that for me?
import org.codehaus.groovy.grails.support.PersistenceContextInterceptor
Ant.property(environment: "env")
grailsHome = Ant.antProject.properties."env.GRAILS_HOME"
includeTargets << new File("${grailsHome}/scripts/Bootstrap.groovy")
target('default': "Runs scripts in the test/local directory") {
if (!args) { throw new RuntimeException("[fail] This script requires an argument - the script to run.") }
depends(configureProxy, packageApp, classpath)
classLoader = new URLClassLoader([classesDir.toURI().toURL()] as URL[], rootLoader)
Thread.currentThread().setContextClassLoader(classLoader)
loadApp()
configureApp()
def interceptor = null
def beanNames = appCtx.getBeanNamesForType(PersistenceContextInterceptor)
if (beanNames && beanNames.size() == 1) {
interceptor = appCtx.getBean(beanNames[0])
}
try {
interceptor?.init()
new GroovyScriptEngine(Ant.antProject.properties."base.dir", classLoader).run("scripts/${args}.groovy", new Binding(['appCtx':appCtx]))
interceptor?.flush()
} catch (Exception e) {
e.printStackTrace()
interceptor?.clear()
} finally {
interceptor?.destroy()
}
}
Yes, try
new BootStrap().init()