very simple get current milestones check
This commit is contained in:
parent
106059595b
commit
3abc97e45e
|
@ -0,0 +1,4 @@
|
|||
test:
|
||||
./node_modules/.bin/mocha --compilers coffee:coffee-script --reporter spec --ui exports --bail
|
||||
|
||||
.PHONY: test
|
|
@ -14,6 +14,10 @@ Show:
|
|||
* For each issue show other tags and assignee (avatar).
|
||||
* Number of working days left.
|
||||
* To whom open issues still belong.
|
||||
* Projected ship date (project running late/not).
|
||||
* For each user/avatar what is their % progress and number of open/closed issues.
|
||||
* Heat: if we are struck/very productive for a period of time, colorize the chart line.
|
||||
* For milestones with no due date, show an estimate as to when it will probably be finished.
|
||||
|
||||
Allow:
|
||||
|
||||
|
|
231
app.coffee
231
app.coffee
|
@ -1,231 +0,0 @@
|
|||
flatiron = require 'flatiron'
|
||||
connect = require 'connect'
|
||||
https = require 'https'
|
||||
fs = require "fs"
|
||||
yaml = require "js-yaml"
|
||||
eco = require 'eco'
|
||||
|
||||
# Helper object for GitHub Issues.
|
||||
Issues =
|
||||
|
||||
# Make HTTPS GET to GitHub API v3.
|
||||
get: (path, type, callback) ->
|
||||
options =
|
||||
host: "api.github.com"
|
||||
method: "GET"
|
||||
path: path
|
||||
headers:
|
||||
'User-Agent': 'Scrum Burndown (1)'
|
||||
|
||||
if Issues.config.api_token
|
||||
options.headers.Authorization = 'token '+Issues.config.api_token
|
||||
|
||||
https.request(options, (response) ->
|
||||
if response.statusCode is 200
|
||||
json = ""
|
||||
response.on "data", (chunk) -> json += chunk
|
||||
|
||||
response.on "end", -> callback JSON.parse(json), type
|
||||
else
|
||||
throw response.statusCode
|
||||
).end()
|
||||
|
||||
# URLs to API.
|
||||
getOpenIssues: (callback) -> Issues.get "/repos/#{Issues.config.github_user}/#{Issues.config.github_project}/issues?state=open", 'issues', callback
|
||||
getClosedIssues: (callback) -> Issues.get "/repos/#{Issues.config.github_user}/#{Issues.config.github_project}/issues?state=closed", 'issues', callback
|
||||
getMilestones: (callback) -> Issues.get "/repos/#{Issues.config.github_user}/#{Issues.config.github_project}/milestones", 'milestones', callback
|
||||
|
||||
# Convert GitHub ISO 8601 to JS timestamp at the beginning of UTC day!'
|
||||
dateToTime: (date) ->
|
||||
# Some milestones do not have due dates.
|
||||
return 0 unless date?
|
||||
# Add miliseconds and create `Date`.
|
||||
date = new Date(date[0...date.length - 1] + '.000' + date.charAt date.length-1)
|
||||
# Move to the beginning of the day (at 9am BST, 8am GMT, so we do not worry about time shifts).
|
||||
date = new Date date.getFullYear(), date.getMonth(), date.getDate(), 9
|
||||
# Return timestamp.
|
||||
date.getTime()
|
||||
|
||||
# Format issues for display in a listing.
|
||||
format: (issue) ->
|
||||
# Format the timestamps.
|
||||
if issue.created_at? then issue.created_at = new Date(Issues.dateToTime(issue.created_at)).toUTCString()
|
||||
if issue.updated_at? then issue.updated_at = new Date(Issues.dateToTime(issue.updated_at)).toUTCString()
|
||||
|
||||
issue
|
||||
|
||||
# Config filters.
|
||||
app = flatiron.app
|
||||
app.use flatiron.plugins.http,
|
||||
'before': [
|
||||
connect.favicon()
|
||||
connect.static __dirname + '/public'
|
||||
]
|
||||
|
||||
# Eco templating.
|
||||
app.use
|
||||
name: "eco-templating"
|
||||
attach: (options) ->
|
||||
app.eco = (path, data, cb) ->
|
||||
fs.readFile "./templates/#{path}.eco", "utf8", (err, template) ->
|
||||
if err then cb err, null
|
||||
else
|
||||
try
|
||||
cb null, eco.render template, data
|
||||
catch e
|
||||
cb e, null
|
||||
|
||||
# Show burndown chart.
|
||||
getBurndown = ->
|
||||
console.log 'Get burndown chart'
|
||||
|
||||
resources = 3 ; store = { 'issues': [], 'milestones': [] }
|
||||
done = (data, type) =>
|
||||
# One less to do.
|
||||
resources--
|
||||
|
||||
switch type
|
||||
when 'issues' then store.issues = store.issues.concat data
|
||||
when 'milestones' then store.milestones = store.milestones.concat data
|
||||
|
||||
# Are we done?
|
||||
if resources is 0
|
||||
# Do we actually have an open milestone?
|
||||
if store.milestones.length > 0
|
||||
# Store the current milestone and its size.
|
||||
current = { 'milestone': {}, 'diff': +Infinity, 'size': 0 }
|
||||
|
||||
# Determine the 'current' milestone
|
||||
now = new Date().getTime()
|
||||
for milestone in store.milestones
|
||||
# JS expects more accuracy.
|
||||
due = Issues.dateToTime milestone['due_on']
|
||||
# Is this the 'current' one?
|
||||
diff = due - now
|
||||
if diff > 0 and diff < current.diff
|
||||
current.milestone = milestone ; current.diff = diff ; current.due = due
|
||||
|
||||
# Create n dict with all dates in the milestone span.
|
||||
days = {} ; totalDays = 0 ; totalNonWorkingDays = 0
|
||||
day = Issues.dateToTime current.milestone.created_at
|
||||
while day < current.due
|
||||
# Do we have weekends configured?
|
||||
if Issues.config.weekend? and Issues.config.weekend instanceof Array
|
||||
dayOfWeek = new Date(day).getDay()
|
||||
# Fix stupid Abrahamic tradition.
|
||||
if dayOfWeek is 0 then dayOfWeek = 7
|
||||
|
||||
# Does this day fall on a weekend?
|
||||
if dayOfWeek in Issues.config.weekend
|
||||
totalNonWorkingDays += 1
|
||||
# Save the day.
|
||||
days[day] = { 'issues': [], 'actual': 0, 'ideal': 0, 'weekend': true }
|
||||
else
|
||||
# Save the day.
|
||||
days[day] = { 'issues': [], 'actual': 0, 'ideal': 0, 'weekend': false }
|
||||
else
|
||||
# Save the day.
|
||||
days[day] = { 'issues': [], 'actual': 0, 'ideal': 0, 'weekend': false }
|
||||
|
||||
# Shift by a day.
|
||||
day += 1000 * 60 * 60 * 24
|
||||
# Increase the total count.
|
||||
totalDays += 1
|
||||
|
||||
# Now go through the issues and place them to the appropriate days.
|
||||
for issue in store.issues
|
||||
# This milestone?
|
||||
if issue.milestone?.number is current.milestone.number
|
||||
# Has a size label?
|
||||
if issue.labels?
|
||||
issue.size = do (issue) ->
|
||||
for label in issue.labels
|
||||
if label.name.indexOf("size ") is 0
|
||||
return parseInt label.name[5...]
|
||||
|
||||
if issue.size?
|
||||
# Increase the total size of the milestone.
|
||||
current.size += issue.size
|
||||
# Is it closed?
|
||||
if issue.closed_at?
|
||||
# Save it.
|
||||
days[Issues.dateToTime issue.closed_at]['issues'].push issue
|
||||
|
||||
# Calculate the predicted daily velocity.
|
||||
dailyIdeal = current['size'] / (totalDays - totalNonWorkingDays) ; ideal = current['size']
|
||||
|
||||
# Go through the days and save the number of outstanding issues size.
|
||||
for day, d of days
|
||||
# Does this day have any closed issues? Reduce the total for this milestone.
|
||||
for issue in d['issues']
|
||||
current['size'] -= issue.size
|
||||
# Save the oustanding count for that day.
|
||||
days[day].actual = current['size']
|
||||
|
||||
# Save the predicted velocity for that day if it is not a non-working day.
|
||||
ideal -= dailyIdeal unless days[day].weekend
|
||||
days[day].ideal = ideal
|
||||
|
||||
# Finally send to client.
|
||||
app.eco 'burndown',
|
||||
'days': days
|
||||
'project': Issues.config.project_name
|
||||
'base_url': Issues.config.base_url
|
||||
, (err, html) =>
|
||||
throw err if err
|
||||
@res.writeHead 200, "content-type": "text/html"
|
||||
@res.write html
|
||||
@res.end()
|
||||
|
||||
else
|
||||
# No current milestone.
|
||||
app.eco 'empty',
|
||||
'project': Issues.config.project_name
|
||||
'base_url': Issues.config.base_url
|
||||
, (err, html) =>
|
||||
throw err if err
|
||||
@res.writeHead 200, "content-type": "text/html"
|
||||
@res.write html
|
||||
@res.end()
|
||||
|
||||
# Get Milestones, Opened and Closed Tickets.
|
||||
Issues.getMilestones done
|
||||
Issues.getOpenIssues done
|
||||
Issues.getClosedIssues done
|
||||
|
||||
# Show open issues.
|
||||
getIssues = ->
|
||||
console.log 'Get open issues'
|
||||
|
||||
Issues.getOpenIssues (issues) =>
|
||||
|
||||
# Replace the dates in issues with nice dates.
|
||||
issues = ( Issues.format(issue) for issue in issues )
|
||||
|
||||
app.eco 'issues',
|
||||
'issues': issues
|
||||
'project': Issues.config.project_name
|
||||
'base_url': Issues.config.base_url
|
||||
, (err, html) =>
|
||||
throw err if err
|
||||
@res.writeHead 200, "content-type": "text/html"
|
||||
@res.write html
|
||||
@res.end()
|
||||
|
||||
# Routes
|
||||
app.router.path '/', ->
|
||||
@get getBurndown
|
||||
|
||||
app.router.path '/burndown', ->
|
||||
@get getBurndown
|
||||
|
||||
app.router.path '/issues', ->
|
||||
@get getIssues
|
||||
|
||||
# Fetch config and start server.
|
||||
fs.readFile "config.yml", "utf8", (err, data) ->
|
||||
Issues.config = yaml.load data
|
||||
|
||||
app.start process.env.PORT, (err) ->
|
||||
throw err if err
|
||||
console.log "Listening on port #{app.server.address().port}"
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"name": "github-burndown-chart",
|
||||
"version": "1.0.0-alpha",
|
||||
"description": "Shows a burndown chart for GitHub Issues",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"dependencies": {
|
||||
"async": "~0.2.9",
|
||||
"proxyquire": "~0.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "~1.12.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/radekstepan/github-burndown-chart.git"
|
||||
},
|
||||
"keywords": [
|
||||
"github",
|
||||
"issues",
|
||||
"burndown",
|
||||
"chart",
|
||||
"scrum"
|
||||
],
|
||||
"author": "Radek <dev@radekstepan.com>",
|
||||
"license": "BSD",
|
||||
"bugs": {
|
||||
"url": "https://github.com/radekstepan/github-burndown-chart/issues"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
#!/usr/bin/env coffee
|
|
@ -0,0 +1 @@
|
|||
../build/build.css
|
|
@ -0,0 +1 @@
|
|||
../build/build.js
|
|
@ -0,0 +1,481 @@
|
|||
{
|
||||
"1003692": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0004110",
|
||||
"symbol": "tin",
|
||||
"secondaryIdentifier": "CG7895"
|
||||
},
|
||||
"identifiers": {
|
||||
"tinman": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1005232": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0000099",
|
||||
"symbol": "ap",
|
||||
"secondaryIdentifier": "CG8376"
|
||||
},
|
||||
"identifiers": {
|
||||
"FBgn0000099": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1005584": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0000166",
|
||||
"symbol": "bcd",
|
||||
"secondaryIdentifier": "CG1034"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG1034": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1006039": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0001150",
|
||||
"symbol": "gt",
|
||||
"secondaryIdentifier": "CG7952"
|
||||
},
|
||||
"identifiers": {
|
||||
"gt": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1006967": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0003300",
|
||||
"symbol": "run",
|
||||
"secondaryIdentifier": "CG1849"
|
||||
},
|
||||
"identifiers": {
|
||||
"runt": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1007192": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0000606",
|
||||
"symbol": "eve",
|
||||
"secondaryIdentifier": "CG2328"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG2328": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1007568": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0003870",
|
||||
"symbol": "ttk",
|
||||
"secondaryIdentifier": "CG1856"
|
||||
},
|
||||
"identifiers": {
|
||||
"tramtrack": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1008149": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0040765",
|
||||
"symbol": "luna",
|
||||
"secondaryIdentifier": "CG33473"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG33473": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1012064": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0003866",
|
||||
"symbol": "tsh",
|
||||
"secondaryIdentifier": "CG1374"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG1374": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1013634": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0003720",
|
||||
"symbol": "tll",
|
||||
"secondaryIdentifier": "CG1378"
|
||||
},
|
||||
"identifiers": {
|
||||
"tll": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1017495": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0000028",
|
||||
"symbol": "acj6",
|
||||
"secondaryIdentifier": "CG9151"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG9151": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1019651": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0011655",
|
||||
"symbol": "Med",
|
||||
"secondaryIdentifier": "CG1775"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG1775": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1020845": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0024250",
|
||||
"symbol": "brk",
|
||||
"secondaryIdentifier": "CG9653"
|
||||
},
|
||||
"identifiers": {
|
||||
"FBgn0024250": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1021556": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0041111",
|
||||
"symbol": "lilli",
|
||||
"secondaryIdentifier": "CG8817"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG8817": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1022210": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0011766",
|
||||
"symbol": "E2f",
|
||||
"secondaryIdentifier": "CG6376"
|
||||
},
|
||||
"identifiers": {
|
||||
"E2f": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1023733": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0011648",
|
||||
"symbol": "Mad",
|
||||
"secondaryIdentifier": "CG12399"
|
||||
},
|
||||
"identifiers": {
|
||||
"Mad": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1029518": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0003460",
|
||||
"symbol": "so",
|
||||
"secondaryIdentifier": "CG11121"
|
||||
},
|
||||
"identifiers": {
|
||||
"so": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1033140": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0025800",
|
||||
"symbol": "Smox",
|
||||
"secondaryIdentifier": "CG2262"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG2262": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1035180": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0001325",
|
||||
"symbol": "Kr",
|
||||
"secondaryIdentifier": "CG3340"
|
||||
},
|
||||
"identifiers": {
|
||||
"FBgn0001251": [
|
||||
"OTHER"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1036625": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0003430",
|
||||
"symbol": "slp1",
|
||||
"secondaryIdentifier": "CG16738"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG16738": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1042703": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0001180",
|
||||
"symbol": "hb",
|
||||
"secondaryIdentifier": "CG9786"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG9786": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1045695": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0010433",
|
||||
"symbol": "ato",
|
||||
"secondaryIdentifier": "CG7508"
|
||||
},
|
||||
"identifiers": {
|
||||
"FBgn0010433": [
|
||||
"MATCH"
|
||||
],
|
||||
"ato": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1065292": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0004915",
|
||||
"symbol": "TfIIB",
|
||||
"secondaryIdentifier": "CG5193"
|
||||
},
|
||||
"identifiers": {
|
||||
"TfIIB": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1068009": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0000157",
|
||||
"symbol": "Dll",
|
||||
"secondaryIdentifier": "CG3629"
|
||||
},
|
||||
"identifiers": {
|
||||
"CG3629": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1077315": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0001077",
|
||||
"symbol": "ftz",
|
||||
"secondaryIdentifier": "CG2047"
|
||||
},
|
||||
"identifiers": {
|
||||
"ftz": [
|
||||
"MATCH"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"1145128": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila melanogaster",
|
||||
"primaryIdentifier": "FBgn0003900",
|
||||
"symbol": "twi",
|
||||
"secondaryIdentifier": "CG2956"
|
||||
},
|
||||
"identifiers": {
|
||||
"TWIST_DROME": [
|
||||
"TYPE_CONVERTED"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"6000138": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila pseudoobscura",
|
||||
"primaryIdentifier": "FBgn0075017",
|
||||
"symbol": "Dpse\ttk",
|
||||
"secondaryIdentifier": "GA14992"
|
||||
},
|
||||
"identifiers": {
|
||||
"tramtrack": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"7000252": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila simulans",
|
||||
"primaryIdentifier": "FBgn0193021",
|
||||
"symbol": "Dsim\ttk",
|
||||
"secondaryIdentifier": "GD21596"
|
||||
},
|
||||
"identifiers": {
|
||||
"tramtrack": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"7000255": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila yakuba",
|
||||
"primaryIdentifier": "FBgn0228787",
|
||||
"symbol": "Dyak\ttk",
|
||||
"secondaryIdentifier": "GE10957"
|
||||
},
|
||||
"identifiers": {
|
||||
"tramtrack": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"7010773": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila simulans",
|
||||
"primaryIdentifier": "FBgn0016352",
|
||||
"symbol": "Dsim\run",
|
||||
"secondaryIdentifier": "GD17500"
|
||||
},
|
||||
"identifiers": {
|
||||
"runt": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"7513758": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila erecta",
|
||||
"primaryIdentifier": "FBgn0085118",
|
||||
"symbol": "Dere\run",
|
||||
"secondaryIdentifier": "GG19696"
|
||||
},
|
||||
"identifiers": {
|
||||
"runt": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"7878354": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila virilis",
|
||||
"primaryIdentifier": "FBgn0013920",
|
||||
"symbol": "Dvir\run",
|
||||
"secondaryIdentifier": "GJ19252"
|
||||
},
|
||||
"identifiers": {
|
||||
"runt": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"7918344": {
|
||||
"summary": {
|
||||
"organism.name": "Drosophila yakuba",
|
||||
"primaryIdentifier": "FBgn0084618",
|
||||
"symbol": "Dyak\run",
|
||||
"secondaryIdentifier": "GE17894"
|
||||
},
|
||||
"identifiers": {
|
||||
"runt": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
},
|
||||
"17023535": {
|
||||
"summary": {
|
||||
"organism.name": "Mus musculus",
|
||||
"primaryIdentifier": "MGI:95866",
|
||||
"symbol": "gt",
|
||||
"secondaryIdentifier": null
|
||||
},
|
||||
"identifiers": {
|
||||
"gt": [
|
||||
"DUPLICATE"
|
||||
]
|
||||
},
|
||||
"type": "Gene"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>component-400</title>
|
||||
|
||||
<link href="/build.css" media="all" rel="stylesheet" type="text/css" />
|
||||
<script src="/build.js"></script>
|
||||
|
||||
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
$.getJSON('/data.json', function(data) {
|
||||
require('component-400/app').call(null, data, '#target', function(err, selected) {
|
||||
if (err) throw err;
|
||||
console.log(selected);
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "app",
|
||||
"main": "app.js",
|
||||
"version": "1.0.0-alpha",
|
||||
"dependencies": {
|
||||
"component/map": "*",
|
||||
"segmentio/extend": "*",
|
||||
"component/object": "*",
|
||||
"manuelstofer/foreach": "*",
|
||||
"component/dom": "*"
|
||||
},
|
||||
"scripts": [ ],
|
||||
"styles": [ ]
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env coffee
|
||||
req = require './request'
|
||||
|
||||
module.exports =
|
||||
'get_current': (user, repo, cb) ->
|
||||
req.milestones user, repo, (err, data) ->
|
||||
return cb err if err
|
||||
# Go through the milestones looking for one that ends/ended soonest.
|
||||
max = [ null, +Infinity ]
|
||||
( max = [ parseInt(i), int ] if (int = +new Date due_on) < max[1] for i, { due_on } of data )
|
||||
cb null, data[max[0]]
|
|
@ -0,0 +1,4 @@
|
|||
#!/usr/bin/env coffee
|
||||
module.exports =
|
||||
'milestones': (user, repo, cb) ->
|
||||
cb null, { 'real': 'one' }
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env coffee
|
||||
assert = require 'assert'
|
||||
async = require 'async'
|
||||
path = require 'path'
|
||||
proxy = require 'proxyquire'
|
||||
|
||||
req = {}
|
||||
|
||||
milestones = proxy path.resolve(__dirname, '../src/milestones.coffee'),
|
||||
'./request': req
|
||||
|
||||
module.exports =
|
||||
'get current': (done) ->
|
||||
req.milestones = (user, repo, cb) ->
|
||||
cb null, [
|
||||
{
|
||||
'number': 1
|
||||
'created_at': '2013-01-01T00:00:00Z'
|
||||
'due_on': '2013-02-01T00:00:00Z'
|
||||
}
|
||||
]
|
||||
|
||||
milestones.get_current null, null, (err, milestone) ->
|
||||
assert.ifError err
|
||||
assert.equal milestone.number, 1
|
||||
done.call null
|
Loading…
Reference in New Issue