devup 0.2.0 → 0.3.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 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