kood 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,10 @@
1
+ class Kood::CLI < Thor
2
+
3
+ desc "switch <BOARD-ID>", "Switches to the specified board"
4
+ def switch(board_id)
5
+ Kood::Board.get!(board_id).select
6
+ ok "Board switched to #{ board_id }."
7
+ end
8
+ map 'select' => 'switch'
9
+
10
+ end
@@ -0,0 +1,95 @@
1
+ require 'toystore'
2
+
3
+ module Kood
4
+ extend self
5
+
6
+ # Path to where data, such as user configurations and boards, is stored
7
+ KOOD_PATH = ".kood"
8
+ KOOD_ROOT = Pathname(File.expand_path("~")).join(KOOD_PATH)
9
+
10
+ # Check if the environment is set to test or production mode
11
+ def test?
12
+ ENV['RACK_ENV'] == 'test'
13
+ end
14
+
15
+ # Default path to the repository where boards are stored
16
+ # @return [String] path to the main repository
17
+ def root
18
+ @root ||= test? ? KOOD_ROOT.join('storage-test').to_s : KOOD_ROOT.join('storage').to_s
19
+ end
20
+
21
+ # File where configurations are stored
22
+ # @return [String] the name of the file
23
+ def config_path
24
+ test? ? "config-test.yml" : "config.yml"
25
+ end
26
+
27
+ # Initialize a repo (and create a master branch since some git commands
28
+ # rely on its existence)
29
+ def repo(path = root)
30
+ @repo ||= {}
31
+ @repo[path] ||= begin
32
+ new_repo = Grit::Repo.init(path)
33
+ Dir.chdir(path) # TODO This is not ideal but otherwise it would be necessary to pass
34
+ # a :chdir option in all calls to Grit. This may be a bug in Grit related with the
35
+ # --work-tree flag
36
+
37
+ unless new_repo.branches.any? { |b| b.name == 'master' } # Check if master exists
38
+ index = new_repo.index
39
+ index.add('k', '')
40
+ index.commit("init")
41
+ end
42
+ new_repo # If this has been done before, the above command will do nothing
43
+ end
44
+ end
45
+
46
+ # Default colors to represent some common card labels
47
+ # @return [Hash] The keys are labels and values are the associated colors
48
+ def default_labels
49
+ labels = { 'user-story' => 'magenta', 'tech-story' => 'green' }
50
+ %w{ bug issue }.each { |k| labels[k] = 'red' }
51
+ %w{ improvement enhancement }.each { |k| labels[k] = 'yellow' }
52
+ %w{ documentation docs }.each { |k| labels[k] = 'cyan' }
53
+ labels['other'] = 'blue'
54
+ return labels
55
+ end
56
+
57
+ # Live configurations that need to be saved.
58
+ class Config
59
+ include Toy::Store
60
+
61
+ # There's no use in tracking changes made to the configurations, so instead of using
62
+ # the git adapter, use a simple configuration file
63
+ adapter :user_config, {}
64
+
65
+ # Associations
66
+ list :boards, Kood::Board
67
+
68
+ # Attributes
69
+ attribute :custom_repos, Hash # Support storing boards in external repos
70
+ attribute :current_board_id, String # Can be stored externally, so checkout isn't enough
71
+ attribute :labels, Hash, default: Kood.default_labels
72
+
73
+ # Only one instance of Config should be created
74
+ # @return [Kood::Config] The singleton instance to be used outside this module
75
+ def self.instance
76
+ @@instance ||= get_or_create('config')
77
+ end
78
+
79
+ # Helper method to set the `current_board_id` attribute
80
+ def select_board(board_id)
81
+ self.current_board_id = board_id
82
+ save! if changed?
83
+ end
84
+
85
+ # Sets the `current_board_id` attribute to nil
86
+ def unselect_board
87
+ select_board nil
88
+ end
89
+ end
90
+
91
+ # @return [Kood::Config] The singleton instance to be used outside this module
92
+ def config
93
+ Config.instance
94
+ end
95
+ end
@@ -0,0 +1,8 @@
1
+ module Kood
2
+ class Error < StandardError; end
3
+ class TypeError < TypeError; end
4
+
5
+ class NotFound < Error; end
6
+ class NotUnique < Error; end
7
+ class MultipleDocumentsFound < Error; end
8
+ end
@@ -0,0 +1,65 @@
1
+ module Grit
2
+ # Reopen the `Grit::Repo` class and add some useful methods.
3
+ #
4
+ # This code is based on [git.io/git-up](//git.io/git-up).
5
+ # A special Thank You to the authors.
6
+ #
7
+ class Repo
8
+ # Automatically stashes and unstashes changes in the current branch.
9
+ # @yield The code block is executed after stashing all existing changes, if any. After
10
+ # executing the block, a `stash pop` applies changes and deletes the stash
11
+ def with_stash(options = {})
12
+ stashed = false
13
+ if change_count(options) > 0
14
+ git.stash(options)
15
+ stashed = true
16
+ end
17
+ yield
18
+ ensure
19
+ git.stash(options, "pop") if stashed
20
+ end
21
+
22
+ # Checkout a specific branch and then return to the previously checked out branch.
23
+ # @yield The code block is executed after a `checkout`. After executing the block,
24
+ # the previous branch is checked out again.
25
+ # @raise [CheckoutError] If it fails to checkout the branch
26
+ def with_branch(options = {}, branch_name)
27
+ unless head.respond_to?(:name)
28
+ raise CheckoutError, "It seems you changed things manually. You are not on a branch."
29
+ end
30
+ current_branch = head.name
31
+ checkout!(options, branch_name)
32
+ yield
33
+ ensure
34
+ checkout!(options, current_branch) unless on_branch? current_branch
35
+ end
36
+
37
+ # Utility method that does both `with_stash` and `with_branch`
38
+ # @see #with_stash
39
+ # @see #with_branch
40
+ def with_stash_and_branch(stash_options = {}, branch_options = {}, branch_name)
41
+ with_stash(stash_options) do
42
+ with_branch(branch_options, branch_name) { yield }
43
+ end
44
+ end
45
+
46
+ # Check if the currently checked out branch matches a given branch name
47
+ def on_branch?(branch_name = nil)
48
+ head.respond_to?(:name) and head.name == branch_name
49
+ end
50
+
51
+ private
52
+
53
+ def change_count(options = {})
54
+ options = { :porcelain => true, :'untracked-files' => 'no' }.merge(options)
55
+ git.status(options).split("\n").count
56
+ end
57
+
58
+ def checkout!(options = {}, branch)
59
+ git.checkout(options, branch)
60
+ raise CheckoutError, "Failed to checkout #{ branch }." unless on_branch? branch
61
+ end
62
+ end
63
+
64
+ class CheckoutError < StandardError; end
65
+ end
@@ -0,0 +1,36 @@
1
+ require 'toystore'
2
+
3
+ module Kood
4
+ class List
5
+ include Toy::Store
6
+
7
+ # Associations
8
+ list :cards, Card, dependent: true
9
+
10
+ # Observers
11
+ before_create :id_is_unique?
12
+
13
+ def self.get!(id)
14
+ super rescue raise NotFound, "The specified list does not exist."
15
+ end
16
+
17
+ private
18
+
19
+ # ToyStore supports adapters per model but this program needs an adapter per instance
20
+ def self.with_adapter(branch, root)
21
+ current_client = adapter.client
22
+ current_options = adapter.options
23
+
24
+ adapter :git, Kood.repo(root), branch: branch, path: 'lists'
25
+ Card.with_adapter(branch, root) do
26
+ yield
27
+ end
28
+ ensure
29
+ adapter :git, current_client, current_options
30
+ end
31
+
32
+ def id_is_unique?
33
+ raise NotUnique, "A list with this ID already exists." unless List.get(id).nil?
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,3 @@
1
+ module Kood
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,74 @@
1
+ .\" generated with Ronn/v0.7.3
2
+ .\" http://github.com/rtomayko/ronn/tree/0.7.3
3
+ .
4
+ .TH "KOOD" "1" "January 2013" "" ""
5
+ .
6
+ .SH "NAME"
7
+ \fBkood\fR \- sample help page
8
+ .
9
+ .SH "SYNOPSIS"
10
+ \fBkood\fR [\fIformat\fR\.\.\.] \fIfile\fR\.\.\.
11
+ .
12
+ .br
13
+ \fBkood\fR \fB\-m\fR|\fB\-\-man\fR \fIfile\fR\.\.\.
14
+ .
15
+ .br
16
+ \fBkood\fR \fB\-S\fR|\fB\-\-server\fR \fIfile\fR\.\.\.
17
+ .
18
+ .br
19
+ \fBkood\fR \fB\-\-pipe\fR \fIfile\fR
20
+ .
21
+ .br
22
+ \fBkood\fR < \fIfile\fR
23
+ .
24
+ .SH "DESCRIPTION"
25
+ \fBKood\fR is a CLI for taskboards with a minimal self\-hosted web interface\.
26
+ .
27
+ .SH "FILES"
28
+ Sed posuere consectetur est at lobortis\. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus\. Curabitur blandit tempus porttitor\. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit\. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus\. Praesent commodo cursus magna, vel scelerisque nisl consectetur et\. Curabitur blandit tempus porttitor\.
29
+ .
30
+ .P
31
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit\. Donec ullamcorper nulla non metus auctor fringilla\. Aenean eu leo quam\. Pellentesque ornare sem lacinia quam venenatis vestibulum\. Curabitur blandit tempus porttitor\.
32
+ .
33
+ .SH "OPTIONS"
34
+ These options control things\.
35
+ .
36
+ .TP
37
+ \fB\-s\fR, \fB\-\-sample\fR
38
+ Aenean eu leo quam\. Pellentesque ornare sem lacinia quam venenatis vestibulum\. Maecenas faucibus mollis interdum\. Curabitur blandit tempus porttitor\.
39
+ .
40
+ .TP
41
+ \fB\-L\fR, \fB\-\-lorem\fR
42
+ Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor\. Cras mattis consectetur purus sit amet fermentum\.
43
+ .
44
+ .TP
45
+ \fB\-\-pipe\fR
46
+ Don\'t generate files, write generated output to standard output\. This is the default behavior when ronn source text is piped in on standard input and no \fIfile\fR arguments are provided\.
47
+ .
48
+ .P
49
+ Miscellaneous options:
50
+ .
51
+ .TP
52
+ \fB\-e\fR, \fB\-\-example\fR
53
+ Porta risus etiam consectetur vestibulum\.
54
+ .
55
+ .SH "EXAMPLES"
56
+ Vestibulum id ligula porta felis euismod semper:
57
+ .
58
+ .IP "" 4
59
+ .
60
+ .nf
61
+
62
+ $ kood \-\-clone my\-board new\-board
63
+ $ kood \-\-c my\-board new\-board
64
+ $ kood \-\-assigned user@server status
65
+ .
66
+ .fi
67
+ .
68
+ .IP "" 0
69
+ .
70
+ .SH "BUGS"
71
+ \fBKood\fR is a work in progress\.
72
+ .
73
+ .SH "SEE ALSO"
74
+ kood\-card(1), kood\-status(1)
@@ -0,0 +1,150 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv='content-type' value='text/html;charset=utf8'>
5
+ <meta name='generator' value='Ronn/v0.7.3 (http://github.com/rtomayko/ronn/tree/0.7.3)'>
6
+ <title>kood(1) - sample help page</title>
7
+ <style type='text/css' media='all'>
8
+ /* style: man */
9
+ body#manpage {margin:0}
10
+ .mp {max-width:100ex;padding:0 9ex 1ex 4ex}
11
+ .mp p,.mp pre,.mp ul,.mp ol,.mp dl {margin:0 0 20px 0}
12
+ .mp h2 {margin:10px 0 0 0}
13
+ .mp > p,.mp > pre,.mp > ul,.mp > ol,.mp > dl {margin-left:8ex}
14
+ .mp h3 {margin:0 0 0 4ex}
15
+ .mp dt {margin:0;clear:left}
16
+ .mp dt.flush {float:left;width:8ex}
17
+ .mp dd {margin:0 0 0 9ex}
18
+ .mp h1,.mp h2,.mp h3,.mp h4 {clear:left}
19
+ .mp pre {margin-bottom:20px}
20
+ .mp pre+h2,.mp pre+h3 {margin-top:22px}
21
+ .mp h2+pre,.mp h3+pre {margin-top:5px}
22
+ .mp img {display:block;margin:auto}
23
+ .mp h1.man-title {display:none}
24
+ .mp,.mp code,.mp pre,.mp tt,.mp kbd,.mp samp,.mp h3,.mp h4 {font-family:monospace;font-size:14px;line-height:1.42857142857143}
25
+ .mp h2 {font-size:16px;line-height:1.25}
26
+ .mp h1 {font-size:20px;line-height:2}
27
+ .mp {text-align:justify;background:#fff}
28
+ .mp,.mp code,.mp pre,.mp pre code,.mp tt,.mp kbd,.mp samp {color:#131211}
29
+ .mp h1,.mp h2,.mp h3,.mp h4 {color:#030201}
30
+ .mp u {text-decoration:underline}
31
+ .mp code,.mp strong,.mp b {font-weight:bold;color:#131211}
32
+ .mp em,.mp var {font-style:italic;color:#232221;text-decoration:none}
33
+ .mp a,.mp a:link,.mp a:hover,.mp a code,.mp a pre,.mp a tt,.mp a kbd,.mp a samp {color:#0000ff}
34
+ .mp b.man-ref {font-weight:normal;color:#434241}
35
+ .mp pre {padding:0 4ex}
36
+ .mp pre code {font-weight:normal;color:#434241}
37
+ .mp h2+pre,h3+pre {padding-left:0}
38
+ ol.man-decor,ol.man-decor li {margin:3px 0 10px 0;padding:0;float:left;width:33%;list-style-type:none;text-transform:uppercase;color:#999;letter-spacing:1px}
39
+ ol.man-decor {width:100%}
40
+ ol.man-decor li.tl {text-align:left}
41
+ ol.man-decor li.tc {text-align:center;letter-spacing:4px}
42
+ ol.man-decor li.tr {text-align:right;float:right}
43
+ </style>
44
+ </head>
45
+ <!--
46
+ The following styles are deprecated and will be removed at some point:
47
+ div#man, div#man ol.man, div#man ol.head, div#man ol.man.
48
+
49
+ The .man-page, .man-decor, .man-head, .man-foot, .man-title, and
50
+ .man-navigation should be used instead.
51
+ -->
52
+ <body id='manpage'>
53
+ <div class='mp' id='man'>
54
+
55
+ <div class='man-navigation' style='display:none'>
56
+ <a href="#NAME">NAME</a>
57
+ <a href="#SYNOPSIS">SYNOPSIS</a>
58
+ <a href="#DESCRIPTION">DESCRIPTION</a>
59
+ <a href="#FILES">FILES</a>
60
+ <a href="#OPTIONS">OPTIONS</a>
61
+ <a href="#EXAMPLES">EXAMPLES</a>
62
+ <a href="#BUGS">BUGS</a>
63
+ <a href="#SEE-ALSO">SEE ALSO</a>
64
+ </div>
65
+
66
+ <ol class='man-decor man-head man head'>
67
+ <li class='tl'>kood(1)</li>
68
+ <li class='tc'></li>
69
+ <li class='tr'>kood(1)</li>
70
+ </ol>
71
+
72
+ <h2 id="NAME">NAME</h2>
73
+ <p class="man-name">
74
+ <code>kood</code> - <span class="man-whatis">sample help page</span>
75
+ </p>
76
+
77
+ <h2 id="SYNOPSIS">SYNOPSIS</h2>
78
+
79
+ <p><code>kood</code> [<var>format</var>...] <var>file</var>...<br />
80
+ <code>kood</code> <code>-m</code>|<code>--man</code> <var>file</var>...<br />
81
+ <code>kood</code> <code>-S</code>|<code>--server</code> <var>file</var>...<br />
82
+ <code>kood</code> <code>--pipe</code> <var>file</var><br />
83
+ <code>kood</code> &lt; <var>file</var></p>
84
+
85
+ <h2 id="DESCRIPTION">DESCRIPTION</h2>
86
+
87
+ <p><strong>Kood</strong> is a CLI for taskboards with a minimal self-hosted web interface.</p>
88
+
89
+ <h2 id="FILES">FILES</h2>
90
+
91
+ <p>Sed posuere consectetur est at lobortis. Fusce dapibus, tellus ac cursus commodo,
92
+ tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Curabitur
93
+ blandit tempus porttitor. Duis mollis, est non commodo luctus, nisi erat porttitor
94
+ ligula, eget lacinia odio sem nec elit. Cum sociis natoque penatibus et magnis dis
95
+ parturient montes, nascetur ridiculus mus. Praesent commodo cursus magna, vel
96
+ scelerisque nisl consectetur et. Curabitur blandit tempus porttitor.</p>
97
+
98
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec ullamcorper nulla
99
+ non metus auctor fringilla. Aenean eu leo quam. Pellentesque ornare sem lacinia
100
+ quam venenatis vestibulum. Curabitur blandit tempus porttitor.</p>
101
+
102
+ <h2 id="OPTIONS">OPTIONS</h2>
103
+
104
+ <p>These options control things.</p>
105
+
106
+ <dl>
107
+ <dt><code>-s</code>, <code>--sample</code></dt><dd><p>Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum.
108
+ Maecenas faucibus mollis interdum. Curabitur blandit tempus porttitor.</p></dd>
109
+ <dt><code>-L</code>, <code>--lorem</code></dt><dd><p>Vivamus sagittis lacus vel augue laoreet rutrum faucibus dolor auctor.
110
+ Cras mattis consectetur purus sit amet fermentum.</p></dd>
111
+ <dt class="flush"><code>--pipe</code></dt><dd><p>Don't generate files, write generated output to standard output. This is the
112
+ default behavior when ronn source text is piped in on standard input and no
113
+ <var>file</var> arguments are provided.</p></dd>
114
+ </dl>
115
+
116
+
117
+ <p>Miscellaneous options:</p>
118
+
119
+ <dl>
120
+ <dt><code>-e</code>, <code>--example</code></dt><dd>Porta risus etiam consectetur vestibulum.</dd>
121
+ </dl>
122
+
123
+
124
+ <h2 id="EXAMPLES">EXAMPLES</h2>
125
+
126
+ <p>Vestibulum id ligula porta felis euismod semper:</p>
127
+
128
+ <pre><code>$ kood --clone my-board new-board
129
+ $ kood --c my-board new-board
130
+ $ kood --assigned user@server status
131
+ </code></pre>
132
+
133
+ <h2 id="BUGS">BUGS</h2>
134
+
135
+ <p><strong>Kood</strong> is a work in progress.</p>
136
+
137
+ <h2 id="SEE-ALSO">SEE ALSO</h2>
138
+
139
+ <p><span class="man-ref">kood-card<span class="s">(1)</span></span>, <span class="man-ref">kood-status<span class="s">(1)</span></span></p>
140
+
141
+
142
+ <ol class='man-decor man-foot man foot'>
143
+ <li class='tl'></li>
144
+ <li class='tc'>January 2013</li>
145
+ <li class='tr'>kood(1)</li>
146
+ </ol>
147
+
148
+ </div>
149
+ </body>
150
+ </html>