Skip to content
This repository has been archived by the owner on Apr 6, 2021. It is now read-only.

Commit

Permalink
Merge pull request #7 from shantytown/plugins-for-everything
Browse files Browse the repository at this point in the history
Use Plugins For Everything
  • Loading branch information
nathankleyn committed May 31, 2015
2 parents 4c6a7e8 + 5be04c1 commit 0f6cce6
Show file tree
Hide file tree
Showing 49 changed files with 519 additions and 964 deletions.
7 changes: 7 additions & 0 deletions .rubocop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,10 @@ require: rubocop-rspec

LineLength:
Max: 120

# This is a stupid lint. Yes, module_function is more explanatory than extend self for most use cases. However, the
# former does not work if you want the methods to be able to call private methods; the latter does. See
# https://practicingruby.com/articles/ruby-and-the-singleton-pattern-dont-get-along for a detailed explanation of the
# problem.
ModuleFunction:
Enabled: False
89 changes: 48 additions & 41 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ PATH
algorithms (~> 0.6)
attr_combined_accessor (~> 1.0)
call_me_ruby (~> 1.0)
commander (~> 4.2)
commander (~> 4.3)
i18n (~> 0.7)

GEM
Expand All @@ -18,87 +18,94 @@ GEM
astrolabe (1.3.0)
parser (>= 2.2.0.pre.3, < 3.0)
attr_combined_accessor (1.0.0)
byebug (3.5.1)
columnize (~> 0.8)
debugger-linecache (~> 1.2)
slop (~> 3.6)
byebug (4.0.5)
columnize (= 0.9.0)
call_me_ruby (1.0.2)
coderay (1.1.0)
columnize (0.9.0)
commander (4.2.1)
highline (~> 1.6.11)
coveralls (0.7.9)
multi_json (~> 1.10)
rest-client (~> 1.7)
simplecov (~> 0.9.1)
commander (4.3.4)
highline (~> 1.7.2)
coveralls (0.8.1)
json (~> 1.8)
rest-client (>= 1.6.8, < 2)
simplecov (~> 0.10.0)
term-ansicolor (~> 1.3)
thor (~> 0.19.1)
debugger-linecache (1.2.0)
diff-lcs (1.2.5)
docile (1.1.5)
filewatcher (0.3.6)
domain_name (0.5.24)
unf (>= 0.0.5, < 1.0.0)
filewatcher (0.5.1)
trollop (~> 2.0)
highline (1.6.21)
highline (1.7.2)
http-cookie (1.0.2)
domain_name (~> 0.5)
i18n (0.7.0)
json (1.8.2)
method_source (0.8.2)
mime-types (2.4.3)
multi_json (1.10.1)
netrc (0.10.2)
parser (2.2.0.2)
mime-types (2.6.1)
netrc (0.10.3)
parser (2.2.2.5)
ast (>= 1.1, < 3.0)
powerpack (0.1.0)
powerpack (0.1.1)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
slop (~> 3.4)
pry-byebug (2.0.0)
byebug (~> 3.4)
pry-byebug (3.1.0)
byebug (~> 4.0)
pry (~> 0.10)
rainbow (2.0.0)
rest-client (1.7.2)
rest-client (1.8.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 3.0)
netrc (~> 0.7)
rspec (3.2.0)
rspec-core (~> 3.2.0)
rspec-expectations (~> 3.2.0)
rspec-mocks (~> 3.2.0)
rspec-core (3.2.0)
rspec-core (3.2.3)
rspec-support (~> 3.2.0)
rspec-expectations (3.2.0)
rspec-expectations (3.2.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-mocks (3.2.0)
rspec-mocks (3.2.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.2.0)
rspec-support (3.2.1)
rubocop (0.29.0)
rspec-support (3.2.2)
rubocop (0.31.0)
astrolabe (~> 1.3)
parser (>= 2.2.0.1, < 3.0)
parser (>= 2.2.2.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.4)
rubocop-rspec (1.2.1)
ruby-progressbar (1.7.1)
simplecov (0.9.1)
rubocop-rspec (1.3.0)
ruby-prof (0.15.8)
ruby-progressbar (1.7.5)
simplecov (0.10.0)
docile (~> 1.1.0)
multi_json (~> 1.0)
simplecov-html (~> 0.8.0)
simplecov-html (0.8.0)
json (~> 1.8)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.0)
slop (3.6.0)
term-ansicolor (1.3.0)
tins (~> 1.0)
thor (0.19.1)
tins (1.3.4)
trollop (2.1.1)
tins (1.5.2)
trollop (2.1.2)
unf (0.1.4)
unf_ext
unf_ext (0.0.7.1)

PLATFORMS
ruby

DEPENDENCIES
coveralls (~> 0.7)
filewatcher (~> 0.3)
pry-byebug (~> 2.0)
coveralls (~> 0.8)
filewatcher (~> 0.5)
pry-byebug (~> 3.1)
rspec (~> 3.2)
rubocop (~> 0.28)
rubocop-rspec (~> 1.2)
rubocop (~> 0.31)
rubocop-rspec (~> 1.3)
ruby-prof (~> 0.15)
shanty!
71 changes: 39 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,59 @@
# Shanty [![Build Status](https://travis-ci.org/shantytown/shanty.svg?branch=master)](https://travis-ci.org/shantytown/shanty) [![Coverage Status](https://coveralls.io/repos/shantytown/shanty/badge.png?branch=master)](https://coveralls.io/r/shantytown/shanty?branch=master) [![Join the chat at https://gitter.im/shantytown/shanty](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/shantytown/shanty)

**Shanty** is a project orchestration tool. It is designed to make it easy for you to build dependencies between projects, and execute tasks across this tree of relationships, regardless of what language or technology these projects use. The aim is consistency in the way you manage, build, test and deploy your projects.
**Shanty** is a tool orchestrator. You can think of Shanty like make, but self-configuring, modular and useful for tasks that don't necessarily create files. It is designed to make it easy for you to build dependencies between projects, and execute tasks across this tree of relationships, regardless of what language or technology these projects use. The aim is consistency in the way you configure, manage, build, test and deploy your projects.

* Shanty is **language agnostic**. Shanty config files must be written in Ruby, but can be written for any type of project written in any language.
* Shanty **is not a build tool**. It is designed to work with your existing build tool, instead living a layer up where it manages tasks to call to your build tool.
* Shanty **is great for people with single repository, many subproject setups**. It makes it trivial to use your repository with many well known Continuous Integration tools and get benefits like building only changed projects, and depedency management.
* Shanty **supports plugins**. You can hook into the lifecycle of Shanty at any point to achieve the task you want. Plugins can discover projects, add support for a new VCS, add actions that will be executed when a command is run, and work out whether a project has changed or not based on more complex dependencies.
* Shanty is **language and framework agnostic**. Shanty can configure, build, test and deploy projects or configurations for any language or framework. Shanty config files are written in Ruby for expressiveness.
* Shanty is **self-configuring and pluggable**. Shanty plugins allow projects to be auto-discovered and configured with sensible defaults. Plugins will enrich a project with tasks and configure them such that most people who are following community best practice will find they don't need to write any configuration.
* Shanty **brings all of your tools and utilities together under a unified interface**. It is designed to work with your existing build tools, but allow you to run them all in a orchestrated and unified way.
* Shanty **is great for people with single repository, many subproject setups**. It makes it trivial for you to run a single build, test or deploy command and have it work for all of your subprojects regardless of language or framework.

## Why Would I Want To Use Shanty Instead Of `<Insert Build Tool Here>`?
## What Shanty Does

Shanty is designed to make it easy to run tasks consistently across projects of many different types or written in many different languages.
Lets say you have a project `Service` that builds an artifact. This project has a dependency on the artifact of another project called `Core`. We want to make a Docker container for the `Service` project.

A great example use case of Shanty is integrating with Docker:
In order to do this, you need to build the `Core` dependency, then build the `Service` project, and then build the Docker container.

Managing this in existing setups often requires cobbling together shell scripts, configuration files, and the build tools of your choice. Shanty is designed to manage these relationships for you, abstracting the tasks of building and linking these projects into plugins that get auto-triggered based on these relationships.

In this scenario, the relationship between `Core`, `Service` and the Docker container would be discovered, and builds would happen in order with the correct artifacts wired into where they need to be. Triggering this build would be as simple as `shanty build`, and the rest is taken care of for you.

## Using Shanty

### Getting Started

Firstly, you need to install Shanty, which is [available as a gem from RubyGems.org](https://rubygems.org/gems/shanty):

```sh
gem install shanty
```
Foo (Java) -> Bar (Java) -> Bar Container (Docker)

Then, inside the root of the project directory you want Shanty to manage, run the following to get started:

```sh
shanty init
```

Lets say you have a Java project `Bar` that builds an artifact. This Java project has a dependency on the artifact of another Java project called `Foo`. In order to dockerise the `Bar` project, you need to build the `Foo` dependency, then build the `Bar` project, and then build the Docker container.
This creates a `.shanty.yml` file, designating this folder as the root of the project tree.

Managing this in existing setups often requires cobbling together shell scripts and the build tool of your choice. Shanty is designed to manage these relationships for you, abstracting the tasks of building and linking these projects into plugins that get auto-triggered based on these relationships (think `make`). Projects like `Gradle` go a long way towards supporting this model with their multi-project support, but the expressiveness of Ruby is missed as soon as you need to do something menial like read in a JSON options file for a project.
### Stub

So, with Shanty, building the Docker container would be as simple as `shanty build` in the Docker container project folder, and the rest is taken care of for you. This is because Shanty is designed to give you the freedom to choose any tool for any project, written in any language, by allowing you to plug in functionality where you need it.
Shanty will try to find projects automatically using any Shanty plugins you have installed. The core of Shanty comes with a few built-in plugins:

## Contibuting
* `Bundler`: If a `Gemfile` is found anywhere, it will make sure the gems are pulled down and kept up to date when the `build` task is triggered.
* `RSpec`: Detects and runs RSpec tests when the `test` task is triggered.
* `Rubocop`: Detects and runs Rubocop to lint Ruby code when the `test` task is triggered.
* `Rubygem`: Detects a `*.gemspec` file and will build and package a gem when the `build` task is triggered.

We welcome any contribution, whether big or small! We're busy importing our planned work as GitHub issues so people can join in the fun, we also have a [Huboard](https://huboard.com/shantytown/shanty) to make following the progress easier. If you have any questions, please hit us up on our freenode IRC channel `#shantytown`.
To add more plugins, simply create a `Gemfile` in the root of the Shanty tree and add the plugins you would like. The `Bundler` plugin wil

## License
### Built-In Tasks

The MIT License (MIT)
### Using Plugins

Copyright (c) 2015 Chris Jansen, Nathan Kleyn
### Writing Plugins

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
### Per-Project Configuration

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
## Contributing

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
We welcome any contribution, whether big or small! Simply raise [GitHub pull requests](/pulls), and we'll collaborate with you! If you need ideas on what to work on, [look at the list of GitHub issues](/issues) or come and talk to us on our [Gitter IM channel](https://gitter.im/shantytown/shanty)!
2 changes: 0 additions & 2 deletions Shantyfile

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
parent 'examples/test-static-project-2'

after_create do
# This will run after the project has been created.
end
2 changes: 2 additions & 0 deletions examples/test-static-project/Shantyfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
option 'foo', 'bar'
tag 'lux'
14 changes: 6 additions & 8 deletions lib/shanty.rb
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
require 'i18n'
require 'pathname'
require 'pry'

require 'shanty/cli'
require 'shanty/env'
require 'shanty/graph'

# Require all discoverers, mutators, plugins and task sets.
Dir[File.join(__dir__, 'shanty', '{discoverers,mutators,plugins,task_sets}', '*.rb')].each { |f| require f }
# Require all plugins and task sets.
Dir[File.join(__dir__, 'shanty', '{plugins,task_sets}', '*.rb')].each { |f| require f }

module Shanty
# Main shanty class
class Shanty
include Env

# This is the root directory where the Shanty gem is located. Do not confuse this with the root of the repository
# in which Shanty is operating, which is available via the TaskEnv class.
GEM_ROOT = File.expand_path(File.join(__dir__, '..'))

def start!
setup_i18n
Cli.new(env, TaskSet.task_sets).run
require!
Cli.new(TaskSet.task_sets).run
end

private
Expand All @@ -27,9 +29,5 @@ def setup_i18n
I18n.enforce_available_locales = true
I18n.load_path = Dir[File.join(GEM_ROOT, 'translations', '*.yml')]
end

def env
Env.new.tap(&:require!)
end
end
end
12 changes: 3 additions & 9 deletions lib/shanty/cli.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
require 'commander'
require 'i18n'
require 'shanty/info'
require 'shanty/task_env'
require 'shanty/task_set'

module Shanty
Expand All @@ -10,17 +9,12 @@ module Shanty
class Cli
include Commander::Methods

attr_reader :env, :task_sets
attr_reader :task_sets

def initialize(env, task_sets)
@env = env
def initialize(task_sets)
@task_sets = task_sets
end

def task_env
@task_env ||= TaskEnv.new(@env)
end

def tasks
@tasks ||= task_sets.reduce({}) do |acc, task_set|
# FIXME: Warn or fail when there are duplicate task names?
Expand Down Expand Up @@ -70,7 +64,7 @@ def add_action_to_command(name, task, command)
end

def execute_task(name, task, options)
klass = task[:klass].new(task_env)
klass = task[:klass].new
arity = klass.method(name).arity
args = (arity >= 1 ? [options] : [])
klass.send(name, *args)
Expand Down
38 changes: 0 additions & 38 deletions lib/shanty/discoverer.rb

This file was deleted.

17 changes: 0 additions & 17 deletions lib/shanty/discoverers/rubygem_discoverer.rb

This file was deleted.

Loading

0 comments on commit 0f6cce6

Please sign in to comment.