devup 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 16b7a8648ef05f7206cc02900450f8f303fc948a0976ac959472451eeef1988f
4
- data.tar.gz: a58834288dcd48d1cde4e353f1a77fb40b15419751896bdd7680b71be64a7266
3
+ metadata.gz: f3111015b0f138014ede5086a6df15c4e3e4f1b30d1bd7a199ec16a69b7eb84e
4
+ data.tar.gz: afab2b2376b8137be5bbbc2a3f85d3464720f63312d1a7cefbc948abbf07168d
5
5
  SHA512:
6
- metadata.gz: 340f23ba29e0cd7e9c187f3ddb20d5e7c825503c5095fd4e3acd244ae2f714f89c2cfe636533207391292685244f4459b70af87a09ad82e7e8b3d9e70639aead
7
- data.tar.gz: d596434a6a8450bf01b433a2f2e4c3abbed3f465046463954595badb82468fabd0f3fc6479d0fe9935dc1bbd48b246e11aabd723251b81b2d288ff7d103b822c
6
+ metadata.gz: 58a825f460fce341d66aa22e3b6c257c920908967a1ae64a207f274ebf051144cfba56a19e526e8555c5061d4f2bc37b14ae86bafc3f03a35315352d78aa98ee
7
+ data.tar.gz: c6897be6a6378476b21e65a0a7d59402641658a400bbc20b655f234d19ab5144e5d23b2bdd764558248519c63fdfc81eee7951c17bcadd779d4c2104377df091
data/.gitignore CHANGED
@@ -15,5 +15,6 @@
15
15
  .vimrc
16
16
 
17
17
  spec/dummy/.env.services
18
+ spec/dummy_rails/.env.services
18
19
 
19
20
  devup-*.gem
@@ -0,0 +1,2 @@
1
+ ignore:
2
+ - 'spec/dummy_rails/**/*'
@@ -5,6 +5,8 @@ language: ruby
5
5
  cache: bundler
6
6
  rvm:
7
7
  - 2.7.1
8
+ - 2.6.6
9
+ - 2.5.8
8
10
  services:
9
11
  - docker
10
12
  before_install:
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- devup (0.2.0)
4
+ devup (0.3.0)
5
5
  dotenv
6
6
 
7
7
  GEM
data/README.md CHANGED
@@ -1,96 +1,105 @@
1
- # DevUp!
1
+ # DevUp! [![Travis (.com) branch](https://img.shields.io/travis/com/sergio-fry/devup/master)](https://travis-ci.com/github/sergio-fry/devup) [![Gem](https://img.shields.io/gem/v/devup)](https://rubygems.org/gems/devup) [![Code Climate coverage](https://img.shields.io/codeclimate/coverage/sergio-fry/devup)](https://codeclimate.com/github/sergio-fry/devup) [![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/sergio-fry/devup)](https://codeclimate.com/github/sergio-fry/devup) [![Gem](https://img.shields.io/gem/dt/devup)](https://rubygems.org/gems/devup)
2
2
 
3
- [![Travis (.com) branch](https://img.shields.io/travis/com/sergio-fry/devup/master)](https://travis-ci.com/github/sergio-fry/devup)
4
- [![Gem](https://img.shields.io/gem/v/devup)](https://rubygems.org/gems/devup)
5
- [![Code Climate coverage](https://img.shields.io/codeclimate/coverage/sergio-fry/devup)](https://codeclimate.com/github/sergio-fry/devup)
6
- [![Code Climate maintainability](https://img.shields.io/codeclimate/maintainability/sergio-fry/devup)](https://codeclimate.com/github/sergio-fry/devup)
7
- [![Gem](https://img.shields.io/gem/dt/devup)](https://rubygems.org/gems/devup)
3
+ Describe development dependencies with docker-compose. It is not required to remember any fancy command to start docker. Just start developing your app. Rails is a first-class citizen, but could be used without ruby.
8
4
 
9
- **DevUp!** is a tool to run dev dependencies. It builds ENV vars with dynamic exposed ports for services defined in a docker-compose.yml to access from application.
10
5
 
11
- ![demo](demo.gif)
6
+ ## Requirements
12
7
 
13
- ## Installation
8
+ * Docker (>= 19.03.8)
9
+ * Docker Compose (>= 1.25.5)
14
10
 
15
- $ gem install devup
16
11
 
17
- ## Usage
18
12
 
13
+ ## Rails
19
14
 
20
- Create a docker-compose.yml with app dependencies like:
15
+ Create a docker-compose.devup.yml with app dependencies like:
21
16
 
22
17
  ```yaml
23
- version: '3'
18
+ version: "3"
24
19
 
25
20
  services:
26
21
  postgres:
27
- image: postgres
22
+ image: postgres:10-alpine
28
23
  ports:
29
24
  - "5432"
30
25
  ```
31
26
 
32
- Add devup/dotenv to your Gemfile:
27
+ Add **DevUp!** to your Gemfile
33
28
 
34
- gem "devup"
35
-
36
- For each service from docker-compose.yml **DevUp!** will export ENV variable like
29
+ ```ruby
30
+ gem "devup", group: [:development, :test]
31
+ ```
37
32
 
38
- POSTGRES_HOST=0.0.0.0
39
- POSTGRES_PORT=5432
33
+ and
40
34
 
41
- ### Rails
35
+ bundle install
42
36
 
43
37
 
44
38
  Update your database.yml to use ENV:
45
39
 
46
40
  ```yaml
47
- default: &default
48
- adapter: postgresql
49
- encoding: unicode
50
- host: <%= ENV.fetch("POSTGRES_HOST") %>
51
- port: <%= ENV.fetch("POSTGRES_PORT") %>
52
- username: postgres
53
- password:
41
+ test:
42
+ url: <%= ENV.fetch("DATABASE_URL") %>
54
43
 
55
44
  development:
56
- <<: *default
57
- database: development
45
+ url: <%= ENV.fetch("DATABASE_URL") %>
58
46
 
59
- test:
60
- <<: *default
61
- database: test
62
47
  ```
63
48
 
64
49
 
65
- You are ready to start rails
50
+ You are ready to use rails with PostgreSQL configured
66
51
 
67
52
  $ bundle exec rake db:create db:migrate
53
+ Creating blog_postgres_1 ... done
54
+ Created database 'blog_development'
55
+
68
56
  $ bundle exec rails server
69
57
 
70
58
 
71
- ### Without Rails
59
+ ## Without Rails
60
+
61
+ ENV vars from .env.services are loaded with dotenv automatically.
72
62
 
73
63
 
74
64
  ```ruby
75
65
  require "devup"
76
66
  require "sequel"
77
67
 
78
- DB = Sequel.connect("postgres://postgres@#{ENV.fetch( "POSTGRES_HOST" )}:#{ENV.fetch("POSTGRES_PORT")}/database_name")
68
+ DB = Sequel.connect(ENV.fetch("DATABASE_URL"))
79
69
  ```
80
70
 
81
71
 
82
- ### Without Ruby (PHP, nodejs, Java, ...)
72
+ ## Without Ruby (PHP, nodejs, Java, ...)
83
73
 
84
74
  Start up services
85
75
 
86
76
  $ devup
77
+ dummy_rails_postgres_1 is up-to-date
78
+ dummy_rails_redis_1 is up-to-date
79
+ dummy_rails_memcached_1 is up-to-date
80
+
81
+ $ cat .env.services
82
+ export POSTGRES_HOST=0.0.0.0
83
+ export POSTGRES_PORT=32944
84
+ export POSTGRES_PORT_5432=32944
85
+ export MEMCACHED_HOST=0.0.0.0
86
+ export MEMCACHED_PORT=32943
87
+ ...
88
+
89
+ Use your favourite dotenv extension to load vars from .env.services ([node-dotenv](https://www.npmjs.com/package/dotenv), [python-dotenv](https://pypi.org/project/python-dotenv/), [phpdotenv](https://github.com/vlucas/phpdotenv), ...)
87
90
 
88
- Load ENV vars from generated .env.services
91
+ Or load ENV vars manually
89
92
 
90
93
  $ source .env.services
91
94
 
92
95
  Now you can run app
93
96
 
97
+ ## How To
98
+
99
+ ### Disable **DevUp!**
100
+
101
+ If you don't want devup to setup your dev services, you can disable it by using `DEVUP_ENABLED=false`. Just add it to .env.local file.
102
+
94
103
 
95
104
  ## Development
96
105
 
@@ -1,2 +1,12 @@
1
- devup = Devup::Environment.new pwd: `pwd`
2
- devup.up
1
+ if ENV.fetch("DEVUP_ENABLED", "true") == "true"
2
+ devup = Devup::Environment.new pwd: `pwd`
3
+ devup.up
4
+
5
+ begin
6
+ require "spring/commands"
7
+
8
+ Spring.watch devup.root.join("docker-compose.yml")
9
+ rescue LoadError, ArgumentError
10
+ # Spring is not available
11
+ end
12
+ end
@@ -1,12 +1,22 @@
1
1
  require "yaml"
2
+ require "open3"
2
3
 
3
4
  module Devup
4
5
  class Compose
5
- attr_reader :path, :project
6
+ attr_reader :path, :project, :logger
6
7
 
7
- def initialize(path, project: "devup")
8
+ class Error < StandardError; end
9
+
10
+ def initialize(path, project: "devup", logger:)
8
11
  @path = path
9
12
  @project = project
13
+ @logger = logger
14
+ end
15
+
16
+ def check
17
+ _output, status = safe_exec("docker-compose -v")
18
+
19
+ status
10
20
  end
11
21
 
12
22
  def services
@@ -18,7 +28,7 @@ module Devup
18
28
  end
19
29
 
20
30
  def up
21
- exec "up -d --remove-orphans"
31
+ exec "up -d --remove-orphans --renew-anon-volumes"
22
32
  end
23
33
 
24
34
  def stop
@@ -30,11 +40,23 @@ module Devup
30
40
  end
31
41
 
32
42
  def exec(cmd)
33
- `docker-compose -p #{project} -f #{path} #{cmd}`
43
+ output, status = safe_exec "docker-compose -p #{project} -f #{path} #{cmd}"
44
+
45
+ raise(Error) unless status
46
+
47
+ output
34
48
  end
35
49
 
36
50
  private
37
51
 
52
+ def safe_exec(cmd)
53
+ output, error, status = Open3.capture3(cmd + ";")
54
+
55
+ logger.error(error) unless status.success?
56
+
57
+ [output, status.success?]
58
+ end
59
+
38
60
  def config
39
61
  YAML.safe_load(config_content)
40
62
  end
@@ -1,52 +1,49 @@
1
1
  require "yaml"
2
2
 
3
+ require "devup/logger"
3
4
  require "devup/compose"
4
5
  require "devup/service"
6
+ require "devup/service_presenter"
5
7
 
6
8
  module Devup
7
9
  class Environment
8
- attr_reader :pwd, :compose
10
+ attr_reader :pwd, :compose, :logger
9
11
 
10
- def initialize(pwd:, compose: nil)
12
+ def initialize(pwd:, compose: nil, logger: Logger.default)
11
13
  @pwd = pwd.to_s.strip
12
- @compose = compose || Compose.new(root.join("docker-compose.yml"), project: project)
14
+ @compose = compose || Compose.new(root.join("docker-compose.devup.yml"), project: project, logger: logger)
15
+ @logger = logger
13
16
  end
14
17
 
15
18
  def project
16
19
  pwd.split("/")[-1].strip
17
20
  end
18
21
 
19
- def vars
20
- compose.services.map { |name| Service.new(compose, name) }.map { |service|
21
- res = []
22
-
23
- res << {"#{service.name}_HOST".upcase => "0.0.0.0"}
24
-
25
- if service.ports.size > 0
26
- res << {"#{service.name}_PORT".upcase => service.ports.first.to}
27
-
28
- service.ports.each do |port|
29
- res << {"#{service.name}_PORT_#{port.from}".upcase => port.to}
30
- end
31
- end
32
-
33
- res
34
- }.flatten
35
- end
36
-
37
22
  def env
38
- vars.reduce({}, :merge).map { |k, v| "export #{k}=#{v}" }.join("\n")
23
+ services.map { |s| service_env(s) }.join("\n\n")
39
24
  end
40
25
 
41
26
  def up
27
+ logger.info "DevUp! is starting up services..."
28
+ check
42
29
  compose.up
43
30
  write_dotenv
31
+ logger.info "DevUp! is up"
32
+ clear_dotenv
33
+
34
+ rescue StandardError
35
+ logger.info "DevUp! halted"
44
36
  end
45
37
 
46
38
  def down
39
+ logger.info "DevUp! is shutting down services..."
47
40
  compose.stop
48
41
  compose.rm
49
42
  clear_dotenv
43
+ logger.info "DevUp! is down"
44
+
45
+ rescue StandardError
46
+ logger.info "DevUp! halted"
50
47
  end
51
48
 
52
49
  def root
@@ -55,6 +52,32 @@ module Devup
55
52
 
56
53
  private
57
54
 
55
+ def check
56
+ return false if missing_config
57
+
58
+ compose.check
59
+
60
+ true
61
+ end
62
+
63
+ def missing_config
64
+ if File.exist?(compose.path)
65
+ false
66
+ else
67
+ logger.error "missing #{compose.path}"
68
+
69
+ true
70
+ end
71
+ end
72
+
73
+ def services
74
+ @services ||= compose.services.map { |name| Service.new(compose, name) }
75
+ end
76
+
77
+ def service_env(service)
78
+ ServicePresenter.new(service, project: project).call
79
+ end
80
+
58
81
  def write_dotenv
59
82
  File.open(root.join(".env.services"), "w") { |f| f.write dotenv }
60
83
  end
@@ -70,7 +93,9 @@ module Devup
70
93
  # Home: https://github.com/sergio-fry/devup #
71
94
  ####################################################
72
95
  # START
96
+
73
97
  #{env}
98
+
74
99
  # END
75
100
 
76
101
  DOTENV
@@ -0,0 +1,10 @@
1
+ require "logger"
2
+
3
+ module Devup
4
+ class Logger < ::Logger
5
+ def self.default
6
+ formatter = ->(_severity, _time, _progname, msg) { "#{msg}\n" }
7
+ new(STDOUT, formatter: formatter)
8
+ end
9
+ end
10
+ end
@@ -10,10 +10,16 @@ module Devup
10
10
  end
11
11
 
12
12
  def ports
13
+ @ports ||= fetch_ports
14
+ end
15
+
16
+ private
17
+
18
+ def fetch_ports
13
19
  compose.service_ports(name).map { |el| el.to_s.split(":")[-1] }.map do |from|
14
20
  OpenStruct.new(
15
- from: from,
16
- to: compose.exec("port #{name} #{from}").split(":")[-1].strip
21
+ from: from.to_i,
22
+ to: compose.exec("port #{name} #{from}").split(":")[-1].strip.to_i
17
23
  )
18
24
  end
19
25
  end
@@ -0,0 +1,88 @@
1
+ module Devup
2
+ class ServicePresenter
3
+ attr_reader :service, :project
4
+
5
+ def initialize(service, project: nil)
6
+ @service = service
7
+ @project = project
8
+ end
9
+
10
+ def call
11
+ res = []
12
+
13
+ res << "# #{service.name}"
14
+ res << magic if magic?
15
+
16
+ if has_ports?
17
+ res << host_env
18
+ res << ports_env
19
+ else
20
+ res << "# no exposed ports"
21
+ end
22
+
23
+ res.join "\n"
24
+ end
25
+
26
+ private
27
+
28
+ def host_env
29
+ "export #{service.name.upcase}_HOST=0.0.0.0"
30
+ end
31
+
32
+ def ports_env
33
+ res = []
34
+
35
+ res << port_env(to: service.ports.first.to) if service.ports.size == 1
36
+
37
+ service.ports.each do |port|
38
+ res << port_env(from: port.from, to: port.to)
39
+ end
40
+
41
+ res.join "\n"
42
+ end
43
+
44
+ def port_env(from: nil, to:)
45
+ if from.nil?
46
+ "export #{service.name.upcase}_PORT=#{to}"
47
+ else
48
+ "export #{service.name.upcase}_PORT_#{from}=#{to}"
49
+ end
50
+ end
51
+
52
+ def has_ports?
53
+ service.ports.size > 0
54
+ end
55
+
56
+ def magic?
57
+ %w[postgres redis mysql memcached].include? service.name
58
+ end
59
+
60
+ def magic
61
+ case service.name
62
+ when "postgres"
63
+ "export DATABASE_URL=postgres://postgres@0.0.0.0:#{port_to(5432)}/#{database_name}"
64
+ when "mysql"
65
+ "export DATABASE_URL=mysql2://root@0.0.0.0:#{port_to(3306)}/#{database_name}"
66
+ when "redis"
67
+ "export REDIS_URL=redis://0.0.0.0:#{port_to(6379)}"
68
+ when "memcached"
69
+ "export MEMCACHE_SERVERS=0.0.0.0:#{port_to(11211)}"
70
+ end
71
+ end
72
+
73
+ def port_to(from)
74
+ service.ports.find { |p| p.from == from }&.to
75
+ end
76
+
77
+ def database_name
78
+ if defined? Rails
79
+ [
80
+ project,
81
+ Rails.env
82
+ ].join("_")
83
+ else
84
+ "db"
85
+ end
86
+ end
87
+ end
88
+ end
@@ -1,3 +1,3 @@
1
1
  module Devup
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devup
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sergei O. Udalov
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-06-05 00:00:00.000000000 Z
11
+ date: 2020-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: dotenv
@@ -35,6 +35,7 @@ files:
35
35
  - ".gitignore"
36
36
  - ".rspec"
37
37
  - ".ruby-version"
38
+ - ".standard.yml"
38
39
  - ".travis.yml"
39
40
  - ".vimrc"
40
41
  - CODE_OF_CONDUCT.md
@@ -45,7 +46,6 @@ files:
45
46
  - Rakefile
46
47
  - bin/console
47
48
  - bin/setup
48
- - demo.gif
49
49
  - devup.gemspec
50
50
  - exe/devup
51
51
  - lib/devup.rb
@@ -53,7 +53,9 @@ files:
53
53
  - lib/devup/compose.rb
54
54
  - lib/devup/dotenv.rb
55
55
  - lib/devup/environment.rb
56
+ - lib/devup/logger.rb
56
57
  - lib/devup/service.rb
58
+ - lib/devup/service_presenter.rb
57
59
  - lib/devup/version.rb
58
60
  homepage: https://github.com/sergio-fry/devup
59
61
  licenses:
data/demo.gif DELETED
Binary file