Djin

Maintainability Test Coverage

Djin is a make-like utility for docker containers

Installation

Djin is distributed as a Ruby Gem, to install simple run:

$ gem install djin

With Rbenv

If you use Rbenv you can install djin only once and create an alias in your .basrc, .zshrc, etc:

ZSH

$ RBENV_VERSION=$(rbenv global) gem install djin && echo "alias djin='RBENV_VERSION=$(rbenv global) djin'" >> ~/.zshrc

Bash

$ RBENV_VERSION=$(rbenv global) gem install djin && echo "alias djin='RBENV_VERSION=$(rbenv global) djin'" >> ~/.bashrc

Usage

To use djin first you need to create a djin.yml file:

djin_version: '0.11.7'

tasks:
  # With a docker image
  script:
    docker:
      image: "ruby:2.6"
      run:
        commands:
          - "ruby /scripts/my_ruby_script.rb"
        options: "--rm -v $(pwd)/my_ruby_script.rb:/scripts/my_ruby_script.rb"

  # Using a docker-compose service
  test:
    docker-compose:
      service: app
      run:
        commands: rspec
        options: "--rm"
    aliases: # Optional Array of strings
      - rspec

You can also set task dependencies with depends_on option:

djin_version: '0.11.7'

_default_run_options: &default_run_options
  options: "--rm"

tasks:
  "db:create":
    docker-compose:
      service: app
      run:
        commands: rake db:create
        <<: *default_run_options

  "db:migrate":
    docker-compose:
      service: app
      run:
        commands: rake db:migrate
        <<: *default_run_options

  "db:setup":
    depends_on:
      - "db:create"
      - "db:migrate"

Or mix local commands and docker/docker-compose commands:

djin_version: '0.11.7'

_default_run_options: &default_run_options
  options: "--rm"

tasks:
  "db:create":
    docker-compose:
      service: app
      run:
        commands: rake db:create
        <<: *default_run_options

  "db:migrate":
    docker-compose:
      service: app
      run:
        commands: rake db:migrate
        <<: *default_run_options

  "setup:copy_samples":
    local:
      run:
        - cp config/database.yml.sample config/database.yml

  "setup":
    depends_on:
      - "setup:copy_samples"
      - "db:create"
      - "db:migrate"

After that you can run djin {{task_name}}, like djin script or djin test

Using Environment variables, custom variables and custom args in djin.yml tasks

You can also use environment variables using the '{YOUR_ENV_HERE}' syntax, like so:

djin_version: '0.11.7'

_default_run_options: &default_run_options
  options: "--rm"

tasks:
  "db:migrate":
    docker-compose:
      service: app
      run:
        commands: ENV={{ENV}} rake db:migrate
        <<: *default_run_options

Or define some variables to use in multiple locations

djin_version: '0.11.7'

_default_run_options: &default_run_options
  options: "--rm"

variables:
  my_ssh_user: user
  some_host: test.local

tasks:
  "some_host:ssh":
    local:
      run:
        - ssh {{my_ssh_user}}@{{some_host}}

  "some_host:logs":
    local:
      run:
        - ssh -t {{my_ssh_user}}@{{some_host}} 'tail -f /var/log/syslog'

It's also possible to pass custom arguments to the command, which means is possible to make a djin task act like the command itself:

djin_version: '0.11.7'

_default_run_options: &default_run_options
  options: "--rm"

tasks:
  "rubocop":
    docker-compose:
      service: app
      run:
        commands: rubocop {{args}}
        <<: *default_run_options
    aliases:
      - lint

With that, you can pass custom args after --, eg: djin rubocop -- --parallel, which will make djin runs rubocop --parallel inside the service app.

Under the hood djin uses Mustache, so you can use other features like conditionals: {{#IS_ENABLE}} Enabled {{/IS_ENABLE}} (for args use the args?, eg: {{#args?}} {{args}} --and-other-thing{{/args?}}), to see more more options you can access this Link

Reusing tasks

If you have multiple tasks with similar behavior and with small differences you can use the include keyword, so this:

djin_version: '0.11.7'

tasks:
  "host1:ssh":
    local:
      run:
        - ssh [email protected]

  "host1:restart":
    local:
      run:
        - ssh -t [email protected] restart

  "host1:logs":
    local:
      run:
        - ssh -t [email protected] tail -f /var/log/my_log

  "host2:ssh":
    local:
      run:
        - ssh [email protected]

  "host2:restart":
    local:
      run:
        - ssh -t [email protected] restart

  "host2:logs":
    local:
      run:
        - ssh -t [email protected] tail -f /var/log/my_file

can become this:

# djin.yml
djin_version: '0.11.7'

include:
  - file: '.djin/server_tasks.yml'
    context:
      variables:
        namespace: host1
        host: host1.com
        ssh_user: my_user

  - file: '.djin/server_tasks.yml'
    context:
      variables:
        namespace: host2
        host: host2.com
        ssh_user: my_user

# .djin/server_tasks.yml
djin_version: '0.11.7'

tasks:
  "{{namespace}}:ssh":
    local:
      run:
        - ssh {{ssh_user}}@{{host}}

  "{{namespace}}:restart":
    local:
      run:
        - ssh -t {{ssh_user}}@{{host}} restart

  "{{namespace}}:logs":
    local:
      run:
        - ssh -t {{ssh_user}}@{{host}} tail -f /var/log/my_log

You can also reuse tasks in some git repository, to do that you need to declare a git source and optionally a version:

djin_version: '0.11.7'

include:
  - git: 'https://github.com/catks/djin.git'
    version: 'master'
    file: 'examples/djin_lib/test.yml'
    context:
      variables:
        namespace: 'remote:'

After that run djin remote-config fetch to fetch the repo and you can start using the tasks (All remote repos are cloned in ~/.djin/remote)

See djin remote-config to learn more.

Loading custom files

You can also specify a file to be read by djin with -f, eg:

djin -f my_file.yml # Returns the help for all tasks in my_file
djin -f my_file.yml build # Execute the build task defined in my_file.yml

You can also specify multiple files to join tasks between files:

# Mix the tasks
djin -f my_file.yml -f my_file2.yml # Returns the help for all tasks in my_file
djin -f my_file.yml -f my_file2.yml build # Execute the build task defined in my_file.yml or my_file2.yml

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, run djin release -- {{increment_option}} (where {incremment_option} can be --patch, --minor or major), which will change version, update the CHANGELOG.md, create a new commit, create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

TODO

  1. Option to export tasks to Makefile
  2. djin-export docker image to create and sync makefiles

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/catks/djin.

License

The gem is available as open source under the terms of the MIT License.