-
Notifications
You must be signed in to change notification settings - Fork 0
/
LsStory.hs
288 lines (263 loc) · 8.64 KB
/
LsStory.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
{-# LANGUAGE DeriveDataTypeable #-}
module Main where
import System.Console.CmdArgs
import Data.Data
import Data.List (intercalate)
import Data.Maybe (fromMaybe, isNothing)
import Control.Applicative( (<*>) )
import Data.Monoid (mconcat)
import Trajectory.Private.Config (withKey)
import Trajectory.API (getStories, Story(..), Iteration(..))
main = do
args <- cmdArgs lsStoryArgDefinition
withKey (profileName args) $ \key -> do
stories <- getStories key (accountName args) (projectName args)
putStrLn $ either (\error -> "Error: " ++ show error)
(handle args)
stories
handle :: LsStoryArg -> ([Story],[Iteration]) -> String
handle args (stories,iterations) =
let filters = buildFilters args iterations
renderer = buildRenderer args in
renderer $ filters `pipe` stories
where
pipe :: [ a -> a ] -> (a -> a)
pipe = foldr (.) id
buildRenderer args [] = ""
buildRenderer args stories
| onlyNext args && null nonMilestones = ""
| detailedOutput args && onlyNext args =
head $ map detailedFormatter nonMilestones
| detailedOutput args =
intercalate "\n\n" $ map detailedFormatter stories
| onlyNext args =
head $ map simpleFormatter nonMilestones
| otherwise =
intercalate "\n" $ map simpleFormatter stories
where
nonMilestones = skipMilestones stories
skipMilestones = filter $ ("Milestone" /=) . storyTaskType
detailedFormatter story =
title ++ "\n" ++ origins ++ "\n" ++ overall
where
title = milestonePrefix story ++ storyTitle story
overall = intercalate "\t" $ [
"id: " ++ (show $ storyId story)
,"points: " ++ (show $ storyPoints story)
,"comments: " ++ (show $ storyCommentsCount story)
]
origins = intercalate "\t" $ [
(fromMaybe "unassigned" $ storyAssigneeName story)
,(maybe "free-floating" ("idea: " ++) $ storyIdeaSubject story)
]
simpleFormatter story = milestonePrefix story ++ storyTitle story
milestonePrefix story
| storyTaskType story == "Milestone" = "^^^ "
| otherwise = ""
buildFilters :: LsStoryArg -> [Iteration] -> [ [Story] -> [Story] ]
buildFilters args iterations = filters <*> [args]
where filters = [
ideaFilter
,beforeMilestoneFilter
,estimationFilter
,assignmentFilter
,stateFilter
,neededFilter
,iterationFilter iterations
,deletionsFilter
]
ideaFilter args
| null summaries && not limitedToNullIdeas = id
| null summaries && limitedToNullIdeas =
filter (isNothing . storyIdeaSubject)
| otherwise = filter ideaElements
where
summaries = ideaSummaries args
limitedToNullIdeas = showNullIdeas args
ideaElements story =
maybe limitedToNullIdeas
(\summary -> summary `elem` summaries)
(storyIdeaSubject story)
beforeMilestoneFilter args
| isNothing $ beforeMilestone args = id
| otherwise = takeWhile notTheMilestone
where
(Just milestoneTitle) = beforeMilestone args
notTheMilestone story =
(storyTaskType story /= "Milestone") &&
(storyTitle story /= milestoneTitle)
estimationFilter args
| null (showEstimate args) && not (showUnestimated args) = id
| null $ showEstimate args =
filter (\story -> (storyPoints story) == 0)
| not $ showUnestimated args =
filter (\story -> (storyPoints story) `elem` (showEstimate args))
| otherwise =
filter (\story -> (storyPoints story) `elem` [0]++(showEstimate args))
assignmentFilter args
| null assignments && not limitedToUnassigned = id
| null assignments = filter (isNothing . storyAssigneeName)
| otherwise = filter assignmentElements
where
limitedToUnassigned = showUnassigned args
assignments = showAssigned args
assignmentElements story =
maybe limitedToUnassigned
(\assignment -> assignment `elem` assignments)
(storyAssigneeName story)
stateFilter args =
filter (\story -> (storyState story) `elem` states)
where
allStates =
["unstarted", "started", "finished", "done", "accepted", "rejected"]
stateBits = [(showUnstarted args)
,(showStarted args)
,(showFinished args)
,(showDone args)
,(showAccepted args)
,(showRejected args)]
states =
if or stateBits
then map fst $ filter snd $ zip allStates stateBits
else allStates
neededFilter args
| showDesignNeeded args && showDevelopmentNeeded args =
filter (\story -> storyDesignNeeded story && storyDevelopmentNeeded story)
| showDesignNeeded args = filter storyDesignNeeded
| showDevelopmentNeeded args = filter storyDevelopmentNeeded
| otherwise = id
iterationFilter iterations args
| showAllIterations args = id
| showCurrentIteration args && (present $ showIteration args) =
filter (storyInIterations $ [currentIteration] ++ desiredIterations)
| present $ showIteration args = filter (storyInIterations desiredIterations)
| otherwise = filter (storyInIterations [currentIteration])
where
currentIteration = head $ filter iterationIsCurrent iterations
present = not . null
desiredIterations = filter (\iteration ->
(iterationStartsOn iteration) `elem` (showIteration args)
) iterations
storyInIterations its story =
(storyIterationId story) `elem` (map iterationId its)
deletionsFilter args = filter (not . storyDeleted)
data LsStoryArg = LsStoryArg {
profileName :: String
,ideaSummaries :: [String]
,showNullIdeas :: Bool
,beforeMilestone :: Maybe String
,showEstimate :: [Int]
,showUnestimated :: Bool
,showAssigned :: [String]
,showUnassigned :: Bool
,showDesignNeeded :: Bool
,showDevelopmentNeeded :: Bool
,showUnstarted :: Bool
,showStarted :: Bool
,showFinished :: Bool
,showDone :: Bool
,showAccepted :: Bool
,showRejected :: Bool
,showAllIterations :: Bool
,showCurrentIteration :: Bool
,showIteration :: [String]
,detailedOutput :: Bool
,onlyNext :: Bool
,accountName :: String
,projectName :: String
} deriving (Show, Data, Typeable)
lsStoryArgDefinition = LsStoryArg {
profileName = "default"
&= explicit
&= name "profile"
&= groupname "Common flags"
&= help "The profile name to use [default]"
,ideaSummaries = def
&= explicit
&= name "idea"
&= groupname "Filtering"
&= help "Stories matching this idea"
,showNullIdeas = def
&= explicit
&= name "unset-idea"
&= help "Stories without an idea"
,beforeMilestone = def
&= explicit
&= name "before-milestone"
&= help "Stories before the given milestone"
,showUnestimated = def
&= explicit
&= name "unestimated"
&= help "Unestimated stories"
,showEstimate = def
&= explicit
&= name "estimate"
&= help "Stories with the given estimate"
,showUnassigned = def
&= explicit
&= name "unassigned"
&= help "Unassigned stories"
,showAssigned = def
&= explicit
&= name "assigned"
&= help "Stories assigned to the named person"
,showDesignNeeded = def
&= explicit
&= name "design"
&= help "Stories that need design"
,showDevelopmentNeeded = def
&= explicit
&= name "development"
&= help "Stories that need development"
,showUnstarted = def
&= explicit
&= name "unstarted"
&= groupname "Filtering on state"
&= help "Unstarted stories"
,showStarted = def
&= explicit
&= name "started"
&= help "Started stories"
,showFinished = def
&= explicit
&= name "finished"
&= help "Finished stories"
,showDone = def
&= explicit
&= name "done"
&= help "Stories in the done state"
,showAccepted = def
&= explicit
&= name "accepted"
&= help "Stories which have been accepted"
,showRejected = def
&= explicit
&= name "rejected"
&= help "Stories which have been rejected"
,showAllIterations = def
&= explicit
&= name "all-iterations"
&= groupname "Iteration filtering"
&= help "Stories from all iterations"
,showCurrentIteration = def
&= explicit
&= name "current-iteration"
&= help "Stories from the current iteration"
,showIteration = def
&= explicit
&= name "iteration"
&= help "Stories from the named iteration"
,onlyNext = def
&= explicit
&= name "next"
&= groupname "Formatting"
&= help "Only show the next matching story"
,detailedOutput = def
&= explicit
&= name "long"
&= name "l"
&= groupname "Formatting"
&= help "Show story details"
,accountName = def &= argPos 0
,projectName = def &= argPos 1
} &= program "lsstory" &= helpArg [groupname "Common flags"]