workroom 0.1.0 → 1.0.0
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.
- checksums.yaml +4 -4
- data/README.md +32 -9
- data/bin/workroom +2 -2
- data/lib/workroom/commands.rb +237 -40
- data/lib/workroom/config.rb +59 -0
- data/lib/workroom/name_generator.rb +42 -0
- data/lib/workroom/version.rb +1 -1
- metadata +17 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3583c94db1c58b26989df8e310ae2550460fd54fda21ba4bcad2837ee758b738
|
|
4
|
+
data.tar.gz: c3de17570cc26d2c477af06bac848e523b9d862024e2d26a042fb4876fec82ad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6435ed5642829932a7ce87b506655140cfc7418180a47e9695d8b33ae4be39f1c603115a2fef4538c456563412b3e1b62a9bf100ecbfecc74755a81842f8fa1f
|
|
7
|
+
data.tar.gz: e55f11b6f8cdb53343991f4b21cbbbd056a4ae6f718516346586a1943f34bbedc61638a6c5af744f2dfe6df9506014cc468e47bcabdd38e29a913d95601f7447
|
data/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Workroom
|
|
2
2
|
|
|
3
|
-
Create and manage local development workrooms using [
|
|
3
|
+
Create and manage local development workrooms using [Git](https://git-scm.com/) worktrees or [Jujutsu](https://martinvonz.github.io/jj/) workspaces.
|
|
4
4
|
|
|
5
|
-
A workroom is an isolated copy of your project
|
|
5
|
+
A workroom is an isolated copy of your project, allowing you to work on multiple branches or features simultaneously without stashing or switching contexts. Workrooms are created under a centralized directory (`~/workrooms` by default, configurable via `workrooms_dir` in `~/.config/workroom/config.json`).
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -23,17 +23,29 @@ gem install workroom
|
|
|
23
23
|
## Requirements
|
|
24
24
|
|
|
25
25
|
- Ruby >= 3.1
|
|
26
|
-
- [JJ (Jujutsu)](https://martinvonz.github.io/jj/) or Git
|
|
26
|
+
- [JJ (Jujutsu)](https://martinvonz.github.io/jj/) or [Git](https://git-scm.com/)
|
|
27
27
|
|
|
28
28
|
## Usage
|
|
29
29
|
|
|
30
30
|
### Create a workroom
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
workroom create
|
|
33
|
+
workroom create
|
|
34
34
|
```
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
A random friendly name (e.g. `swift-meadow`) is auto-generated. Workroom automatically detects whether you're using JJ or Git and uses the appropriate mechanism (JJ workspace or git worktree).
|
|
37
|
+
|
|
38
|
+
Alias: `workroom c`
|
|
39
|
+
|
|
40
|
+
### List workrooms
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
workroom list
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Lists all workrooms for the current project. When run from outside a known project, lists all workrooms grouped by parent project. When run from inside a workroom, shows the parent project path.
|
|
47
|
+
|
|
48
|
+
Aliases: `workroom ls`, `workroom l`
|
|
37
49
|
|
|
38
50
|
### Delete a workroom
|
|
39
51
|
|
|
@@ -43,14 +55,25 @@ workroom delete my-feature
|
|
|
43
55
|
|
|
44
56
|
Removes the workspace/worktree and cleans up the directory. You'll be prompted for confirmation before deletion.
|
|
45
57
|
|
|
58
|
+
When run without a name, an interactive multi-select menu is shown, allowing you to pick one or more workrooms to delete:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
workroom delete
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
To skip the confirmation prompt (useful for scripting), pass `--confirm` with the workroom name:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
workroom delete my-feature --confirm my-feature
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Alias: `workroom d`
|
|
71
|
+
|
|
46
72
|
### Options
|
|
47
73
|
|
|
48
74
|
- `-v`, `--verbose` - Print detailed output
|
|
49
75
|
- `-p`, `--pretend` - Run through the command without making changes (dry run)
|
|
50
|
-
|
|
51
|
-
### Naming rules
|
|
52
|
-
|
|
53
|
-
Workroom names must be alphanumeric (dashes and underscores allowed) and must not start or end with a dash or underscore.
|
|
76
|
+
- `--confirm NAME` - Skip delete confirmation when NAME matches the workroom being deleted
|
|
54
77
|
|
|
55
78
|
## Setup and teardown scripts
|
|
56
79
|
|
data/bin/workroom
CHANGED
data/lib/workroom/commands.rb
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require 'open3'
|
|
4
4
|
require 'thor'
|
|
5
|
+
require 'tty-prompt'
|
|
6
|
+
require 'pathname'
|
|
5
7
|
|
|
6
8
|
module Workroom
|
|
7
9
|
class Commands < Thor
|
|
@@ -19,15 +21,19 @@ module Workroom
|
|
|
19
21
|
true
|
|
20
22
|
end
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
map 'c' => :create
|
|
25
|
+
map 'd' => :delete
|
|
26
|
+
map %w[ls l] => :list
|
|
27
|
+
|
|
28
|
+
desc 'create|c', 'Create a new workroom'
|
|
23
29
|
long_desc <<-DESC, wrap: false
|
|
24
|
-
Create a new workroom
|
|
25
|
-
|
|
30
|
+
Create a new workroom at the same level as your main project directory, using JJ workspaces
|
|
31
|
+
if available, otherwise falling back to git worktrees. A random friendly name is
|
|
32
|
+
auto-generated.
|
|
26
33
|
DESC
|
|
27
|
-
def create
|
|
28
|
-
@name = name
|
|
34
|
+
def create
|
|
29
35
|
check_not_in_workroom!
|
|
30
|
-
|
|
36
|
+
@name = generate_unique_name
|
|
31
37
|
|
|
32
38
|
if !options[:pretend]
|
|
33
39
|
if workroom_exists?
|
|
@@ -36,24 +42,75 @@ module Workroom
|
|
|
36
42
|
end
|
|
37
43
|
|
|
38
44
|
if workroom_path.exist?
|
|
39
|
-
raise_error DirExistsError,
|
|
45
|
+
raise_error DirExistsError,
|
|
46
|
+
"Workroom directory '#{display_path(workroom_path)}' already exists!"
|
|
40
47
|
end
|
|
41
48
|
end
|
|
42
49
|
|
|
43
50
|
create_workroom
|
|
51
|
+
update_config(:add)
|
|
44
52
|
run_setup_script
|
|
45
53
|
|
|
46
54
|
say
|
|
47
|
-
say "Workroom '#{name}' created successfully at #{workroom_path}.", :green
|
|
55
|
+
say "Workroom '#{name}' created successfully at #{display_path(workroom_path)}.", :green
|
|
56
|
+
|
|
57
|
+
if @setup_result
|
|
58
|
+
say 'Setup script output:', :blue
|
|
59
|
+
say @setup_result
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
say
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
desc 'list|l|ls', 'List all workrooms for the current project'
|
|
66
|
+
def list
|
|
67
|
+
data = config.read
|
|
68
|
+
project_path, project = find_project(data)
|
|
69
|
+
|
|
70
|
+
# Inside a workroom
|
|
71
|
+
if project && Pathname.pwd.to_s != project_path
|
|
72
|
+
say 'You are already in a workroom.', :yellow
|
|
73
|
+
say "Parent project is at #{display_path(project_path)}"
|
|
74
|
+
return
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
# Inside a parent project
|
|
78
|
+
if project
|
|
79
|
+
workrooms = project['workrooms']
|
|
80
|
+
if !workrooms || workrooms.empty?
|
|
81
|
+
say 'No workrooms found for this project.'
|
|
82
|
+
return
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
list_workrooms(workrooms, project['vcs'])
|
|
86
|
+
return
|
|
87
|
+
end
|
|
48
88
|
|
|
49
|
-
|
|
89
|
+
# Neither — list all workrooms grouped by parent
|
|
90
|
+
projects_with_workrooms = data.select { |_, p| p['workrooms']&.any? }
|
|
91
|
+
if projects_with_workrooms.empty?
|
|
92
|
+
say 'No workrooms found.'
|
|
93
|
+
return
|
|
94
|
+
end
|
|
50
95
|
|
|
51
|
-
|
|
52
|
-
|
|
96
|
+
projects_with_workrooms.each do |path, proj|
|
|
97
|
+
say "#{display_path(path)}:"
|
|
98
|
+
inside path do
|
|
99
|
+
list_workrooms(proj['workrooms'], proj['vcs'])
|
|
100
|
+
end
|
|
101
|
+
say
|
|
102
|
+
end
|
|
53
103
|
end
|
|
54
104
|
|
|
55
|
-
desc 'delete NAME', 'Delete an existing workroom'
|
|
56
|
-
|
|
105
|
+
desc 'delete|d [NAME]', 'Delete an existing workroom'
|
|
106
|
+
method_option :confirm, type: :string,
|
|
107
|
+
desc: 'Skip confirmation if value matches the workroom name'
|
|
108
|
+
def delete(name = nil)
|
|
109
|
+
if !name
|
|
110
|
+
interactive_delete
|
|
111
|
+
return
|
|
112
|
+
end
|
|
113
|
+
|
|
57
114
|
@name = name
|
|
58
115
|
check_not_in_workroom!
|
|
59
116
|
validate_name!
|
|
@@ -64,30 +121,19 @@ module Workroom
|
|
|
64
121
|
raise_error exception, "#{vcs_label} '#{name}' does not exist!"
|
|
65
122
|
end
|
|
66
123
|
|
|
67
|
-
if
|
|
124
|
+
if options[:confirm]
|
|
125
|
+
if options[:confirm] != name
|
|
126
|
+
raise_error ArgumentError,
|
|
127
|
+
"--confirm value '#{options[:confirm]}' does not match " \
|
|
128
|
+
"workroom name '#{name}'."
|
|
129
|
+
end
|
|
130
|
+
elsif !yes?("Are you sure you want to delete workroom '#{name}'?")
|
|
68
131
|
say_error "Aborting. Workroom '#{name}' was not deleted.", :yellow
|
|
69
132
|
return
|
|
70
133
|
end
|
|
71
134
|
end
|
|
72
135
|
|
|
73
|
-
|
|
74
|
-
cleanup_directory if jj?
|
|
75
|
-
run_teardown_script
|
|
76
|
-
|
|
77
|
-
say
|
|
78
|
-
say "Workroom '#{name}' deleted successfully.", :green
|
|
79
|
-
|
|
80
|
-
if !jj?
|
|
81
|
-
say
|
|
82
|
-
say "Note: Git branch '#{name}' was not deleted."
|
|
83
|
-
say " Delete manually with `git branch -D #{name}` if needed."
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
return if !@teardown_result
|
|
87
|
-
|
|
88
|
-
say
|
|
89
|
-
say 'Teardown script output:', :blue
|
|
90
|
-
say @teardown_result
|
|
136
|
+
delete_by_name(name)
|
|
91
137
|
end
|
|
92
138
|
|
|
93
139
|
private
|
|
@@ -147,8 +193,20 @@ module Workroom
|
|
|
147
193
|
raise exception_class, message
|
|
148
194
|
end
|
|
149
195
|
|
|
196
|
+
def config
|
|
197
|
+
@config ||= Config.new
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def workrooms_dir
|
|
201
|
+
@workrooms_dir ||= config.workrooms_dir
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def vcs_name
|
|
205
|
+
"workroom/#{name}"
|
|
206
|
+
end
|
|
207
|
+
|
|
150
208
|
def workroom_path
|
|
151
|
-
@workroom_path ||=
|
|
209
|
+
@workroom_path ||= workrooms_dir.join(name)
|
|
152
210
|
end
|
|
153
211
|
|
|
154
212
|
def jj?
|
|
@@ -163,9 +221,9 @@ module Workroom
|
|
|
163
221
|
say_status :repo, 'Detected Git'
|
|
164
222
|
:git
|
|
165
223
|
else
|
|
166
|
-
say_status :repo, 'No supported VCS detected', :red
|
|
224
|
+
say_status :repo, 'No supported VCS detected in this directory.', :red
|
|
167
225
|
raise_error UnsupportedVCSError, <<~_
|
|
168
|
-
No supported VCS detected. Workroom requires either
|
|
226
|
+
No supported VCS detected in this directory. Workroom requires either Git or Jujutsu to manage workspaces.
|
|
169
227
|
_
|
|
170
228
|
end
|
|
171
229
|
end
|
|
@@ -179,7 +237,7 @@ module Workroom
|
|
|
179
237
|
end
|
|
180
238
|
|
|
181
239
|
def jj_workspace_exists?
|
|
182
|
-
jj_workspaces.include?(
|
|
240
|
+
jj_workspaces.include?(vcs_name)
|
|
183
241
|
end
|
|
184
242
|
|
|
185
243
|
def git_worktree_exists?
|
|
@@ -230,22 +288,109 @@ module Workroom
|
|
|
230
288
|
def check_not_in_workroom!
|
|
231
289
|
return if !Pathname.pwd.join('.Workroom').exist?
|
|
232
290
|
|
|
233
|
-
say_status :create, name, :red
|
|
234
291
|
raise_error InWorkroomError, <<~_
|
|
235
292
|
Looks like you are already in a workroom. Run this command from the root of your main development directory, not from within an existing workroom.
|
|
236
293
|
_
|
|
237
294
|
end
|
|
238
295
|
|
|
296
|
+
def interactive_delete
|
|
297
|
+
check_not_in_workroom!
|
|
298
|
+
|
|
299
|
+
data = config.read
|
|
300
|
+
_, project = find_project(data)
|
|
301
|
+
|
|
302
|
+
if !project || !project['workrooms'] || project['workrooms'].empty?
|
|
303
|
+
say 'No workrooms found for this project.'
|
|
304
|
+
return
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
workrooms = project['workrooms']
|
|
308
|
+
prompt = TTY::Prompt.new
|
|
309
|
+
selected = prompt.multi_select(
|
|
310
|
+
'Select workrooms to delete:',
|
|
311
|
+
workrooms.keys
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
if selected.empty?
|
|
315
|
+
say_error 'Aborting. No workrooms were selected.', :yellow
|
|
316
|
+
return
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
names_list = selected.map { |n| "'#{n}'" }.join(', ')
|
|
320
|
+
if !yes?("Are you sure you want to delete #{selected.size} workroom(s): #{names_list}?")
|
|
321
|
+
say_error 'Aborting. No workrooms were deleted.', :yellow
|
|
322
|
+
return
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
selected.each { |n| delete_by_name(n) }
|
|
326
|
+
end
|
|
327
|
+
|
|
328
|
+
def delete_by_name(selected_name)
|
|
329
|
+
@name = selected_name
|
|
330
|
+
@workroom_path = nil
|
|
331
|
+
|
|
332
|
+
delete_workroom
|
|
333
|
+
cleanup_directory if jj?
|
|
334
|
+
update_config(:remove)
|
|
335
|
+
run_teardown_script
|
|
336
|
+
|
|
337
|
+
say "Workroom '#{name}' deleted successfully.", :green
|
|
338
|
+
|
|
339
|
+
if !jj?
|
|
340
|
+
say
|
|
341
|
+
say "Note: Git branch '#{vcs_name}' was not deleted."
|
|
342
|
+
say " Delete manually with `git branch -D #{vcs_name}` if needed."
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
return if !@teardown_result
|
|
346
|
+
|
|
347
|
+
say
|
|
348
|
+
say 'Teardown script output:', :blue
|
|
349
|
+
say @teardown_result
|
|
350
|
+
say
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def generate_unique_name
|
|
354
|
+
generator = NameGenerator.new
|
|
355
|
+
last_name = nil
|
|
356
|
+
|
|
357
|
+
5.times do
|
|
358
|
+
last_name = generator.generate
|
|
359
|
+
if !workroom_exists_for?(last_name) && !workroom_path_for(last_name).exist?
|
|
360
|
+
return last_name
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
loop do
|
|
365
|
+
candidate = "#{last_name}-#{rand(10..99)}"
|
|
366
|
+
if !workroom_exists_for?(candidate) && !workroom_path_for(candidate).exist?
|
|
367
|
+
return candidate
|
|
368
|
+
end
|
|
369
|
+
end
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def workroom_exists_for?(candidate)
|
|
373
|
+
@name = candidate
|
|
374
|
+
@workroom_path = nil
|
|
375
|
+
workroom_exists?
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def workroom_path_for(candidate)
|
|
379
|
+
workrooms_dir.join(candidate)
|
|
380
|
+
end
|
|
381
|
+
|
|
239
382
|
def create_workroom
|
|
383
|
+
FileUtils.mkdir_p(workrooms_dir) if !workrooms_dir.exist?
|
|
384
|
+
|
|
240
385
|
if testing?
|
|
241
386
|
FileUtils.copy('./', workroom_path)
|
|
242
387
|
return
|
|
243
388
|
end
|
|
244
389
|
|
|
245
390
|
if jj?
|
|
246
|
-
run "jj workspace add #{workroom_path}"
|
|
391
|
+
run "jj workspace add #{workroom_path} --name #{vcs_name}"
|
|
247
392
|
else
|
|
248
|
-
run "git worktree add -b #{
|
|
393
|
+
run "git worktree add -b #{vcs_name} #{workroom_path}"
|
|
249
394
|
end
|
|
250
395
|
end
|
|
251
396
|
|
|
@@ -256,7 +401,7 @@ module Workroom
|
|
|
256
401
|
end
|
|
257
402
|
|
|
258
403
|
if jj?
|
|
259
|
-
run "jj workspace forget #{
|
|
404
|
+
run "jj workspace forget #{vcs_name}"
|
|
260
405
|
else
|
|
261
406
|
run "git worktree remove #{workroom_path} --force"
|
|
262
407
|
end
|
|
@@ -268,6 +413,16 @@ module Workroom
|
|
|
268
413
|
remove_dir(workroom_path, verbose:)
|
|
269
414
|
end
|
|
270
415
|
|
|
416
|
+
def update_config(action)
|
|
417
|
+
return if options[:pretend]
|
|
418
|
+
|
|
419
|
+
if action == :add
|
|
420
|
+
config.add_workroom Pathname.pwd.to_s, name, workroom_path.to_s, vcs
|
|
421
|
+
else
|
|
422
|
+
config.remove_workroom Pathname.pwd.to_s, name
|
|
423
|
+
end
|
|
424
|
+
end
|
|
425
|
+
|
|
271
426
|
def run(command, config = {})
|
|
272
427
|
if !config[:force] && testing?
|
|
273
428
|
raise TestError, "Command execution blocked during testing: `#{command}`"
|
|
@@ -290,5 +445,47 @@ module Workroom
|
|
|
290
445
|
def testing?
|
|
291
446
|
ENV['WORKROOM_TEST'] == '1'
|
|
292
447
|
end
|
|
448
|
+
|
|
449
|
+
def display_path(path)
|
|
450
|
+
path.to_s.sub(/\A#{Regexp.escape(Dir.home)}/, '~')
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
def list_workrooms(workrooms, vcs)
|
|
454
|
+
rows = workrooms.map do |name, info|
|
|
455
|
+
warnings = workroom_warnings(name, info, vcs)
|
|
456
|
+
row = [shell.set_color(name, :bold), shell.set_color(display_path(info['path']), :black)]
|
|
457
|
+
row << shell.set_color("[#{warnings.join(', ')}]", :yellow) if warnings.any?
|
|
458
|
+
row
|
|
459
|
+
end
|
|
460
|
+
print_table rows, indent: 2
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
# Find the project for the current directory. If pwd is a project in the config, return it
|
|
464
|
+
# directly. Otherwise, check if pwd is a workroom path under any project.
|
|
465
|
+
def find_project(data)
|
|
466
|
+
pwd = Pathname.pwd.to_s
|
|
467
|
+
return [pwd, data[pwd]] if data.key?(pwd)
|
|
468
|
+
|
|
469
|
+
data.each do |project_path, project|
|
|
470
|
+
workrooms = project['workrooms'] || {}
|
|
471
|
+
return [project_path, project] if workrooms.any? { |_, info| info['path'] == pwd }
|
|
472
|
+
end
|
|
473
|
+
|
|
474
|
+
[pwd, nil]
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
def workroom_warnings(name, info, stored_vcs)
|
|
478
|
+
warnings = []
|
|
479
|
+
warnings << 'directory not found' if !Dir.exist?(info['path'])
|
|
480
|
+
if !testing?
|
|
481
|
+
vcs_missing = if stored_vcs == 'jj'
|
|
482
|
+
!jj_workspaces.include?("workroom/#{name}")
|
|
483
|
+
elsif stored_vcs == 'git'
|
|
484
|
+
git_worktrees.none? { |path| File.basename(path) == name }
|
|
485
|
+
end
|
|
486
|
+
warnings << "#{stored_vcs} workspace not found" if vcs_missing
|
|
487
|
+
end
|
|
488
|
+
warnings
|
|
489
|
+
end
|
|
293
490
|
end
|
|
294
491
|
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
module Workroom
|
|
6
|
+
class Config
|
|
7
|
+
CONFIG_DIR = File.expand_path('~/.config/workroom')
|
|
8
|
+
DEFAULT_WORKROOMS_DIR = '~/workrooms'
|
|
9
|
+
|
|
10
|
+
def config_path
|
|
11
|
+
@config_path ||= File.join(CONFIG_DIR, 'config.json')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def read
|
|
15
|
+
return {} if !File.exist?(config_path)
|
|
16
|
+
|
|
17
|
+
JSON.parse(File.read(config_path))
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def write(data)
|
|
21
|
+
dir = File.dirname(config_path)
|
|
22
|
+
FileUtils.mkdir_p(dir)
|
|
23
|
+
File.write(config_path, JSON.pretty_generate(data))
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def add_workroom(parent_path, name, workroom_path, vcs)
|
|
27
|
+
update do |data|
|
|
28
|
+
data[parent_path] ||= { 'vcs' => vcs.to_s, 'workrooms' => {} }
|
|
29
|
+
data[parent_path]['vcs'] = vcs.to_s
|
|
30
|
+
data[parent_path]['workrooms'][name] = { 'path' => workroom_path }
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def remove_workroom(parent_path, name)
|
|
35
|
+
update do |data|
|
|
36
|
+
return if !data[parent_path]
|
|
37
|
+
|
|
38
|
+
data[parent_path]['workrooms'].delete(name)
|
|
39
|
+
data.delete(parent_path) if data[parent_path]['workrooms'].empty?
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def workrooms_dir
|
|
44
|
+
Pathname.new(File.expand_path(read['workrooms_dir'] || DEFAULT_WORKROOMS_DIR))
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def workrooms_dir=(path)
|
|
48
|
+
update { |data| data['workrooms_dir'] = path }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def update
|
|
54
|
+
data = read
|
|
55
|
+
yield data
|
|
56
|
+
write data
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Workroom
|
|
4
|
+
class NameGenerator
|
|
5
|
+
ADJECTIVES = %w[
|
|
6
|
+
agile amber apt azure bold brave bright brisk calm cedar clear cold cool
|
|
7
|
+
coral crisp cyan damp dark dawn deep deft dry dusk dusty easy even fair
|
|
8
|
+
fast firm flat fond free fresh full glad gold good gray green hale happy
|
|
9
|
+
hazy high idle jade keen kind lark last lean left light lime long lost
|
|
10
|
+
loud lush mild mint misty mossy neat nice noble north novel oak odd opal
|
|
11
|
+
open pale peak pine pink plum proud pure quick quiet rapid rare red rich
|
|
12
|
+
ripe rosy ruby safe sage salt sharp shy silk slim slow smart snowy soft
|
|
13
|
+
solid south stark steel still stout sunny sure swift tall tame teal thin
|
|
14
|
+
tidy trim true vivid warm west wide wild wise young
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
NOUNS = %w[
|
|
18
|
+
acre arch aspen badge bank bark basin bay beach bear birch blade blaze
|
|
19
|
+
bloom bolt bone bow brace brass breeze brick bridge brook brush canopy
|
|
20
|
+
cape cave cedar chain chime cliff cloud clover colt coop coral core
|
|
21
|
+
cove crane creek crest crow curve dale dawn deer delta dew dock dove
|
|
22
|
+
drake drift dune dusk eagle edge elm ember fawn feather fern field finch
|
|
23
|
+
fjord flame flask flint float flora flute fog font forge fox frost gate
|
|
24
|
+
glade glen globe gorge grain grove gulf gust hare haven hawk hazel
|
|
25
|
+
heath hedge heron hill hollow horn inlet isle ivy jade jewel knoll
|
|
26
|
+
lake larch lark latch laurel leaf ledge light lilac lily linen lodge
|
|
27
|
+
loft lynx maple marsh meadow mesa mint mirror mist moon moss mound
|
|
28
|
+
nest north oak opal orbit orion otter palm pass path peak pearl
|
|
29
|
+
pebble perch petal pine pixel plume pond pool porch prism quail
|
|
30
|
+
quarry quartz rail rain raven reef ridge river robin rock root rose
|
|
31
|
+
ruby sage sand scope seal seed shade shell shore silk sky slate
|
|
32
|
+
slope smoke snow south spark spire spoke spring spruce star stem
|
|
33
|
+
stone stork storm strand surf swift tern thyme tide timber tower
|
|
34
|
+
trail tree vale vault vine vista wand ward wave west wheat willow
|
|
35
|
+
wind wing wolf wren yard
|
|
36
|
+
].freeze
|
|
37
|
+
|
|
38
|
+
def generate
|
|
39
|
+
"#{ADJECTIVES.sample}-#{NOUNS.sample}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/workroom/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: workroom
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joel Moss
|
|
@@ -23,6 +23,20 @@ dependencies:
|
|
|
23
23
|
- - "~>"
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
25
|
version: '1.5'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: tty-prompt
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '0.23'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '0.23'
|
|
26
40
|
- !ruby/object:Gem::Dependency
|
|
27
41
|
name: zeitwerk
|
|
28
42
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -51,7 +65,9 @@ files:
|
|
|
51
65
|
- bin/workroom
|
|
52
66
|
- lib/workroom.rb
|
|
53
67
|
- lib/workroom/commands.rb
|
|
68
|
+
- lib/workroom/config.rb
|
|
54
69
|
- lib/workroom/engine.rb
|
|
70
|
+
- lib/workroom/name_generator.rb
|
|
55
71
|
- lib/workroom/version.rb
|
|
56
72
|
homepage: https://github.com/joelmoss/workroom
|
|
57
73
|
licenses:
|