Event/Timing problem when posting data to Tempo Timehsheets

Hi All,

Looking for some advice on how to work around a problem I have. I recently integrated JIRA with an external system using HTTP rest calls from Script-Runner (with a lot of help from some very knowledgeable people on this forum).  My goal was to query the external system and retrieve two pieces of data about the user and enter this data into Tempo Timesheet Attribute fields. These are a very similar concept to custom fields in a JIRA issue, the Tempo timesheet attributes are just extra information about the work log in question… I created a scripted listener that fires on the ‘Work Logged’ event. When fired, it successfully retrieves the users name who logged the work, the work log id etc. I then query the external system and get returned the two new pieces of information. I can then post the information back to the tempo work log. However, I can only do that last piece (posting to the work log) in the script runner console. It does not work when the listener fires in real life, for a reason it took me while to understand…

My issue is because when a user logs work in tempo, it pops up a window to enter the relevant data (start time, duration etc). Also present of the popup screen are the two work log attributes (blank at this point in time) that I had hoped to fill in programmatically. When user clicks the ‘Log work’ button, the window says open, the even fires, my script runs, and does actually post the data I need to post, however the popup window stays open until the work logged script/listener/event  completes. The pop-up screen then closes itself, but  my two ‘attribute’ fields are still blank in this dialog, and I think these blank/empty strings are now being written to the database, overwriting the data my rest call entered as few milliseconds before.

I tired firing my script off the ‘work log updated’ event instead as a test, but it causes an infinite recursion as every time it posts data it seems to refire the event..

Any advice on how to restructure my approach?

Can I somehow fire another script after the normal JIRA work log event completes (event_complete + 1 second maybe)?

1 answer

Sounds tricky. If I've understood correctly, the sequence of events when using the UI is:

  • Users fills out form
  • Presses submit
  • Tempo does a rest call which creates the worklog
  • Your listener runs and tacks on some additional attributes
  • If success, dialog closes (depending on whether you had the Create Another checked)

You think, that then another rest call is made which overwrites your tempo attributes with the empty ones from the UI?

Seems a bit unlikely, but... is there a way in tempo to make an attribute not shown on the form?

If not, I would press F12 in Chrome, and look at the network tab. Click the Preserve Log box otherwise you lose the log when the page updates.

You should see a PUT or POST for creating the worklog. If your theory is right then you will see an additional PUT/POST which overwrites the attributes. There will be other junk which so you have to find the relevant stuff.

The other possibility is that tempo uses the JIRA api to create the worklog initially, then later adds the attributes (which are native to tempo, whereas the worklogs it uses are not). That would explain it.

But a network transcript would help work that out, before we worry about delayed listeners (which is possible, but can be painful).

 

Hi Jamie,

Your summary of what i'm doing is correct. There is no way to configure the log work pop-up to not display the attributes (using normal UI to configure plugin at least). I think the second scenario you described is whats happening. Just after I click the submit button, in the network tab I can see a POST to http://xxx.xxx.xxx.xxx:8080/rest/tempo-rest/1.0/worklogs/GEO-12. It posts the form data: (relevant bit shown) 

image2016-4-18 19:25:47.png

The last two items are my custom attributes, and are blank. There are 4 other POST events after this, to 'resource' and 'bulk' but looking at the payloads they are only setting some statistical information. There are tons of GET requests but they seems to just fetch icons and other decorations, I think i can ignore these...

I also did another test, in my listener script, after I post the data to tempo, I entered a sleep statement for 2 seconds. I do a GET and log.debug its return. I can see the relevant data I wrote in my POST, so i know the write is working. After that temporary mod, I then put in another 30 second sleep in the script. During this wait period, the submit work log pop-up screen stays open. I then go to another computer and look at my tempo time-sheet, and it will display the the information I posted to the the attribute fields. As soon as the 30 seconds times out, the pop-up window closes, the blank strings are sent, and then on the separate computer the text in the attribute fields simply dissapears as it was overwritten the instant the pop-up closes.


Does that help any?

I think it's probably simpler than this. Tempo call its rest api, which creates the worklog. Your code fires and sets the attributes. Then tempo sets the attributes again.

How are you setting them, are you using WorklogAttributeService, as per https://scriptrunner.adaptavist.com/latest/jira/working-with-tempo.html, not using rest or something?

@Viðar Svansson - can any of your guys help here?

I think he should be using Tempo APIs, not trying to hack the web dialog that might change any time, if I understand correctly.

I'll answer for him. He's not trying to hack the web dialog, he just has an event handler that updates the attributes. 

Hi guys  -i am using the temp rest api, as i found it documented here:

Tempo API site

and, correct, not trying to hack tempo in any way, i am just sending a HTTP PUT request. Somehow the data I send via PUT gets overwritten once the work logging popup page closes.

For reference my code is:

def baseUrl = ComponentAccessor.getApplicationProperties().getString(APKeys.JIRA_BASEURL)
def RESTClient http2 = new RESTClient(baseUrl)
http2.client.addRequestInterceptor(new HttpRequestInterceptor() {
    void process(HttpRequest httpRequest, HttpContext httpContext) {
        httpRequest.addHeader('Authorization', 'Basic ' + 'cGJ5cm5lOk1pbGVzdG9uZTEwMQ==')
        httpRequest.addHeader('X-Atlassian-Token', "no-check")
   }})
def String issueKey =  issue.getKey()
// Need to remove commas from string to prevent tempo splitting sting into more attributes
def String locS = myaddr.replace(",", "")
def String locE = myaddrEnd.replace(",", "")
def String payload = """{
"worklogAttributes":[{"key":"_EndAddress_","value":"${locE}"},{"key":"_StartAddress_","value":"${locS}"}],  
"issue":{"key":"${issueKey}"}
}"""
HttpResponse response2
def statusCode2
try {
    response2 = http2.request(PUT, JSON) {
        uri.path = "/rest/tempo-timesheets/3/worklogs/${WorkLogID}"
        send JSON, payload
    }
    statusCode2 = response2.getStatusLine().statusCode
    log.debug "status code is : ${statusCode2}"
} catch (HttpResponseException ex) {
    log.error "error:  ${ex.message}"
}

All my imports etc excluded from snippet, but the above really does work. As described above, if i force the script to pause, then do a GET to read the work-log back, the attributes are present. And I can also see them in normal time-sheet view page in another browser, up until the instant the the log-work screen closes, then they get overwritten

It's not a good idea to use the rest api unless it's a different instance - you should use the WorklogAttributeService as in the previous comment of mine. Not sure it will fix the issue though. I need to let the tempo guys answer this though, as it's not so much an SR issue.

I chose rest for a few reasons: future portability convenience, it seems to be what tempo recommend, and also my script was using other rest calls for other reasons, to retrieve data from a foreign system. It just seemed to make sense to keep all my methodologies the same. I think using the WorklogAttributeService method in this instance would result in the same problem though - any writes it makes to the attributes will just get overwritten at the last instant by the log work window.

I did not intend to imply there was any issue with SR, or tempo even, there is just something going on that I don't understand (yet), and I'm trying to work my way around it. SR has helped me on many occasions to do 'strange' things - I love it, in my opinion its one of the best plug-ins around smile

As an aside, I tried to replicate my functionality using the tempo examples on Jamie's SR site but wasn't able to. The examples on SR site are good, and I could get them to work by replicating the contexts/scenarios, but as far as modifying them to suit my specific needs in this instance I failed. I could not find any documents on-line that gave more instructions on the various methods/functions that you can use. If there are any examples anyone can point me to so I can write to an known worklog id number and add data to pre-existing worklog attribute I'd appreciate it....

I wasn't suggesting you were implying there was an issue with SR... just that the tempo guys are much better positioned to help you, but that help doesn't seem to be forthcoming. After some experimenting I have the following listener (on Work Logged on Issue). Basically it does one of your earlier suggestions. It's hacky and there must be a better way but I don't have time to delve any further:

import com.atlassian.jira.event.issue.IssueEvent
import com.onresolve.scriptrunner.runner.customisers.PluginModule
import com.onresolve.scriptrunner.runner.customisers.WithPlugin
import is.origo.jira.plugin.common.TempoWorklogManager

@WithPlugin("is.origo.jira.tempo-plugin")

@PluginModule
TempoWorklogManager tempoWorklogManager

def event = event as IssueEvent
def worklog = event.getWorklog()

Thread.start {
    Thread.sleep(1000)
    tempoWorklogManager.updateWorklogAttributes(worklog.id.toString(), ["_String_": "some string set from the script"])
}

\_String\_ is the key of the attribute.

 

Hi Jamie - Thanks!!!! that works. I borrowed your thread.start idea and wrapped my existing PUT call in it, after the sleep statement, and it just works! I'll have a go some time of converting my whole script over to the 'TempoWorklogManager' method, but for now I'm happy I have something that works. I'll take 'working' over 'hacky' any day smile.

Thanks again, delighted with the support you gave.

you're welcome, glad it's working.

Suggest an answer

Log in or Sign up to answer
Community showcase
Published Oct 31, 2018 in Marketplace Apps

Marketplace Spotlight: Zephyr

Hello Atlassian Community! Each month, we run a series of Spotlights to highlight Marketplace vendors and apps that our team thinks this Community would find valuable. In last month's Spotlig...

344 views 0 1
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you