I have series of ProForma forms that are submitted as issues to the Jira Service Desk.

I needed to run some scripts against these issues after they were created and fast-tracked into a Queued state.  I elected to run a Groovy script as a Listener on Issue Update. The thinking was that because the state of the ticket was being updated from Open to Queued, the Listener would have plenty of material to work with.

The issue that I encountered was that the listener was only detecting some of the issues.  I enabled logging at the outset of the Listener script and told it to record any ticket that was subject to an Issue Updated event.  Some of the issues created by the forms weren’t being detected by this at all. At the same time, some of them were.

The issue was consistent, in that certain forms were never detected by the listener, and certain forms were always detected.  There was no appreciable difference in the form setup or the way the tickets were processed.  The Listener script itself simply examined the Request Type field of each ticket (which is a Jira Core field), and routed the ticket based on

 

During the process of writing a listener for Jira, I found myself encountering a strange error.  The error looked like this:

com.atlassian.servicedesk.api.AuthorizationException: The action performed required a logged in user. Please log in and try again.

This was strange for two reasons. First, I am a Jira administrator with total access to the entire instance. Second, my script had explicitly supplied the logged-in user (myself) as the account under which to run the script.

What gives?

The code I used to supply my own account to the script looks like so:

 def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
 

This solution had been more than sufficient previously.   I searched and I searched and I couldn’t find anything related to my issue.  If you search the text of the error, three results are returned, and they’re about REST API permissions. Not applicable here.

In the end I accidentally stumbled on the answer, by trying different solutions for the action I was trying to take.  What I was trying to do was get the Request Type of the issue in question.

The solution was to explicitly provide an account to the script, under which the method could run.   That is, I changed the code to:

I found myself in a situation wherein a ProForma form on the Jira Service Desk contained a custom field.  I needed the contents of that field to dictate which team the resulting issue was assigned to.

The first thing I tried was to add a Groovy script to a transition in the Service Desk Workflow.   If I could tell the script to transition the issue based on the value of a field, the issue should be resolved.

This turned out to not be possible. For some reason, the value of a custom field is not populated from the form to the field until after the ticket “lands”, or finishes moving through the workflow.  It’s not enough to simply trigger the script after the Open/Create transition.   No matter what, the value of the custom field is not available until after all of the initial transitions have finished.  No matter how you try to reference the custom field, the value returned will always be NULL.

This was extremely aggravating, especially when it seems like such a simple solution SHOULD work, and it’s not clear whether the issue lies with your script or with the system.

The solution you’re going to come across

Introduction

Jira Issues can only be transition between states in a manner that resembles the Workflow of the parent project. In other words, before you begin trying to script the transition of a Jira issue, you must understand the workflow and what the available transitions actually are.

Further to that point, there’s more to transitions that simply changing the status of an issue. Some transitions have criteria.  For example, you may want to move an issue from Open to Pending.  In order to do so, you may need to select a Pending State, and add a comment.  How do you account for that in a script?

Using Groovy and ScriptRunner to transition Jira issues is a pretty straightforward process. So too is this process quite simple if you need to include transition criteria.  It’s simple, if you can find a guide on how to do it. As with most of the things I blog about, I couldn’t find instructions for accomplishing this simple task, so I’m writing my own.

Overview

The script we’re going to explore transitions a Jira issue from one state to another, and fills in the criteria required to make the transition a valid one.  As

It is entirely possible to set up Jira so that a subtask may remain open, while the parent task is closed. This effectively creates orphan subtasks, not connected to any open issue or ticket.

Identifying these is a matter of first identifying all subtasks, and then checking the status of both the subtask and its parent.

We first identify all subtasks for a given project by invoking a service context, and running some JQL against the Jira instance:

 import com.atlassian.jira.bc.filter.SearchRequestService
import com.atlassian.jira.issue.search.SearchRequest
import com.atlassian.sal.api.component.ComponentLocator
import com.atlassian.jira.bc.JiraServiceContext
import com.atlassian.jira.bc.JiraServiceContextImpl
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.issue.search.SearchProvider
import com.atlassian.jira.jql.parser.JqlQueryParser
import com.atlassian.jira.web.bean.PagerFilter
import com.atlassian.jira.bc.issue.search.SearchService
import com.atlassian.jira.issue.label.LabelManager

def jqlQueryParser = ComponentAccessor.getComponent(JqlQueryParser)
def searchProvider = ComponentAccessor.getComponent(SearchProvider)
def issueManager = ComponentAccessor.getIssueManager()
def searchService = ComponentLocator.getComponent(SearchService)
def user = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser()
def searchManager = ComponentLocator.getComponent(SearchRequestService)
def contextManager = ComponentLocator.getComponent(JiraServiceContext)
def searchRequest = ComponentLocator.getComponent(SearchRequest)
def labelManager = ComponentLocator.getComponent(LabelManager)



JiraServiceContextImpl serviceCtx = new JiraServiceContextImpl(user);
//Declare a search context using the logged-in user

def queryParser = ComponentAccessor.getComponent(JqlQueryParser)
//Declare a parser to handle the JQL query

def query = queryParser.parseQuery('project = "<project name>" ')
//Define the JQL query.  In this instance we're returning all issues under a given project

def search = searchService.search(user, query, PagerFilter.getUnlimitedFilter())
//Define a search, using all the pieces defined 

This is part three of my series on using Python to connect to the Twitter API.

Imagine for a moment that you had a specific vision for your Twitter account.  A vision of balance, and harmony.  What if you only followed people who also followed you?  Whether or not you want to curate your Twitter experience in this transactional way is entirely up to you. It’s your account!

We can do that with Python. As always, replace the placeholders with your own account credentials.  See Part One of this series if you’re not sure how to do that. 

Let’s take a look at the code required to do this:

 import tweepy

consumerKey = "<>"
consumerSecret = "<>"
accessToken = "<>"
accessTokenSecret = "<>"

auth = tweepy.OAuthHandler(consumerKey, consumerSecret)
auth.set_access_token(accessToken, accessTokenSecret)

#Call the api 
api = tweepy.API(auth,wait_on_rate_limit=True)

#define two empty lists
followers = []
following = []
  
#Get the list of friends
for status in tweepy.Cursor(api.get_friends,count=200).items():
    #Add the results to the list
    following.append(status.screen_name)

#get the list of followers
for status in tweepy.Cursor(api.get_followers,count=200).items():
    #Add the results to the list
    followers.append(status.screen_name)
    
#compare the lists and take action
for person in following:
    if person not in followers:
        api.destroy_friendship(screen_name=person)
        print("Unfollowed " + person)
         

As

Introduction

There are a great number of things that you might want to do with Twitter, for which the web or mobile clients don’t have facilities.  For example, you might want to run a script that automatically thanks anyone who follows you.  Or you might want to run a script that Likes any comment that someone adds to your post. 
It is worth noting that Twitter is extremely strict when it comes to automated actions around followers.  For example, it’s entirely possible to scrape the follower list of large accounts, and write a script to automatically follow all of those people. That would conceivably get you a large number of followers, and when you were done you could just write anther script to unfollow anyone who didn’t follow you back.   I promise that the Twitter API will pick up on what you’re doing, and put you in Twitter Jail.  Don’t do that.
In this post we’ll examine how to make a basic connection to the Twitter API, using Python and Tweepy.    We’ll investigate one of the errors you might encounter, and discuss the pagination of the results that the API returns. The example we’re using will return a list

Introduction

A great deal of the available information regarding the use of Twitter and Python is outdated. The Twitter API has undergone several major revisions in the last few years, and many of the available tutorials now only lead to frustration.

Not only has the API undergone major revisions, but there are multiple supported versions of the API.  Some methods referenced by online tutorials will only work with certain other methods!

My hope for this series is to provide a clear and concise tutorial for connecting to the Twitter API using Tweepy and Python.

In order to connect to the Twitter API, your account must be provisioned for Developer access.  This is a free service, at the basic level, but does require additional setup.  That will be the focus of this first blog post.

Resources Required

You will need:

  • A Twitter account with a verified email address and verified phone number
  • Developer access to that account
  • A Python IDE (I use Spyder)
  • Tweepy

This post focuses solely on gaining Developer access, and assumes you already have the account.

The Setup

While I intend for this tutorial to be quite detailed, I trust that you can handle signing up for a

Introduction

I’ve been considering pivoting my career toward developer advocacy.  I’m a decent developer with great customer service skills, and I can see myself doing well in such a position.   In order to do that, I need to have a stronger idea of what I believe the role will entail.  When I’ve established that, I’ll know which jobs to apply for.

 In this post, I am attempting to answer two questions: what do developers actually do, and how can an advocate help them do that?

What is the point of a developer?

In previous blog posts I have discussed the role of Knowledge Management in an organization. That role is the consistent application of the organization’s ideology.   Put it another way, the organization has a certain way it needs to run, and to think about things, and Knowledge Management helps with that process.

So, what is the role of the developer?  When we start talking about developers, we quickly move from a very general business context to a much more specific one.   Software can do many things, but in a lot of ways a developer is a developer.  The offhand answer is, of course, that a developer develops software.  This

Knowledge Management has an active role in shaping the ongoing ideology that an institution develops.  As the curators of the information that ultimately informs ideology, the Knowledge Management team has a responsibility to be aware of not only their privilege, but also of the historic unequal privilege afforded to marginalized groups found within an organization.

Knowledge is power, and access to knowledge has long been wielded as a weapon by the ruling class.  For many years the Bible was only available in Latin. This was because the ruling class (the clergy) were the only people who could read Latin.  They therefor were the only ones able to interpret the bible, giving them full authority over the working class as the voice of God on earth.

In the middle of the 19th century, literacy tests were given to voters.  As the literacy rates of marginalized groups such as African Americans was low, this effectively disenfranchised large groups of voters. 

These are historic examples, but limited access to information continues to be used to shut out or keep down marginalized groups.   The Freedom of Information act was passed in the USA in 1967, and in theory should have allowed ordinary citizens