Plugins

Modules in this direcotry are searched for available stats. Each plugin should contain a single class inheriting from StatsGroup. Stats from this group will be included in the report if enabled in user config. Name of the plugin should match config section type. Attribute order defines the default order in the final report.

This is the default plugin order:

header 000
google 050
nitrate 100
bugzilla 200
git 300
gerrit 350
trac 400
trello 450
rt 500
jira 600
wiki 700
bitly 701
items 800
footer 900
did.plugins.detect()

Detect available plugins and return enabled/configured stats

Yields tuples of the form (section, statsgroup) sorted by the default StatsGroup order which maybe overriden in the config file. The ‘section’ is the name of the configuration section as well as the option used to enable those particular stats.

did.plugins.load()

Check available plugins and attempt to import them

bugzilla

Bugzilla stats such as filed, fixed or verified bugs

This plugin uses python-bugzilla module to gather the stats. Use the bugzilla login command to initialize Bugzilla cookies which then will be used for authentication. Reports will contain only publicly available issues if cookies are not properly set.

Config example:

[bz]
type = bugzilla
prefix = BZ
url = https://bugzilla.redhat.com/xmlrpc.cgi
resolutions = notabug, duplicate
Resolutions:
List of resolutions to be displayed at the end of the summary if bug is closed. By default notabug and duplicate are shown. Use all to always display resolution if available or none to turn off the feature completely.

Available options:

--bz-filed Bugs filed
--bz-patched Bugs patched
--bz-posted Bugs posted
--bz-fixed Bugs fixed
--bz-returned Bugs returned
--bz-verified Bugs verified
--bz-commented Bugs commented
--bz-subscribed
 Bugs subscribed
--bz-closed Bugs closed
--bz All above
class did.plugins.bugzilla.Bug(bug, history, comments, parent)

Bugzilla search

closed(user)

Moved to CLOSED and not later moved to ASSIGNED

commented(user)

True if comment was added in given time frame

fixed()

Moved to MODIFIED and not later moved to ASSIGNED

logs

Return relevant who-did-what pairs from the bug history

patched(user)

True if Patch was added to Keywords field by given user

posted()

True if bug was moved to POST in given time frame

returned(user)

Moved to ASSIGNED by given user (but not from NEW)

subscribed(user)

True if CC was added in given time frame

summary

Bug summary including resolution if enabled

verified()

True if bug was verified in given time frame

class did.plugins.bugzilla.Bugzilla(parent)

Bugzilla investigator

search(query, options)

Perform Bugzilla search

server

Connection to the server

class did.plugins.bugzilla.BugzillaStats(option, name=None, parent=None, user=None)

Bugzilla stats

order = 200
class did.plugins.bugzilla.ClosedBugs(option, name=None, parent=None, user=None, options=None)

Bugs closed

Bugs which have been moved to the CLOSED state in given time frame and later have not been moved back to the ASSIGNED state (which would suggest the bug was not closed for a proper reason).

fetch()
class did.plugins.bugzilla.CommentedBugs(option, name=None, parent=None, user=None, options=None)

Bugs commented

All bugs commented by given user in requested time frame.

fetch()
class did.plugins.bugzilla.FiledBugs(option, name=None, parent=None, user=None, options=None)

Bugs filed

Newly created bugs by given user, marked as the Reporter.

fetch()
class did.plugins.bugzilla.FixedBugs(option, name=None, parent=None, user=None, options=None)

Bugs fixed

Bugs which have been moved to the MODIFIED state in given time frame and later have not been moved back to the ASSIGNED state (which would suggest an incomplete fix).

fetch()
class did.plugins.bugzilla.PatchedBugs(option, name=None, parent=None, user=None, options=None)

Bugs patched

Gathers bugs with keyword Patch added by given user, denoting the patch for the issue is available (e.g. attached to the bug or pushed to a feature git branch).

fetch()
class did.plugins.bugzilla.PostedBugs(option, name=None, parent=None, user=None, options=None)

Bugs posted

Bugs with patches posted for review, detected by their status change to POST and given user set as Assignee.

fetch()
class did.plugins.bugzilla.ReturnedBugs(option, name=None, parent=None, user=None, options=None)

Bugs returned

Returned bugs are those which were returned by given user to the ASSIGNED status, meaning the fix for the issue is not correct or complete.

fetch()
class did.plugins.bugzilla.SubscribedBugs(option, name=None, parent=None, user=None, options=None)

Bugs subscribed

All bugs subscribed by given user in requested time frame.

fetch()
class did.plugins.bugzilla.VerifiedBugs(option, name=None, parent=None, user=None, options=None)

Bugs verified

Bugs with QA Contact field set to given user and having their status changed to VERIFIED.

fetch()

footer

Customizable footer

Config example:

[footer]
type = footer
next = Plans, thoughts, ideas...
status = Status: Green | Yellow | Orange | Red
class did.plugins.footer.Footer(option, name=None, parent=None, user=None)
order = 900

gerrit

Gerrit stats such as submitted, review or merged changes

Config example:

[gerrit]
type = gerrit
url = https://example.org/gerrit/#/
prefix = GR
class did.plugins.gerrit.AbandonedChanges(option, name=None, parent=None, base_url=None, prefix=None)

Changes abandoned

fetch()
class did.plugins.gerrit.AddedPatches(option, name=None, parent=None, base_url=None, prefix=None)

Additional patches added to existing changes

fetch()
class did.plugins.gerrit.Change(ticket, prefix, changelog=None)

Request gerrit change

class did.plugins.gerrit.Gerrit(baseurl, prefix)

curl -s ‘https://REPOURL/gerrit/changes/?q=is:abandoned+age:7d

get_changelog(chg)
get_query_result(url)
static join_URL_frags(base, query)
search(query)
class did.plugins.gerrit.GerritStats(option, name=None, parent=None, user=None)

Gerrit

order = 350
class did.plugins.gerrit.GerritUnit(option, name=None, parent=None, base_url=None, prefix=None)

General mother class offering general services for querying Gerrit repo.

fetch(query_string='', common_query_options=None, limit_since=False)

Backend for the actual gerrit query.

query_string:
basic query terms, e.g., ‘status:abandoned’
common_query_options:
[optional] rest of the query string; if omitted, the default one is used (limit by the current user and since option); if empty, nothing will be added to query_string
limit_since:
[optional] Boolean (defaults to False) post-process the results to eliminate items created after since option.
static get_gerrit_date(instr)
class did.plugins.gerrit.MergedChanges(option, name=None, parent=None, base_url=None, prefix=None)

Changes succesfully merged

fetch()
class did.plugins.gerrit.PublishedDrafts(option, name=None, parent=None, base_url=None, prefix=None)

Draft changes published

fetch()
class did.plugins.gerrit.ReviewedChanges(option, name=None, parent=None, base_url=None, prefix=None)

Review of a change (for reviewers)

fetch()
class did.plugins.gerrit.SubmitedChanges(option, name=None, parent=None, base_url=None, prefix=None)

Changes submitted for review

fetch()

git

Git commits

Config example:

[tools]
type = git
apps = /home/psss/git/apps

[tests]
type = git
tests = /home/psss/git/tests/*

Note that using * you can enable multiple git repositories.

class did.plugins.git.GitCommits(option, name=None, parent=None, path=None)

Git commits

fetch()
header()

Show summary header.

class did.plugins.git.GitRepo(path)

Git repository investigator

commits(user, options)

List commits for given user.

class did.plugins.git.GitStats(option, name=None, parent=None, user=None)

Git stats group

order = 300

github

GitHub stats such as created and closed issues

Config example:

[github]
type = github
url = https://api.github.com/
token = <authentication-token>
login = <username>

The authentication token is optional. However, unauthenticated queries are limited. For more details see GitHub API docs. Use login to override the default email address for searching. See the Config documentation for details on using aliases.

class did.plugins.github.GitHub(url, token)

GitHub Investigator

search(query)

Perform GitHub query

class did.plugins.github.GitHubStats(option, name=None, parent=None, user=None)

GitHub work

order = 330
class did.plugins.github.Issue(data)

GitHub Issue

class did.plugins.github.IssuesClosed(option, name=None, parent=None, user=None, options=None)

Issues closed

fetch()
class did.plugins.github.IssuesCreated(option, name=None, parent=None, user=None, options=None)

Issues created

fetch()
class did.plugins.github.PullRequestsClosed(option, name=None, parent=None, user=None, options=None)

Pull requests closed

fetch()
class did.plugins.github.PullRequestsCreated(option, name=None, parent=None, user=None, options=None)

Pull requests created

fetch()

google

Google Apps stats such as attended events or sent emails

Config example:

[google]
type = google
client_id = <client_id>
client_secret = <client_secret>
apps = calendar
storage = /home/diduser/.did/google-api-credentials.json

To retrieve data via Google API, you will need to create access credentials (client_id and client_secret) first. Perform the following steps to create such a pair:

  1. Open https://console.developers.google.com/flows/enableapi?apiid=calendar
  2. In the drop-down menu, select Create project and click Continue
  3. Click Go to credentials
  4. In the Where will you be calling the API from? drop-down menu, choose Other UI (e.g. Windows, CLI tool)
  5. In What data will you be accessing?, choose User data
  6. Click What credentials do I need?
  7. Input ‘did credentials’ in the Name field and click Create client ID
  8. In Product name shown to users, type ‘did’
  9. Click Continue, then Done
  10. Click the did credentials link to display the credentials

The apps configuration option defines the scope of user data the application will request (read-only) access to. Currently, the only supported value is calendar.

During the first run, user will be asked to grant the plugin access rights to selected apps. If the user approves the request, this decision is remembered by creating a credential storage file. The path to the storage can be customized by configuring the storage option.

class did.plugins.google.Event(dict)

Googe Calendar Event

attended_by(email)

Check if user attended the event

created_by(email)

Check if user created the event

organized_by(email)

Check if user created the event

class did.plugins.google.GoogleCalendar(http)

Google Calendar functions

events(**kwargs)

Fetch events meeting specified criteria

class did.plugins.google.GoogleEventsAttended(option, name=None, parent=None)

Events attended

fetch()
class did.plugins.google.GoogleEventsOrganized(option, name=None, parent=None)

Events organized

fetch()
class did.plugins.google.GoogleStatsBase(option, name=None, parent=None)

Base class containing common code

events

All events in calendar within specified time range

class did.plugins.google.GoogleStatsGroup(option, name=None, parent=None, user=None)

Google stats group

order = 50
did.plugins.google.authorized_http(client_id, client_secret, apps, file=None)

Start an authorized HTTP session.

Try fetching valid user credentials from storage. If nothing has been stored, or if the stored credentials are invalid, complete the OAuth2 flow to obtain new credentials.

header

Customizable header

Config example:

[header]
type = header
highlights = Highlights
joy = Joy of the week ;-)
class did.plugins.header.Header(option, name=None, parent=None, user=None)
order = 0

idonethis

Export Idonethis.com Dones

Config example:

[idonethis]
type = idonethis
token = ...
token
https://idonethis.com/api/token/
class did.plugins.idonethis.IdonethisStats(option, name=None, parent=None, user=None, options=None)

Idonethis.com stats

fetch(page_size=100)
class did.plugins.idonethis.IdonethisStatsGroup(option, name=None, parent=None, user=None)

Idonethis stats group

order = 801
session

Initialize the session

items

Custom section with multiple items

Config example:

[projects]
type = items
header = Work on projects
item1 = Project One
item2 = Project Two
item3 = Project Three
class did.plugins.items.CustomStats(option, name=None, parent=None, user=None)

Custom stats

order = 800
class did.plugins.items.ItemStats(option, name=None, parent=None)

Custom section with given items

fetch()
header()

Simple header for custom stats (no item count)

jira

Jira stats such as created, updated or resolved issues

Configuration example (GSS authentication):

[jboss]
type = jira
prefix = JIRA
project = ORG
url = https://issues.jboss.org/

Configuration example (basic authentication):

[jboss]
type = jira
prefix = JIRA
project = ORG
url = https://issues.jboss.org/
auth_url = https://issues.jboss.org/rest/auth/latest/session
auth_type = basic
auth_username = username
auth_password = password

Notes:

  • auth_url parameter is optional. If not provided, url + "/step-auth-gss" will be used for authentication.
  • auth_type parameter is optional, default value is ‘gss’.
  • auth_username and auth_password are only valid for basic authentication.
class did.plugins.jira.Issue(issue=None, prefix=None)

Jira issue investigator

static search(query, stats)

Perform issue search for given stats instance

updated(user, options)

True if the issue was commented by given user

class did.plugins.jira.JiraCreated(option, name=None, parent=None, user=None, options=None)

Created issues

fetch()
class did.plugins.jira.JiraResolved(option, name=None, parent=None, user=None, options=None)

Resolved issues

fetch()
class did.plugins.jira.JiraStats(option, name=None, parent=None, user=None)

Jira stats

order = 600
session

Initialize the session

class did.plugins.jira.JiraUpdated(option, name=None, parent=None, user=None, options=None)

Updated issues

fetch()

nitrate

Nitrate stats such as created test plans, runs, cases

Config example:

[nitrate]
type = nitrate
class did.plugins.nitrate.AutomatedCases(option, name=None, parent=None, user=None, options=None)

Automated cases created

fetch()
class did.plugins.nitrate.AutoproposedCases(option, name=None, parent=None, user=None, options=None)

Cases proposed for automation

fetch()
class did.plugins.nitrate.CopiedCases(option, name=None, parent=None, user=None, options=None)

Test cases copied

fetch()
class did.plugins.nitrate.ManualCases(option, name=None, parent=None, user=None, options=None)

Manual cases created

fetch()
class did.plugins.nitrate.NitrateStats(option, name=None, parent=None, user=None)

Nitrate stats

cases

All test cases created by the user

copies

All test case copies created by the user

order = 100
class did.plugins.nitrate.TestPlans(option, name=None, parent=None, user=None, options=None)

Test plans created

fetch()
class did.plugins.nitrate.TestRuns(option, name=None, parent=None, user=None, options=None)

Test runs finished

fetch()

rt

Request Tracker stats such as reported and resolved tickets

Config example:

[rt]
type = rt
prefix = RT
url = https://tracker.org/rt/Search/Results.tsv
class did.plugins.rt.ReportedTickets(option, name=None, parent=None, user=None, options=None)

Tickets reported

fetch()
class did.plugins.rt.RequestTracker(parent)

Request Tracker Investigator

get(path)

Perform a GET request with Kerberos authentication

search(query)

Perform request tracker search

class did.plugins.rt.RequestTrackerStats(option, name=None, parent=None, user=None)

Request Tracker

order = 500
class did.plugins.rt.ResolvedTickets(option, name=None, parent=None, user=None, options=None)

Tickets resolved

fetch()
class did.plugins.rt.Ticket(record, parent)

Request tracker ticket

trac

Trac stats such as created, accepted, updated and closed tickets

Config example:

[trac]
type = trac
prefix = TT
url = https://some.trac.com/trac/project/rpc
class did.plugins.trac.Trac(ticket=None, changelog=None, parent=None, options=None)

Trac investigator

accepted(user)

True if ticket was accepted in given time frame

closed()

True if ticket was closed in given time frame

history(user=None)

Return relevant who-did-what logs from the ticket history

static search(query, parent, options)

Perform Trac search

updated(user)

True if the user commented the ticket in given time frame

class did.plugins.trac.TracAccepted(option, name=None, parent=None)

Accepted tickets

fetch()
class did.plugins.trac.TracClosed(option, name=None, parent=None)

Closed tickets

fetch()
class did.plugins.trac.TracCommon(option, name=None, parent=None)

Common Trac Stats object for saving prefix & proxy

class did.plugins.trac.TracCreated(option, name=None, parent=None)

Created tickets

fetch()
class did.plugins.trac.TracStats(option, name=None, parent=None, user=None)

Trac stats group

order = 400
class did.plugins.trac.TracUpdated(option, name=None, parent=None)

Updated tickets

fetch()

trello

Trello actions such as created, moved or closed cards

Config example (public):

[tools]
type = trello
user = member

Config example (private):

[tools]
type = trello
apikey = ...
token = ...

Optional arguments:

board_links = g9mdhdzg
filters = createCard, updateCard,
    updateCard:idList, updateCard:closed,
    updateCheckItemStateOnCard
apikey
https://trello.com/app-key
token
http://stackoverflow.com/questions/17178907
boards
default: all
filters
default: all
class did.plugins.trello.TrelloAPI(stats, config)

Trello API

Convert board links to ids

get_actions(filters, since=None, before=None, limit=1000)

Example of data structure: https://api.trello.com/1/members/ben/actions?limit=2

class did.plugins.trello.TrelloCards(trello, filt, option, name=None, parent=None)

Trello cards updated

fetch()
class did.plugins.trello.TrelloCardsClosed(trello, filt, option, name=None, parent=None)

Trello cards closed

fetch()
class did.plugins.trello.TrelloCardsCreated(trello, filt, option, name=None, parent=None)

Trello cards created

fetch()
class did.plugins.trello.TrelloCardsMoved(trello, filt, option, name=None, parent=None)

Trello cards moved

fetch()
class did.plugins.trello.TrelloCheckItem(trello, filt, option, name=None, parent=None)

Trello checklist items completed

fetch()
class did.plugins.trello.TrelloStats(trello, filt, option, name=None, parent=None)

Trello stats

class did.plugins.trello.TrelloStatsGroup(option, name=None, parent=None, user=None)

Trello stats group

order = 450
session

Initialize the session

wiki

MoinMoin wiki stats about updated pages

Config example:

[wiki]
type = wiki
wiki test = http://moinmo.in/
class did.plugins.wiki.WikiChanges(option, name=None, parent=None, url=None)

Wiki changes

fetch()
header()

Show summary header.

merge(other)

Merge another stats.

class did.plugins.wiki.WikiStats(option, name=None, parent=None, user=None)

Wiki stats

order = 700

bitly

Bit.ly stats such as:

  • links saved

Config example:

[bitly]
type = bitly
token = ...

To get a token, see: https://bitly.com/a/oauth_apps

Available options:

--bitly-saved Links Saved
--bitly All above
class did.plugins.bitly.Bitly(parent, token=None)

Bit.ly Link History

api

Bit.ly API - user_link_history wrapper

class did.plugins.bitly.BitlyStats(option, name=None, parent=None, user=None)

Bit.ly

order = 701

Links saved

fetch()

Bit.ly API expect unix timestamps