ddsl 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f71118bf1db75829c800cdc9a8f8be55a563f22b
4
+ data.tar.gz: 4009fa8ce03a9c76b085e8b5fdc01ad5f37a27b1
5
+ SHA512:
6
+ metadata.gz: c5994bb90f41a8f49358f9ef9f1b76c1bbb40d6693c933d390d89f6b7b118bc4f4c59f917f341fc273441895f889343307ca955b596ae3e2f957a447499d7890
7
+ data.tar.gz: 8399bd7b709813fe7fafba8fe51a1bf9ee2b256be72a49fc417c22f2097bd80d765a3e238a51bac20bed710db1db4e16c8abd328cfe74d9dee62bcec6a79a34d
@@ -0,0 +1,56 @@
1
+ version: 2
2
+
3
+ docker_options: &docker_options
4
+ working_directory: ~/ddsl
5
+ docker:
6
+ - image: bilby91/ddsl:latest
7
+ auth:
8
+ username: $DOCKER_REGISTRY_USERNAME
9
+ password: $DOCKER_REGISTRY_PASSWORD
10
+
11
+ workflows:
12
+ version: 2
13
+ build-deploy:
14
+ jobs:
15
+ - build
16
+ - test:
17
+ requires:
18
+ - build
19
+ - lint:
20
+ requires:
21
+ - build
22
+
23
+ jobs:
24
+ build:
25
+ <<: *docker_options
26
+ steps:
27
+ - checkout
28
+ - setup_remote_docker
29
+ - run:
30
+ command: echo "$DOCKER_REGISTRY_PASSWORD" | docker login --username $DOCKER_REGISTRY_USERNAME --password-stdin
31
+ - run:
32
+ command: |
33
+ export CI_SHA1=$CIRCLE_SHA1
34
+ ddsl build feature-branch
35
+ test:
36
+ <<: *docker_options
37
+ steps:
38
+ - checkout
39
+ - setup_remote_docker
40
+ - run:
41
+ command: echo "$DOCKER_REGISTRY_PASSWORD" | docker login --username $DOCKER_REGISTRY_USERNAME --password-stdin
42
+ - run:
43
+ command: |
44
+ export CI_SHA1=$CIRCLE_SHA1
45
+ ddsl run test-ci
46
+ lint:
47
+ <<: *docker_options
48
+ steps:
49
+ - checkout
50
+ - setup_remote_docker
51
+ - run:
52
+ command: echo "$DOCKER_REGISTRY_PASSWORD" | docker login --username $DOCKER_REGISTRY_USERNAME --password-stdin
53
+ - run:
54
+ command: |
55
+ export CI_SHA1=$CIRCLE_SHA1
56
+ ddsl run lint-ci
data/.ddsl.yml ADDED
@@ -0,0 +1,48 @@
1
+ version: 1
2
+
3
+ builds:
4
+ - name: feature-branch
5
+ type: docker
6
+ context: .
7
+ file: docker/Dockerfile
8
+ tags:
9
+ - bilby91/ddsl:$CI_SHA1
10
+ push: true
11
+ cache_from:
12
+ - bilby91/ddsl:latest
13
+ - name: master-branch
14
+ type: docker
15
+ context: .
16
+ file: docker/Dockerfile
17
+ tags:
18
+ - bilby91/ddsl:$CI_SHA1
19
+ - bilby91/ddsl:latest
20
+ push: true
21
+ cache_from:
22
+ - bilby91/ddsl:latest
23
+ - name: dev
24
+ type: docker-compose
25
+ file: docker/docker-compose.yml
26
+
27
+ runs:
28
+ - name: bash
29
+ type: docker-compose
30
+ file: docker/docker-compose.yml
31
+ service: ddsl
32
+ cmd: /bin/bash
33
+ - name: test-ci
34
+ type: docker
35
+ image: bilby91/ddsl:$CI_SHA1
36
+ cmd: rspec spec .
37
+ - name: test
38
+ type: docker
39
+ image: bilby91/ddsl:latest
40
+ cmd: rspec spec .
41
+ - name: lint-ci
42
+ type: docker
43
+ image: bilby91/ddsl:$CI_SHA1
44
+ cmd: rubocop .
45
+ - name: lint
46
+ type: docker
47
+ image: bilby91/ddsl:latest
48
+ cmd: rubocop .
data/.gitignore ADDED
@@ -0,0 +1,5 @@
1
+ # Code Coverage
2
+ coverage
3
+
4
+ # Compiled gem
5
+ *.gem
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,19 @@
1
+ AllCops:
2
+ TargetRubyVersion: 2.4
3
+
4
+ Metrics/LineLength:
5
+ Max: 120
6
+
7
+ Metrics/MethodLength:
8
+ Max: 15
9
+
10
+ Metrics/BlockLength:
11
+ Exclude:
12
+ - 'spec/**/*.rb'
13
+
14
+ Style/Documentation:
15
+ Enabled: false
16
+
17
+ Style/AccessModifierDeclarations:
18
+ EnforcedStyle: inline
19
+
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,68 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ddsl (0.0.1)
5
+ clamp (~> 1)
6
+ json-schema (~> 2)
7
+ transproc (~> 1)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ addressable (2.5.2)
13
+ public_suffix (>= 2.0.2, < 4.0)
14
+ ast (2.4.0)
15
+ clamp (1.3.0)
16
+ diff-lcs (1.3)
17
+ docile (1.3.1)
18
+ jaro_winkler (1.5.1)
19
+ json (2.1.0)
20
+ json-schema (2.8.1)
21
+ addressable (>= 2.4)
22
+ parallel (1.12.1)
23
+ parser (2.5.3.0)
24
+ ast (~> 2.4.0)
25
+ powerpack (0.1.2)
26
+ public_suffix (3.0.3)
27
+ rainbow (3.0.0)
28
+ rspec (3.8.0)
29
+ rspec-core (~> 3.8.0)
30
+ rspec-expectations (~> 3.8.0)
31
+ rspec-mocks (~> 3.8.0)
32
+ rspec-core (3.8.0)
33
+ rspec-support (~> 3.8.0)
34
+ rspec-expectations (3.8.2)
35
+ diff-lcs (>= 1.2.0, < 2.0)
36
+ rspec-support (~> 3.8.0)
37
+ rspec-mocks (3.8.0)
38
+ diff-lcs (>= 1.2.0, < 2.0)
39
+ rspec-support (~> 3.8.0)
40
+ rspec-support (3.8.0)
41
+ rubocop (0.60.0)
42
+ jaro_winkler (~> 1.5.1)
43
+ parallel (~> 1.10)
44
+ parser (>= 2.5, != 2.5.1.1)
45
+ powerpack (~> 0.1)
46
+ rainbow (>= 2.2.2, < 4.0)
47
+ ruby-progressbar (~> 1.7)
48
+ unicode-display_width (~> 1.4.0)
49
+ ruby-progressbar (1.10.0)
50
+ simplecov (0.16.1)
51
+ docile (~> 1.1)
52
+ json (>= 1.8, < 3)
53
+ simplecov-html (~> 0.10.0)
54
+ simplecov-html (0.10.2)
55
+ transproc (1.0.2)
56
+ unicode-display_width (1.4.0)
57
+
58
+ PLATFORMS
59
+ ruby
60
+
61
+ DEPENDENCIES
62
+ ddsl!
63
+ rspec (~> 3)
64
+ rubocop (~> 0.60)
65
+ simplecov (~> 0.16)
66
+
67
+ BUNDLED WITH
68
+ 1.17.1
data/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # ddsl
2
+
3
+ Docker Declarative Specific Language
4
+
5
+ `ddsl` lets you declare how your docker images are built and what checks (test, linter, etc) need be run in your images.
6
+
7
+ ```yaml
8
+ version: 1
9
+
10
+ builds:
11
+ - name: main
12
+ type: docker
13
+ context: .
14
+ file: docker/Dockerfile
15
+ tags:
16
+ - bilby91/ddsl:latest
17
+ - name: dev
18
+ type: docker-compose
19
+ file: docker/docker-compose.yml
20
+
21
+ runs:
22
+ - name: bash
23
+ type: docker-compose
24
+ file: docker/docker-compose.yml
25
+ service: ddsl
26
+ cmd: /bin/bash
27
+
28
+ - name: test
29
+ type: docker
30
+ image: bilby91/ddsl:latest
31
+ cmd: rspec spec .
32
+
33
+ - name: lint
34
+ type: docker
35
+ image: bilby91/ddsl:latest
36
+ cmd: rubocop .
37
+ ```
38
+
39
+ ## Dependencies
40
+
41
+ - ruby
42
+ - docker
43
+ - docker-compose
44
+
45
+ ## TODO
46
+
47
+ - [X] Docker Compose support
48
+ - [X] Variable interpolation
49
+ - [X] Build/Test DDSL using DDSL. Inception :)
50
+ - [ ] Add CI GitLab
51
+ - [ ] Add CI Travis
52
+ - [ ] Variable sharing/reusing
53
+ - [ ] Registries?
54
+ - [ ] External secret proviers ? (KMS, Google?)
55
+
56
+ ## Contact
57
+
58
+ - Martín Fernández <mfernandez@geofore.com>
data/bin/ddsl ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/ddsl'
5
+
6
+ DDSL::CLI.run
data/bin/dev ADDED
@@ -0,0 +1,15 @@
1
+ #!/bin/bash
2
+
3
+ export COMPOSE_FILE=docker/docker-compose.yml
4
+
5
+ case "$1" in
6
+ bash)
7
+ docker-compose run --rm ddsl /bin/bash
8
+ ;;
9
+ build)
10
+ docker-compose build
11
+ ;;
12
+ down)
13
+ docker-compose down
14
+ ;;
15
+ esac
data/ddsl.gemspec ADDED
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'ddsl/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'ddsl'
9
+ spec.version = DDSL::VERSION
10
+ spec.homepage = 'https://github.com/bilby91/ddsl'
11
+ spec.license = 'MIT'
12
+ spec.authors = ['Martin Fernandez']
13
+ spec.email = ['fmartin91@gmail.com']
14
+ spec.summary = 'Docker Declarative Specific Language'
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ spec.executables = ['ddsl']
19
+ spec.require_paths = ['lib']
20
+ spec.add_dependency 'clamp', '~> 1'
21
+ spec.add_dependency 'json-schema', '~> 2'
22
+ spec.add_dependency 'transproc', '~> 1'
23
+ spec.add_development_dependency 'rspec', '~> 3'
24
+ spec.add_development_dependency 'rubocop', '~> 0.60'
25
+ spec.add_development_dependency 'simplecov', '~> 0.16'
26
+ end
data/docker/Dockerfile ADDED
@@ -0,0 +1,44 @@
1
+ FROM docker:18.05
2
+
3
+ LABEL maintainer="Martín Fernández <mfernandez@geoforce.com>"
4
+
5
+ ENV APP_HOME /var/www/app
6
+
7
+ # Install the base tooling
8
+ RUN apk add --no-cache \
9
+ build-base \
10
+ gcc \
11
+ python \
12
+ py-pip \
13
+ python-dev \
14
+ gettext \
15
+ curl \
16
+ bash \
17
+ git \
18
+ ruby \
19
+ ruby-dev \
20
+ ruby-bigdecimal
21
+
22
+ # Install docker-compose
23
+ RUN pip install docker-compose
24
+
25
+ # Install ruby dependencies
26
+ RUN gem install bundler --no-ri
27
+
28
+ WORKDIR ${APP_HOME}
29
+
30
+ # Copy only Gemfile for caching
31
+ COPY lib/ddsl/version.rb $APP_HOME/lib/ddsl/version.rb
32
+ COPY Gemfile* *.gemspec $APP_HOME/
33
+
34
+ # Install ruby dependencies
35
+ RUN bundle install
36
+
37
+ # COPY app to container
38
+ COPY . $APP_HOME
39
+
40
+ # Build the gem locally
41
+ RUN bundle exec gem build ddsl.gemspec
42
+
43
+ # Install binary
44
+ RUN bundle exec gem install --no-rdoc --no-ri --local ddsl-0.0.1.gem
@@ -0,0 +1,34 @@
1
+ FROM docker:18.05
2
+
3
+ LABEL maintainer="Martín Fernández <mfernandez@geoforce.com>"
4
+
5
+ ENV APP_HOME /var/www/app
6
+
7
+ # Install the base tooling
8
+ RUN apk add --no-cache \
9
+ build-base \
10
+ gcc \
11
+ python \
12
+ py-pip \
13
+ python-dev \
14
+ gettext \
15
+ curl \
16
+ bash \
17
+ git \
18
+ ruby \
19
+ ruby-dev \
20
+ ruby-bigdecimal
21
+
22
+ # Install untrusted packages (separate line for scoping)
23
+ RUN apk add --no-cache \
24
+ --repository http://dl-3.alpinelinux.org/alpine/edge/testing/ \
25
+ --allow-untrusted \
26
+ aws-cli
27
+
28
+ # Install docker-compose
29
+ RUN pip install docker-compose
30
+
31
+ # Install ruby dependencies
32
+ RUN gem install builder bundler --no-ri
33
+
34
+ WORKDIR ${APP_HOME}
@@ -0,0 +1,22 @@
1
+ version: '3'
2
+
3
+ volumes:
4
+ ddsl_bundle:
5
+
6
+ services:
7
+ dind:
8
+ image: docker:dind
9
+ privileged: true
10
+ ddsl:
11
+ build:
12
+ context: ../
13
+ dockerfile: docker/Dockerfile.dev
14
+ environment:
15
+ BUNDLE_PATH: /bundle
16
+ DOCKER_HOST: tcp://dind:2375
17
+ volumes:
18
+ - ../:/var/www/app:cached
19
+ - ddsl_bundle:/bundle:cached
20
+ - ~/.bash_history:/root/.bash_history
21
+ depends_on:
22
+ - dind
data/lib/ddsl/cli.rb ADDED
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'clamp'
4
+
5
+ require_relative './parser'
6
+ require_relative './variable_injector'
7
+ require_relative './shell'
8
+ require_relative './command'
9
+
10
+ module DDSL
11
+ class CLI < Clamp::Command
12
+ option '--config', 'CONFIG', 'Configuration file path'
13
+
14
+ subcommand 'build', 'Build the docker image associated with the project' do
15
+ parameter 'NAME ...', 'name of the build', required: true, attribute_name: :names
16
+
17
+ def execute
18
+ with_builder(search_targets!('builds')) do |runner, spec|
19
+ begin
20
+ runner.run(spec)
21
+ rescue DDSL::Shell::ExitStatusError
22
+ $stdout.puts 'Build failed.'
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ subcommand 'run', 'Run a docker container or docker-compose service' do
29
+ parameter 'NAME ...', 'name of the run', required: true, attribute_name: :names
30
+
31
+ def execute
32
+ with_runner(search_targets!('runs')) do |runner, spec|
33
+ begin
34
+ runner.run(spec)
35
+ rescue DDSL::Shell::ExitStatusError
36
+ $stdout.puts 'Run failed.'
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ private def with_builder(builds)
43
+ builds.map do |b|
44
+ yield(builder_for_type(b['type']), b)
45
+ end
46
+ end
47
+
48
+ private def with_runner(runs)
49
+ runs.map do |r|
50
+ yield(runner_for_type(r['type']), r)
51
+ end
52
+ end
53
+
54
+ private def runner_for_type(type)
55
+ case type
56
+ when 'docker'
57
+ Command::Docker::Run.new
58
+ when 'docker-compose'
59
+ Command::DockerCompose::Run.new
60
+ end
61
+ end
62
+
63
+ private def builder_for_type(type)
64
+ case type
65
+ when 'docker'
66
+ Command::Docker::Build.new
67
+ when 'docker-compose'
68
+ Command::DockerCompose::Build.new
69
+ end
70
+ end
71
+
72
+ private def search_targets!(type)
73
+ command_targets = targets(type)
74
+ raise Clamp::UsageError.new('invalid NAME given', type) unless command_targets.count == names.count
75
+
76
+ command_targets
77
+ end
78
+
79
+ private def targets(type)
80
+ parsed_config[type].select { |item| names.include? item['name'] }
81
+ end
82
+
83
+ private def config_path
84
+ @config_path ||= config || '.ddsl.yml'
85
+ end
86
+
87
+ private def parsed_config
88
+ @parsed_config ||= DDSL::VariableInjector.new(ENV).inject(
89
+ DDSL::Parser.new.parse(config_path)
90
+ )
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative './dsl'
4
+
5
+ module DDSL
6
+ module Command
7
+ class Base
8
+ include DSL
9
+
10
+ attr_reader :shell
11
+
12
+ def initialize(shell = DDSL::Shell.new)
13
+ @shell = shell
14
+ end
15
+
16
+ def run(spec)
17
+ argv = [
18
+ executable,
19
+ executable_options.call(spec),
20
+ command,
21
+ options.call(spec),
22
+ arguments.call(spec).values
23
+ ].flatten
24
+
25
+ @shell.call!(argv)
26
+
27
+ exec_after_block(spec)
28
+ end
29
+
30
+ def exec_after_block(spec)
31
+ instance_exec(spec, &after_block) unless after_block.nil?
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base'
4
+
5
+ module DDSL
6
+ module Command
7
+ module Docker
8
+ class Build < Base
9
+ executable 'docker'
10
+ command 'build'
11
+
12
+ options do
13
+ accept_keys(%w[
14
+ build_args file cache_from tags labels rm
15
+ ])
16
+
17
+ rename_keys(
18
+ 'build_args' => 'build_arg',
19
+ 'tags' => 'tag',
20
+ 'labels' => 'label'
21
+ )
22
+
23
+ optionize_keys
24
+ expand_options
25
+ end
26
+
27
+ arguments do
28
+ accept_keys(['context'])
29
+ end
30
+
31
+ after do |spec|
32
+ spec['tags'].each { |t| Push.new(shell).run('image' => t) } if spec['push'] && spec['tags'].count.positive?
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base'
4
+
5
+ module DDSL
6
+ module Command
7
+ module Docker
8
+ class Push < Base
9
+ executable 'docker'
10
+ command 'push'
11
+
12
+ arguments do
13
+ accept_keys(['image'])
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base'
4
+
5
+ module DDSL
6
+ module Command
7
+ module Docker
8
+ class Run < Base
9
+ executable 'docker'
10
+ command 'run'
11
+
12
+ options do
13
+ accept_keys(%w[
14
+ rm envs volumes ports
15
+ ])
16
+
17
+ rename_keys(
18
+ 'envs' => 'env',
19
+ 'volumes' => 'volume',
20
+ 'ports' => 'publish'
21
+ )
22
+
23
+ optionize_keys
24
+ expand_options
25
+ end
26
+
27
+ arguments do
28
+ accept_keys(%w[image cmd])
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../base'
4
+
5
+ module DDSL
6
+ module Command
7
+ module DockerCompose
8
+ class Build < Base
9
+ executable 'docker-compose'
10
+ command 'build'
11
+
12
+ executable_options do
13
+ accept_keys([
14
+ 'file'
15
+ ])
16
+
17
+ optionize_keys
18
+ expand_options
19
+ end
20
+
21
+ options do
22
+ accept_keys(%w[
23
+ build_args memory parallel compress force_rm pull no_cache
24
+ ])
25
+
26
+ rename_keys(
27
+ 'build_args' => 'build_arg'
28
+ )
29
+
30
+ optionize_keys
31
+ expand_options
32
+ end
33
+
34
+ arguments do
35
+ accept_keys(['service'])
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end