Created
February 28, 2015 22:42
-
-
Save lightstrike/6036d676e344a6be4b7b to your computer and use it in GitHub Desktop.
Pivotal Tracker Developer Focus Metric
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # -*- coding: utf-8 -*- | |
| """ | |
| Calculates the following 'Developer Focus' metric using | |
| data from the Pivotal Tracker API: | |
| # unique developers actively working on active projects / | |
| Open stories ("started" state) from active projects | |
| For this first pass, the IDs of active projects and | |
| developers are set as environment variables. | |
| In the future, it may be possible to determine these | |
| values dynamically using the Pivotal Tracker API, | |
| though it doesn't appear to be possible as of 3.2015. | |
| """ | |
| from os import environ | |
| import requests | |
| import json | |
| def get_env_setting(setting, default=None): | |
| """ | |
| Get the environment setting or return exception | |
| """ | |
| try: | |
| var = environ.get(setting, default) if default else environ[setting] | |
| return var | |
| except KeyError: | |
| error_msg = "Set the %s env variable" % setting | |
| raise KeyError(error_msg) | |
| def get_env_list(setting, structure=int, delimiter=','): | |
| """ | |
| converts delimited string variable into a Python list | |
| """ | |
| env_variable = get_env_setting(setting).replace(" ", "") | |
| return map(structure, env_variable.split(delimiter)) | |
| # Get API token for Pivotal Tracker | |
| # Found at https://www.pivotaltracker.com/profile | |
| PIVOTAL_TOKEN = get_env_setting('PIVOTAL_API_TOKEN') | |
| TRACKER_HEADERS = {'X-TrackerToken': PIVOTAL_TOKEN} | |
| # Get active project and developer IDs for API lookups | |
| ACTIVE_PROJECTS = get_env_list('ACTIVE_PIVOTAL_PROJECTS') | |
| ACTIVE_DEVELOPERS = get_env_list('ACTIVE_PIVOTAL_DEVELOPERS') | |
| # Set Pivotal Tracker Endpoints | |
| # https://www.pivotaltracker.com/help/api/rest/v5#Stories | |
| OPEN_STORIES_URL = "https://www.pivotaltracker.com/services/v5/projects/{project_id}/stories?with_state=started" | |
| PROJECTS_URL = "https://www.pivotaltracker.com/services/v5/projects" | |
| # Set Slack endpoint for posting metric (optional) | |
| SLACK_METRICS_URL = get_env_setting('SLACK_METRICS_URL', 'console') | |
| SLACK_METRICS_CHANNEL = get_env_setting('SLACK_METRICS_CHANNEL') | |
| # Set metric inputs | |
| active_developers = len(ACTIVE_DEVELOPERS) | |
| total_open_stories = 0 | |
| def get_open_stories(project_id): | |
| """ | |
| return number of open stories given a | |
| Pivotal Tracker project ID | |
| """ | |
| request_url = OPEN_STORIES_URL.format(project_id=project_id) | |
| # https://www.pivotaltracker.com/help/api#Request_Authentication_and_CORS | |
| stories_request = requests.get(request_url, headers=TRACKER_HEADERS) | |
| return json.loads(stories_request.content) | |
| for project in ACTIVE_PROJECTS: | |
| """ | |
| get open stories for all active projects and add to tally | |
| If successful response, json.loads will return a list object, | |
| if failed response, json.loads will return a dict object. | |
| """ | |
| open_stories = get_open_stories(project) | |
| if type(open_stories) == list: | |
| total_open_stories += len(open_stories) | |
| else: | |
| raise Exception("This request was not successful. Please try again later.") | |
| # Calculate active project string for display | |
| projects_request = requests.get(PROJECTS_URL, headers=TRACKER_HEADERS) | |
| projects_json = json.loads(projects_request.content) | |
| active_projects = [p['name'] for p in projects_json if p['id'] in ACTIVE_PROJECTS] | |
| # calculate metric and | |
| developer_focus = (float(active_developers)/float(total_open_stories))*100 | |
| metrics_text = ("Developer Focus: {focus_metric}% ({developers} " | |
| "Developers / {stories} Open Stories) in {projects} " | |
| "active projects ({active_projects}).").format( | |
| focus_metric=developer_focus, | |
| developers=active_developers, | |
| stories=total_open_stories, | |
| projects=len(active_projects), | |
| active_projects=', '.join(active_projects) | |
| ) | |
| # if SLACK_URL, post to SLACK room, otherwise just print to console | |
| if not SLACK_METRICS_URL == 'console': | |
| slack_payload = { | |
| "channel": SLACK_METRICS_CHANNEL, | |
| "username": "metricsbot", | |
| "text": metrics_text, | |
| "icon_emoji": ":chart:" | |
| } | |
| requests.post(SLACK_METRICS_URL, data=json.dumps(slack_payload), headers=TRACKER_HEADERS) | |
| else: | |
| print(metrics_text) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment