devinator 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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 046f88a18615ff14000b6152870bc84c8e8f7eedfd827a9c8a24d1c001f5fb9a
4
+ data.tar.gz: d22ff6f57a13d3c6166cc61665f26bd40f3da09c4af11e1aa8bb37ce043c262b
5
+ SHA512:
6
+ metadata.gz: 8df565e8abfe627a0092227af9d393242c5e906bc85279ea5ff09147e5a64a3e98c81d5d7b7b17776058df9b486fbdd8a08bf9e7e7ea6d19f6696fc98538e55d
7
+ data.tar.gz: 14f6a8f20a1109135bf49acea9f5139a51524efc3828e9124445af3067bc78fbdeb216a94cc93a25ef9d71cd09af3ee70c6b80a3ee639275f686079489746a2f
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ bin/test
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.gem
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --require spec_helper
2
+ --format documentation
data/Gemfile ADDED
@@ -0,0 +1,11 @@
1
+ source "https://rubygems.org" do
2
+ gem "tty-command"
3
+
4
+ group :development do
5
+ gem "standardrb"
6
+ end
7
+
8
+ group :test do
9
+ gem "rspec"
10
+ end
11
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,85 @@
1
+ GEM
2
+ specs:
3
+
4
+ GEM
5
+ remote: https://rubygems.org/
6
+ specs:
7
+ ast (2.4.3)
8
+ diff-lcs (1.6.2)
9
+ json (2.15.1)
10
+ language_server-protocol (3.17.0.5)
11
+ lint_roller (1.1.0)
12
+ parallel (1.27.0)
13
+ parser (3.3.9.0)
14
+ ast (~> 2.4.1)
15
+ racc
16
+ pastel (0.8.0)
17
+ tty-color (~> 0.5)
18
+ prism (1.6.0)
19
+ racc (1.8.1)
20
+ rainbow (3.1.1)
21
+ regexp_parser (2.11.3)
22
+ rspec (3.13.2)
23
+ rspec-core (~> 3.13.0)
24
+ rspec-expectations (~> 3.13.0)
25
+ rspec-mocks (~> 3.13.0)
26
+ rspec-core (3.13.6)
27
+ rspec-support (~> 3.13.0)
28
+ rspec-expectations (3.13.5)
29
+ diff-lcs (>= 1.2.0, < 2.0)
30
+ rspec-support (~> 3.13.0)
31
+ rspec-mocks (3.13.6)
32
+ diff-lcs (>= 1.2.0, < 2.0)
33
+ rspec-support (~> 3.13.0)
34
+ rspec-support (3.13.6)
35
+ rubocop (1.80.2)
36
+ json (~> 2.3)
37
+ language_server-protocol (~> 3.17.0.2)
38
+ lint_roller (~> 1.1.0)
39
+ parallel (~> 1.10)
40
+ parser (>= 3.3.0.2)
41
+ rainbow (>= 2.2.2, < 4.0)
42
+ regexp_parser (>= 2.9.3, < 3.0)
43
+ rubocop-ast (>= 1.46.0, < 2.0)
44
+ ruby-progressbar (~> 1.7)
45
+ unicode-display_width (>= 2.4.0, < 4.0)
46
+ rubocop-ast (1.47.1)
47
+ parser (>= 3.3.7.2)
48
+ prism (~> 1.4)
49
+ rubocop-performance (1.25.0)
50
+ lint_roller (~> 1.1)
51
+ rubocop (>= 1.75.0, < 2.0)
52
+ rubocop-ast (>= 1.38.0, < 2.0)
53
+ ruby-progressbar (1.13.0)
54
+ standard (1.51.1)
55
+ language_server-protocol (~> 3.17.0.2)
56
+ lint_roller (~> 1.0)
57
+ rubocop (~> 1.80.2)
58
+ standard-custom (~> 1.0.0)
59
+ standard-performance (~> 1.8)
60
+ standard-custom (1.0.2)
61
+ lint_roller (~> 1.0)
62
+ rubocop (~> 1.50)
63
+ standard-performance (1.8.0)
64
+ lint_roller (~> 1.1)
65
+ rubocop-performance (~> 1.25.0)
66
+ standardrb (1.0.1)
67
+ standard
68
+ tty-color (0.6.0)
69
+ tty-command (0.10.1)
70
+ pastel (~> 0.8)
71
+ unicode-display_width (3.2.0)
72
+ unicode-emoji (~> 4.1)
73
+ unicode-emoji (4.1.0)
74
+
75
+ PLATFORMS
76
+ ruby
77
+ x86_64-linux
78
+
79
+ DEPENDENCIES
80
+ rspec!
81
+ standardrb!
82
+ tty-command!
83
+
84
+ BUNDLED WITH
85
+ 2.7.2
data/Makefile ADDED
@@ -0,0 +1,9 @@
1
+ .PHONY: setup_hooks pretty build
2
+ build:
3
+ gem build
4
+
5
+ setup_hooks:
6
+ git config core.hooksPath ./.git-hooks
7
+
8
+ pretty:
9
+ bin/formatting-fix
data/README.md ADDED
@@ -0,0 +1,16 @@
1
+ # Devinator
2
+
3
+ A simple tool to help start your development environment. It's fairly
4
+ opinionated but can be twisted to your will.
5
+
6
+ ## How it works
7
+
8
+ Simply `cd` to your project and run `devinator`. It will do several things for
9
+ you in this order:
10
+
11
+ 1. `dx/build`
12
+ 2. `dx/start`
13
+ 3. `bin/setup` or `bin/setup`
14
+ 4. start your multiplexer
15
+ 5. launch your editor
16
+ 6. run the commands in `Procfile.dev` or `bin/dev`
data/bin/devinator ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH << File.expand_path("./lib")
3
+
4
+ require "devinator"
5
+
6
+ Devinator.run
data/bin/pretty ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ echo "=== Bundle ==="
5
+ bundle check || bundle install
6
+
7
+ echo "=== StandardRB ==="
8
+ bundle exec standardrb --fix-unsafely
data/bin/test ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ echo "=== Bundle ==="
5
+ bundle check || bundle install
6
+
7
+ echo "=== StandardRB ==="
8
+ bundle exec standardrb
9
+
10
+ echo "=== RSpec ==="
11
+ bundle exec rspec
data/devinator.gemspec ADDED
@@ -0,0 +1,21 @@
1
+ require_relative "lib/devinator/version"
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "devinator"
5
+ gem.version = Devinator::VERSION
6
+ gem.summary = "Start your development environment with one command!"
7
+ gem.description = <<-DESC
8
+ A little tool to help you get your development
9
+ environment up and running with a single command.
10
+ DESC
11
+ gem.authors = ["Sean Earle"]
12
+ gem.email = ["sean.r.earle@gmail.com"]
13
+ gem.homepage = "https://github.com/HellRok/devinator"
14
+ gem.license = "MIT"
15
+ gem.required_ruby_version = ">= 2.6.0"
16
+
17
+ gem.files = `git ls-files`.split($\)
18
+ gem.executables = [
19
+ "devinator"
20
+ ]
21
+ end
@@ -0,0 +1,64 @@
1
+ class Devinator
2
+ module Backends
3
+ class Tmux
4
+ BINARY = "tmux"
5
+
6
+ def initialize(name:, commands:, executer:)
7
+ @name = name
8
+ @commands = commands
9
+ @executer = executer
10
+ end
11
+
12
+ def launch
13
+ if session?
14
+ reconnect
15
+ else
16
+ run_commands
17
+ connect
18
+ end
19
+ end
20
+
21
+ def session?
22
+ @executer.run!(BINARY, "has-session", "-t", @name).success?
23
+ end
24
+
25
+ def reconnect
26
+ Process.exec(BINARY, "attach-session", "-t", @name)
27
+ end
28
+
29
+ def connect
30
+ @executer.run(
31
+ BINARY, "select-window", "-t", "#{@name}:0",
32
+ only_output_on_error: true
33
+ )
34
+ Process.exec(BINARY, "attach-session", "-t", @name)
35
+ end
36
+
37
+ def run_commands
38
+ @executer.run(
39
+ BINARY, "new-session", "-d", "-s", @name,
40
+ only_output_on_error: true
41
+ )
42
+
43
+ @commands.each_with_index do |command, index|
44
+ if index.zero?
45
+ @executer.run(
46
+ BINARY, "rename-window", "-t", @name, command[:title],
47
+ only_output_on_error: true
48
+ )
49
+ else
50
+ @executer.run(
51
+ BINARY, "new-window", "-t", @name, "-n", command[:title],
52
+ only_output_on_error: true
53
+ )
54
+ end
55
+
56
+ @executer.run(
57
+ BINARY, "send-keys", "-t", @name, command[:command], "C-m",
58
+ only_output_on_error: true
59
+ )
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,68 @@
1
+ require "devinator/editor_configuration"
2
+ require "devinator/user_configuration"
3
+
4
+ class Devinator
5
+ class Config
6
+ @setup_commands = []
7
+ @commands = []
8
+
9
+ def self.user_configuration
10
+ @user_configuration ||= Devinator::UserConfiguration.new
11
+ end
12
+
13
+ def self.configure
14
+ yield user_configuration
15
+ end
16
+
17
+ def self.setup_commands
18
+ @setup_commands = []
19
+
20
+ @setup_commands += user_configuration.setup_commands
21
+
22
+ @setup_commands << "dx/build" if File.exist? "dx/build"
23
+ @setup_commands << "dx/start" if File.exist? "dx/start"
24
+
25
+ @setup_commands << dx_exec("bin/setup") if File.exist? "bin/setup"
26
+
27
+ @setup_commands << user_configuration.editor.command if user_configuration.editor.timing == :end_of_setup
28
+
29
+ @setup_commands
30
+ end
31
+
32
+ def self.run_commands
33
+ @commands = []
34
+
35
+ if user_configuration.editor.timing == :first_command
36
+ @commands << {
37
+ title: user_configuration.editor.title,
38
+ command: user_configuration.editor.command
39
+ }
40
+ end
41
+
42
+ if File.exist? "Procfile.dev"
43
+ File.read("Procfile.dev").lines.each { |line|
44
+ name, command = line.split(":", 2)
45
+ @commands << {title: name, command: dx_exec(command.strip)}
46
+ }
47
+
48
+ elsif File.exist? "bin/dev"
49
+ @commands << {title: "dev", command: dx_exec("bin/dev")}
50
+ end
51
+
52
+ if user_configuration.editor.timing == :last_command
53
+ @commands << {
54
+ title: user_configuration.editor.title,
55
+ command: user_configuration.editor.command
56
+ }
57
+ end
58
+
59
+ @commands
60
+ end
61
+
62
+ private_class_method def self.dx_exec(command)
63
+ result = ""
64
+ result << "dx/exec " if File.exist? "dx/exec"
65
+ result << command
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,18 @@
1
+ class Devinator
2
+ class EditorConfiguration
3
+ VALID_TIMINGS = [:end_of_setup, :first_command, :last_command]
4
+ attr_accessor :command, :title
5
+ attr_reader :timing
6
+
7
+ def timing=(val)
8
+ unless VALID_TIMINGS.include? val
9
+ raise(
10
+ ArgumentError,
11
+ "must be one of #{VALID_TIMINGS.inspect}"
12
+ )
13
+ end
14
+
15
+ @timing = val
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,21 @@
1
+ class Devinator
2
+ class UserConfiguration
3
+ attr_writer :setup_commands
4
+
5
+ def initialize
6
+ @setup_commands = []
7
+ end
8
+
9
+ def editor
10
+ @editor_configuration ||= Devinator::EditorConfiguration.new
11
+ end
12
+
13
+ def setup_commands
14
+ if @setup_commands.is_a?(Enumerable)
15
+ @setup_commands
16
+ else
17
+ [@setup_commands].compact
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ class Devinator
2
+ VERSION = "0.0.1"
3
+ end
data/lib/devinator.rb ADDED
@@ -0,0 +1,23 @@
1
+ require "tty-command"
2
+
3
+ require "devinator/config"
4
+ require "devinator/backends/tmux"
5
+
6
+ class Devinator
7
+ def self.run
8
+ tty = TTY::Command.new(uuid: false)
9
+
10
+ user_config_path = File.expand_path("~/.config/devinator.rb")
11
+ Kernel.require(user_config_path) if File.exist?(user_config_path)
12
+
13
+ Devinator::Config.setup_commands.each { tty.run it, only_output_on_error: true }
14
+
15
+ tmux = Devinator::Backends::Tmux.new(
16
+ name: File.basename(Dir.pwd),
17
+ commands: Devinator::Config.run_commands,
18
+ executer: tty
19
+ )
20
+
21
+ tmux.launch
22
+ end
23
+ end
@@ -0,0 +1,185 @@
1
+ describe Devinator::Backends::Tmux do
2
+ before do
3
+ @tmux = Devinator::Backends::Tmux
4
+ end
5
+
6
+ describe "#session?" do
7
+ before do
8
+ @tty = double(:tty)
9
+ end
10
+
11
+ it "returns true if there is a session" do
12
+ expect(@tty).to receive(:run!).with(
13
+ "tmux", "has-session", "-t", "the-session"
14
+ ).and_return(double(:result, success?: true))
15
+
16
+ expect(
17
+ @tmux.new(
18
+ name: "the-session",
19
+ commands: [],
20
+ executer: @tty
21
+ ).session?
22
+ ).to be(true)
23
+ end
24
+
25
+ it "returns false if there is no session" do
26
+ expect(@tty).to receive(:run!).with(
27
+ "tmux", "has-session", "-t", "the-session"
28
+ ).and_return(double(:result, success?: false))
29
+
30
+ expect(
31
+ @tmux.new(
32
+ name: "the-session",
33
+ commands: [],
34
+ executer: @tty
35
+ ).session?
36
+ ).to be(false)
37
+ end
38
+
39
+ describe "#reconnect" do
40
+ it "reconnects to the session" do
41
+ expect(Process).to receive(:exec).with(
42
+ "tmux", "attach-session", "-t", "the-session"
43
+ )
44
+
45
+ @tmux.new(
46
+ name: "the-session",
47
+ commands: [],
48
+ executer: @tty
49
+ ).reconnect
50
+ end
51
+ end
52
+
53
+ describe "#run_commands" do
54
+ it "launches a session and on the first command renames the window then a new window for each following command" do
55
+ expect(@tty).to receive(:run).with(
56
+ "tmux", "new-session", "-d", "-s", "the-session",
57
+ only_output_on_error: true
58
+ )
59
+
60
+ expect(@tty).to receive(:run).with(
61
+ "tmux", "rename-window", "-t", "the-session", "cmd1",
62
+ only_output_on_error: true
63
+ )
64
+
65
+ expect(@tty).to receive(:run).with(
66
+ "tmux", "send-keys", "-t", "the-session", "command 1", "C-m",
67
+ only_output_on_error: true
68
+ )
69
+
70
+ expect(@tty).to receive(:run).with(
71
+ "tmux", "new-window", "-t", "the-session", "-n", "cmd2",
72
+ only_output_on_error: true
73
+ )
74
+
75
+ expect(@tty).to receive(:run).with(
76
+ "tmux", "send-keys", "-t", "the-session", "command 2", "C-m",
77
+ only_output_on_error: true
78
+ )
79
+
80
+ expect(@tty).to receive(:run).with(
81
+ "tmux", "new-window", "-t", "the-session", "-n", "cmd3",
82
+ only_output_on_error: true
83
+ )
84
+
85
+ expect(@tty).to receive(:run).with(
86
+ "tmux", "send-keys", "-t", "the-session", "command 3", "C-m",
87
+ only_output_on_error: true
88
+ )
89
+
90
+ @tmux.new(
91
+ name: "the-session",
92
+ commands: [
93
+ {title: "cmd1", command: "command 1"},
94
+ {title: "cmd2", command: "command 2"},
95
+ {title: "cmd3", command: "command 3"}
96
+ ],
97
+ executer: @tty
98
+ ).run_commands
99
+ end
100
+ end
101
+
102
+ describe "#connect" do
103
+ it "connects to the tmux session" do
104
+ expect(@tty).to receive(:run).with(
105
+ "tmux", "select-window", "-t", "the-session:0",
106
+ only_output_on_error: true
107
+ )
108
+
109
+ expect(Process).to receive(:exec).with(
110
+ "tmux", "attach-session", "-t", "the-session"
111
+ )
112
+
113
+ @tmux.new(
114
+ name: "the-session",
115
+ commands: [],
116
+ executer: @tty
117
+ ).connect
118
+ end
119
+ end
120
+
121
+ describe "#launch" do
122
+ context "with a session available" do
123
+ before do
124
+ @tty = double(:tty)
125
+ end
126
+
127
+ it "reconnects to that session" do
128
+ expect(@tty).to receive(:run!).with(
129
+ "tmux", "has-session", "-t", "the-session"
130
+ ).and_return(double(:result, success?: true))
131
+
132
+ expect(Process).to receive(:exec).with(
133
+ "tmux", "attach-session", "-t", "the-session"
134
+ )
135
+
136
+ @tmux.new(
137
+ name: "the-session",
138
+ commands: [],
139
+ executer: @tty
140
+ ).launch
141
+ end
142
+ end
143
+
144
+ context "without a session" do
145
+ it "creates a new session" do
146
+ expect(@tty).to receive(:run!).with(
147
+ "tmux", "has-session", "-t", "the-session"
148
+ ).and_return(double(:result, success?: false))
149
+
150
+ expect(@tty).to receive(:run).with(
151
+ "tmux", "new-session", "-d", "-s", "the-session",
152
+ only_output_on_error: true
153
+ )
154
+
155
+ expect(@tty).to receive(:run).with(
156
+ "tmux", "rename-window", "-t", "the-session", "cmd1",
157
+ only_output_on_error: true
158
+ )
159
+
160
+ expect(@tty).to receive(:run).with(
161
+ "tmux", "send-keys", "-t", "the-session", "command 1", "C-m",
162
+ only_output_on_error: true
163
+ )
164
+
165
+ expect(@tty).to receive(:run).with(
166
+ "tmux", "select-window", "-t", "the-session:0",
167
+ only_output_on_error: true
168
+ )
169
+
170
+ expect(Process).to receive(:exec).with(
171
+ "tmux", "attach-session", "-t", "the-session"
172
+ )
173
+
174
+ @tmux.new(
175
+ name: "the-session",
176
+ commands: [
177
+ {title: "cmd1", command: "command 1"}
178
+ ],
179
+ executer: @tty
180
+ ).launch
181
+ end
182
+ end
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,207 @@
1
+ describe Devinator::Config do
2
+ describe ".configure" do
3
+ it "does nothing with an empty block" do
4
+ Devinator::Config.configure {}
5
+
6
+ expect(Devinator::Config.setup_commands).to eq([])
7
+ expect(Devinator::Config.run_commands).to eq([])
8
+ end
9
+
10
+ it "loads the setup commands" do
11
+ Devinator::Config.configure do |config|
12
+ config.setup_commands = [
13
+ "update_secrets",
14
+ "load_secrets sean"
15
+ ]
16
+ end
17
+
18
+ expect(Devinator::Config.setup_commands).to eq(
19
+ [
20
+ "update_secrets",
21
+ "load_secrets sean"
22
+ ]
23
+ )
24
+ expect(Devinator::Config.run_commands).to eq([])
25
+ end
26
+ end
27
+
28
+ describe ".setup_commands" do
29
+ it "returns nothing when no files" do
30
+ expect(Devinator::Config.setup_commands).to eq([])
31
+ end
32
+
33
+ it "returns bin/setup when available" do
34
+ File.write "bin/setup", ""
35
+
36
+ expect(Devinator::Config.setup_commands).to eq(["bin/setup"])
37
+ end
38
+
39
+ it "returns dx/exec bin/setup when both are available" do
40
+ File.write "dx/exec", ""
41
+ File.write "bin/setup", ""
42
+
43
+ expect(Devinator::Config.setup_commands).to eq(["dx/exec bin/setup"])
44
+ end
45
+
46
+ it "returns dx/start when available" do
47
+ File.write "dx/start", ""
48
+
49
+ expect(Devinator::Config.setup_commands).to eq(["dx/start"])
50
+ end
51
+
52
+ it "returns dx/build when available" do
53
+ File.write "dx/build", ""
54
+
55
+ expect(Devinator::Config.setup_commands).to eq(["dx/build"])
56
+ end
57
+
58
+ it "returns all files when available" do
59
+ File.write "bin/setup", ""
60
+ File.write "dx/start", ""
61
+ File.write "dx/build", ""
62
+
63
+ Devinator::Config.configure do |config|
64
+ config.setup_commands = [
65
+ "update_secrets",
66
+ "load_secrets sean",
67
+ "git pull"
68
+ ]
69
+ end
70
+
71
+ expect(Devinator::Config.setup_commands).to eq(
72
+ [
73
+ "update_secrets",
74
+ "load_secrets sean",
75
+ "git pull",
76
+ "dx/build",
77
+ "dx/start",
78
+ "bin/setup"
79
+ ]
80
+ )
81
+ end
82
+
83
+ context "with an editor command setup" do
84
+ describe "when the timing is :end_of_setup" do
85
+ it "returns before the other commands" do
86
+ Devinator::Config.configure do |config|
87
+ config.editor.command = "nvim"
88
+ config.editor.timing = :end_of_setup
89
+ end
90
+
91
+ File.write "bin/setup", ""
92
+
93
+ expect(Devinator::Config.setup_commands).to eq([
94
+ "bin/setup", "nvim"
95
+ ])
96
+ end
97
+ end
98
+ end
99
+ end
100
+
101
+ describe ".run_commands" do
102
+ context "with a bin/dev" do
103
+ it "returns nothing when no files" do
104
+ expect(Devinator::Config.run_commands).to eq([])
105
+ end
106
+
107
+ it "returns bin/dev when available" do
108
+ File.write "bin/dev", ""
109
+
110
+ expect(Devinator::Config.run_commands).to eq([
111
+ {title: "dev", command: "bin/dev"}
112
+ ])
113
+ end
114
+
115
+ it "returns dx/exec bin/dev when both available" do
116
+ File.write "dx/exec", ""
117
+ File.write "bin/dev", ""
118
+
119
+ expect(Devinator::Config.run_commands).to eq([
120
+ {title: "dev", command: "dx/exec bin/dev"}
121
+ ])
122
+ end
123
+ end
124
+
125
+ context "with a Procfile.dev" do
126
+ it "returns nothing when no files" do
127
+ expect(Devinator::Config.run_commands).to eq([])
128
+ end
129
+
130
+ it "uses Procfile.dev commands" do
131
+ File.write "Procfile.dev", <<~PROCFILE
132
+ web: bin/web
133
+ assets: bin/assets
134
+ PROCFILE
135
+
136
+ expect(Devinator::Config.run_commands).to eq([
137
+ {title: "web", command: "bin/web"},
138
+ {title: "assets", command: "bin/assets"}
139
+ ])
140
+ end
141
+
142
+ it "returns dx/exec for the commands when present" do
143
+ File.write "dx/exec", ""
144
+ File.write "Procfile.dev", <<~PROCFILE
145
+ web: bin/web
146
+ assets: bin/assets
147
+ PROCFILE
148
+
149
+ expect(Devinator::Config.run_commands).to eq([
150
+ {title: "web", command: "dx/exec bin/web"},
151
+ {title: "assets", command: "dx/exec bin/assets"}
152
+ ])
153
+ end
154
+
155
+ context "when bin/dev is also present" do
156
+ it "uses Procfile.dev commands and ignores bin/dev" do
157
+ File.write "bin/dev", ""
158
+ File.write "Procfile.dev", <<~PROCFILE
159
+ web: bin/web
160
+ tests: bin/tests
161
+ PROCFILE
162
+
163
+ expect(Devinator::Config.run_commands).to eq([
164
+ {title: "web", command: "bin/web"},
165
+ {title: "tests", command: "bin/tests"}
166
+ ])
167
+ end
168
+ end
169
+ end
170
+
171
+ context "with an editor command setup" do
172
+ describe "when the timing is :first_command" do
173
+ it "returns before the other commands" do
174
+ Devinator::Config.configure do |config|
175
+ config.editor.title = "editor"
176
+ config.editor.command = "nvim"
177
+ config.editor.timing = :first_command
178
+ end
179
+
180
+ File.write "bin/dev", ""
181
+
182
+ expect(Devinator::Config.run_commands).to eq([
183
+ {title: "editor", command: "nvim"},
184
+ {title: "dev", command: "bin/dev"}
185
+ ])
186
+ end
187
+ end
188
+
189
+ describe "when the timing is :last_command" do
190
+ it "returns before the other commands" do
191
+ Devinator::Config.configure do |config|
192
+ config.editor.title = "editor"
193
+ config.editor.command = "nvim"
194
+ config.editor.timing = :last_command
195
+ end
196
+
197
+ File.write "bin/dev", ""
198
+
199
+ expect(Devinator::Config.run_commands).to eq([
200
+ {title: "dev", command: "bin/dev"},
201
+ {title: "editor", command: "nvim"}
202
+ ])
203
+ end
204
+ end
205
+ end
206
+ end
207
+ end
@@ -0,0 +1,54 @@
1
+ describe Devinator do
2
+ describe ".run" do
3
+ before do
4
+ @tty = double(:tty)
5
+ allow(TTY::Command).to receive(:new).and_return(@tty)
6
+
7
+ allow(Dir).to receive(:pwd).and_return("/path/to/project")
8
+ allow(Devinator::Config).to receive(:setup_commands).and_return([])
9
+ allow(Devinator::Config).to receive(:run_commands).and_return([])
10
+
11
+ @tmux = double(:tmux)
12
+ allow(Devinator::Backends::Tmux).to receive(:new).and_return(@tmux)
13
+ allow(@tmux).to receive(:launch)
14
+ end
15
+
16
+ it "runs the setup commands before run commands" do
17
+ expect(File).to receive(:expand_path).with("~/.config/devinator.rb").and_return("user config")
18
+ expect(File).to receive(:exist?).with("user config").and_return(false)
19
+ expect(TTY::Command).to receive(:new).with(uuid: false)
20
+
21
+ expect(Dir).to receive(:pwd).and_return("/path/to/project")
22
+ expect(Devinator::Config).to receive(:setup_commands).and_return(["bin/setup"])
23
+
24
+ expect(@tty).to receive(:run).with(
25
+ "bin/setup",
26
+ only_output_on_error: true
27
+ )
28
+
29
+ allow(Devinator::Config).to receive(:run_commands).and_return(
30
+ [{title: "dev", command: "bin/dev"}]
31
+ )
32
+ expect(Devinator::Backends::Tmux).to receive(:new).with(
33
+ name: "project",
34
+ commands: [
35
+ title: "dev", command: "bin/dev"
36
+ ],
37
+ executer: @tty
38
+ ).and_return(@tmux).ordered
39
+
40
+ expect(@tmux).to receive(:launch)
41
+
42
+ Devinator.run
43
+ end
44
+
45
+ it "loads the user config" do
46
+ expect(File).to receive(:expand_path).with("~/.config/devinator.rb").and_return("user config")
47
+ expect(File).to receive(:exist?).with("user config").and_return(true)
48
+
49
+ expect(Kernel).to receive(:require).with("user config")
50
+
51
+ Devinator.run
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,24 @@
1
+ describe Devinator::UserConfiguration do
2
+ describe "#timing=" do
3
+ it "lets you set :end_of_setup, :first_command, and :last_command" do
4
+ config = Devinator::EditorConfiguration.new
5
+
6
+ expect do
7
+ config.timing = :end_of_setup
8
+ config.timing = :first_command
9
+ config.timing = :last_command
10
+ end.not_to raise_error
11
+ end
12
+
13
+ it "raises an error if passed a different value" do
14
+ config = Devinator::EditorConfiguration.new
15
+
16
+ expect do
17
+ config.timing = :nope
18
+ end.to raise_error(
19
+ ArgumentError,
20
+ "must be one of [:end_of_setup, :first_command, :last_command]"
21
+ )
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,113 @@
1
+ require "tmpdir"
2
+
3
+ require "devinator"
4
+
5
+ # This file was generated by the `rspec --init` command. Conventionally, all
6
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
7
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
8
+ # this file to always be loaded, without a need to explicitly require it in any
9
+ # files.
10
+ #
11
+ # Given that it is always loaded, you are encouraged to keep this file as
12
+ # light-weight as possible. Requiring heavyweight dependencies from this file
13
+ # will add to the boot time of your test suite on EVERY test run, even for an
14
+ # individual file that may not need all of that loaded. Instead, consider making
15
+ # a separate helper file that requires the additional dependencies and performs
16
+ # the additional setup, and require it from the spec files that actually need
17
+ # it.
18
+ #
19
+ # See https://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
20
+ RSpec.configure do |config|
21
+ # rspec-expectations config goes here. You can use an alternate
22
+ # assertion/expectation library such as wrong or the stdlib/minitest
23
+ # assertions if you prefer.
24
+ config.expect_with :rspec do |expectations|
25
+ # This option will default to `true` in RSpec 4. It makes the `description`
26
+ # and `failure_message` of custom matchers include text for helper methods
27
+ # defined using `chain`, e.g.:
28
+ # be_bigger_than(2).and_smaller_than(4).description
29
+ # # => "be bigger than 2 and smaller than 4"
30
+ # ...rather than:
31
+ # # => "be bigger than 2"
32
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
33
+ end
34
+
35
+ # rspec-mocks config goes here. You can use an alternate test double
36
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
37
+ config.mock_with :rspec do |mocks|
38
+ # Prevents you from mocking or stubbing a method that does not exist on
39
+ # a real object. This is generally recommended, and will default to
40
+ # `true` in RSpec 4.
41
+ mocks.verify_partial_doubles = true
42
+ end
43
+
44
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
45
+ # have no way to turn it off -- the option exists only for backwards
46
+ # compatibility in RSpec 3). It causes shared context metadata to be
47
+ # inherited by the metadata hash of host groups and examples, rather than
48
+ # triggering implicit auto-inclusion in groups with matching metadata.
49
+ config.shared_context_metadata_behavior = :apply_to_host_groups
50
+
51
+ # The settings below are suggested to provide a good initial experience
52
+ # with RSpec, but feel free to customize to your heart's content.
53
+ # # This allows you to limit a spec run to individual examples or groups
54
+ # # you care about by tagging them with `:focus` metadata. When nothing
55
+ # # is tagged with `:focus`, all examples get run. RSpec also provides
56
+ # # aliases for `it`, `describe`, and `context` that include `:focus`
57
+ # # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
58
+ # config.filter_run_when_matching :focus
59
+ #
60
+ # # Allows RSpec to persist some state between runs in order to support
61
+ # # the `--only-failures` and `--next-failure` CLI options. We recommend
62
+ # # you configure your source control system to ignore this file.
63
+ # config.example_status_persistence_file_path = "spec/examples.txt"
64
+ #
65
+ # # Limits the available syntax to the non-monkey patched syntax that is
66
+ # # recommended. For more details, see:
67
+ # # https://rspec.info/features/3-12/rspec-core/configuration/zero-monkey-patching-mode/
68
+ # config.disable_monkey_patching!
69
+ #
70
+ # # This setting enables warnings. It's recommended, but in some cases may
71
+ # # be too noisy due to issues in dependencies.
72
+ # config.warnings = true
73
+ #
74
+ # # Many RSpec users commonly either run the entire suite or an individual
75
+ # # file, and it's useful to allow more verbose output when running an
76
+ # # individual spec file.
77
+ # if config.files_to_run.one?
78
+ # # Use the documentation formatter for detailed output,
79
+ # # unless a formatter has already been configured
80
+ # # (e.g. via a command-line flag).
81
+ # config.default_formatter = "doc"
82
+ # end
83
+ #
84
+ # # Print the 10 slowest examples and example groups at the
85
+ # # end of the spec run, to help surface which specs are running
86
+ # # particularly slow.
87
+ # config.profile_examples = 10
88
+ #
89
+ # # Run specs in random order to surface order dependencies. If you find an
90
+ # # order dependency and want to debug it, you can fix the order by providing
91
+ # # the seed, which is printed after each run.
92
+ # # --seed 1234
93
+ # config.order = :random
94
+ #
95
+ # # Seed global randomization in this process using the `--seed` CLI option.
96
+ # # Setting this allows you to use `--seed` to deterministically reproduce
97
+ # # test failures related to randomization by passing the same `--seed` value
98
+ # # as the one that triggered the failure.
99
+ # Kernel.srand config.seed
100
+ config.order = :random
101
+ Kernel.srand config.seed
102
+
103
+ config.around do |spec|
104
+ original_dir = Dir.pwd
105
+ Dir.chdir Dir.mktmpdir "devinator-specs-"
106
+ Dir.mkdir "bin"
107
+ Dir.mkdir "dx"
108
+ spec.run
109
+ ensure
110
+ Dir.chdir original_dir
111
+ Devinator::Config.instance_variable_set(:@user_configuration, nil)
112
+ end
113
+ end
@@ -0,0 +1,31 @@
1
+ describe Devinator::UserConfiguration do
2
+ describe "#setup_commands" do
3
+ it "returns an empty array if not specifically set" do
4
+ expect(Devinator::UserConfiguration.new.setup_commands).to eq([])
5
+ end
6
+
7
+ it "returns an array if set to a single value" do
8
+ config = Devinator::UserConfiguration.new
9
+
10
+ config.setup_commands = "load_secrets"
11
+
12
+ expect(config.setup_commands).to eq(["load_secrets"])
13
+ end
14
+
15
+ it "returns normally if already an array" do
16
+ config = Devinator::UserConfiguration.new
17
+
18
+ config.setup_commands = ["update_secrets", "load_secrets", "git pull"]
19
+
20
+ expect(config.setup_commands).to eq(["update_secrets", "load_secrets", "git pull"])
21
+ end
22
+ end
23
+
24
+ describe "#editor" do
25
+ it "is a EditorConfiguration class" do
26
+ config = Devinator::UserConfiguration.new
27
+
28
+ expect(config.editor).to be_a(Devinator::EditorConfiguration)
29
+ end
30
+ end
31
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: devinator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Sean Earle
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: |2
13
+ A little tool to help you get your development
14
+ environment up and running with a single command.
15
+ email:
16
+ - sean.r.earle@gmail.com
17
+ executables:
18
+ - devinator
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - ".git-hooks/pre-commit"
23
+ - ".gitignore"
24
+ - ".rspec"
25
+ - Gemfile
26
+ - Gemfile.lock
27
+ - Makefile
28
+ - README.md
29
+ - bin/devinator
30
+ - bin/pretty
31
+ - bin/test
32
+ - devinator.gemspec
33
+ - lib/devinator.rb
34
+ - lib/devinator/backends/tmux.rb
35
+ - lib/devinator/config.rb
36
+ - lib/devinator/editor_configuration.rb
37
+ - lib/devinator/user_configuration.rb
38
+ - lib/devinator/version.rb
39
+ - spec/backends/tmux_spec.rb
40
+ - spec/config_spec.rb
41
+ - spec/devinator_spec.rb
42
+ - spec/editor_configuration_spec.rb
43
+ - spec/spec_helper.rb
44
+ - spec/user_configuration_spec.rb
45
+ homepage: https://github.com/HellRok/devinator
46
+ licenses:
47
+ - MIT
48
+ metadata: {}
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 2.6.0
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubygems_version: 3.6.7
64
+ specification_version: 4
65
+ summary: Start your development environment with one command!
66
+ test_files: []