pairzone 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +26 -0
- data/.rspec +1 -0
- data/.rvmrc +7 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +76 -0
- data/README.md +44 -0
- data/Rakefile +14 -0
- data/bin/pairzone +83 -0
- data/config/cucumber.yml +4 -0
- data/features/collaborator_joins_pairzone.feature +20 -0
- data/features/developer_signs_in.feature +11 -0
- data/features/developer_starts_pairzone.feature +35 -0
- data/features/keys/bob.key +12 -0
- data/features/keys/bob.key.pub +1 -0
- data/features/keys/derek.key +27 -0
- data/features/keys/derek.key.pub +1 -0
- data/features/server/stub-pairzone-server.rb +76 -0
- data/features/step_definitions/authorisation_steps.rb +8 -0
- data/features/step_definitions/info_steps.rb +5 -0
- data/features/step_definitions/repository_steps.rb +6 -0
- data/features/step_definitions/running_steps.rb +32 -0
- data/features/step_definitions/starting_steps.rb +47 -0
- data/features/support/aruba.rb +1 -0
- data/features/support/env.rb +5 -0
- data/features/support/helpers/server_helper.rb +40 -0
- data/features/support/hooks.rb +24 -0
- data/features/support/pairzone-config.rb +13 -0
- data/lib/pairzone.rb +14 -0
- data/lib/pairzone/api/base.rb +27 -0
- data/lib/pairzone/api/pairzone.rb +25 -0
- data/lib/pairzone/api/pairzone_connection.rb +32 -0
- data/lib/pairzone/api/pairzone_lifecycle.rb +34 -0
- data/lib/pairzone/api/user.rb +16 -0
- data/lib/pairzone/authenticate.rb +51 -0
- data/lib/pairzone/commands/info.rb +25 -0
- data/lib/pairzone/commands/join.rb +21 -0
- data/lib/pairzone/commands/start.rb +29 -0
- data/lib/pairzone/logger.rb +33 -0
- data/lib/pairzone/shell.rb +38 -0
- data/lib/pairzone/version.rb +3 -0
- data/pairzone.gemspec +35 -0
- data/spec/pairzone/api/pairzone_lifecycle_spec.rb +26 -0
- data/spec/pairzone/authentication_spec.rb +44 -0
- data/spec/pairzone/logger_spec.rb +41 -0
- data/spec/spec_helper.rb +7 -0
- metadata +292 -0
@@ -0,0 +1,8 @@
|
|
1
|
+
When /^"([^"]*)" supplies his credentials$/ do |developer_name|
|
2
|
+
When %{I type "#{developer_name}@example.com"}
|
3
|
+
And %{I type "#{developer_name}_password"}
|
4
|
+
end
|
5
|
+
|
6
|
+
Then /^his API key is saved$/ do
|
7
|
+
Then %{the file "#{config_directory}/authentication_token" should contain "#{@apikey}"}
|
8
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
def save_token(username)
|
2
|
+
create_api_account_for(username) unless tokens.include? username
|
3
|
+
Pairzone::Authenticate.save_token("#{config_directory}/authentication_token", tokens[username])
|
4
|
+
end
|
5
|
+
|
6
|
+
def pairzone_command(command, identity = 'bob', interactive = false)
|
7
|
+
pairzone, *args = command.split
|
8
|
+
interactively = interactive ? " interactively" : ""
|
9
|
+
When %{I run "#{pairzone} --server=localhost:54101 --debug --config=#{config_directory} --identity=../../features/keys/#{identity}.key #{args.join(' ')}"#{interactively}}
|
10
|
+
end
|
11
|
+
|
12
|
+
When /^"([^"]*)" runs? "([^"]*)" in test mode$/ do |developer_name, command|
|
13
|
+
save_token(developer_name)
|
14
|
+
pairzone_command(command, developer_name)
|
15
|
+
end
|
16
|
+
|
17
|
+
When /^"([^"]*)" runs "([^"]*)" in test mode with no api key$/ do |developer_name, command|
|
18
|
+
create_api_account_for(developer_name)
|
19
|
+
pairzone_command(command, developer_name, true)
|
20
|
+
end
|
21
|
+
|
22
|
+
Given /^"([^"]*)" has already started a pairzone with "([^"]*)" as a collaborator$/ do |developer_name, collaborator_name|
|
23
|
+
Given "I have a local git repository"
|
24
|
+
save_token(developer_name)
|
25
|
+
pairzone_command("pairzone start --background -c #{collaborator_name}", developer_name)
|
26
|
+
end
|
27
|
+
|
28
|
+
Given /^"([^"]*)" has already started a pairzone$/ do |developer_name|
|
29
|
+
Given "I have a local git repository"
|
30
|
+
save_token(developer_name)
|
31
|
+
pairzone_command("pairzone start --background", developer_name)
|
32
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
def look_for(text)
|
2
|
+
Then %{the output should contain "#{text}"}
|
3
|
+
end
|
4
|
+
|
5
|
+
Then /^a new pairzone is started for "([^"]*)"$/ do |developer_name|
|
6
|
+
look_for "Starting Pairzone for project 'aruba'..."
|
7
|
+
look_for "Pairzone '#{developer_name}-aruba' started."
|
8
|
+
look_for "Pairzone booted: ip address 127.0.0.1"
|
9
|
+
end
|
10
|
+
|
11
|
+
Then /^no pairzone should be started$/ do
|
12
|
+
And %{the output should not contain "started"}
|
13
|
+
end
|
14
|
+
|
15
|
+
Then /^a new pairzone is started for "([^"]*)" in the background$/ do |developer_name|
|
16
|
+
Then %{a new pairzone is started for "#{developer_name}"}
|
17
|
+
And %{the output should not contain "pairzone-tmux"} # We cannot run the session, but if this shows up we tried to
|
18
|
+
end
|
19
|
+
|
20
|
+
Then /^the code in my current directory is pushed to the server$/ do
|
21
|
+
look_for "pushing local code to pairzone instance"
|
22
|
+
look_for "master -> master (forced update)" # the git printout
|
23
|
+
end
|
24
|
+
|
25
|
+
Then /^an SSH connection is made to my new pairzone$/ do
|
26
|
+
look_for "/usr/local/bin/pairzone-tmux.sh: No such file or directory" # We cannot run the session, but this will show we tried to
|
27
|
+
end
|
28
|
+
|
29
|
+
Then /^the code is downloaded to a "([^"]*)" branch when I quit the session$/ do |branch_name|
|
30
|
+
Then %{the output should match /master.*->.*#{branch_name}/}
|
31
|
+
end
|
32
|
+
|
33
|
+
Then /^"([^"]*)" is added as a collaborator on my new pairzone$/ do |collaborator_name|
|
34
|
+
look_for "Collaborator '#{collaborator_name}' added."
|
35
|
+
end
|
36
|
+
|
37
|
+
Then /^"([^"]*)" is not added as a collaborator on my new pairzone$/ do |collaborator_name|
|
38
|
+
Then %{the output should not contain "Collaborator '#{collaborator_name}' added."}
|
39
|
+
end
|
40
|
+
|
41
|
+
Then /^"([^"]*)" should be connected to "([^"]*)"$/ do |arg1, arg2|
|
42
|
+
look_for "/usr/local/bin/pairzone-tmux.sh: No such file or directory" # We cannot run the session, but this will show we tried to
|
43
|
+
end
|
44
|
+
|
45
|
+
Then /^"([^"]*)" should not be able to connect$/ do |collaborator_name|
|
46
|
+
look_for "No pairzone exists"
|
47
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'aruba/cucumber'
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'background_process'
|
2
|
+
|
3
|
+
module ServerHelper
|
4
|
+
SERVER_PATH = "#{File.dirname(__FILE__)}/../../../../pairzone-web"
|
5
|
+
def server(command)
|
6
|
+
wrapped = "bash -lc 'cd #{SERVER_PATH} && BUNDLE_GEMFILE=#{SERVER_PATH}/Gemfile && #{command}'"
|
7
|
+
BackgroundProcess.run(wrapped)
|
8
|
+
end
|
9
|
+
|
10
|
+
def start_server
|
11
|
+
@server = server("rails s -e smoke -p 54101")
|
12
|
+
@server.detect {|line| out << line; line =~ /WEBrick::HTTPServer#start/ }
|
13
|
+
end
|
14
|
+
|
15
|
+
def out
|
16
|
+
@out ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop_server
|
20
|
+
if (@server && @server.running?)
|
21
|
+
# only reliable way I've found to kill it, as it's in a subshell
|
22
|
+
`ps ax | grep "rails s -e smoke -p 54101" | grep -v bash | grep -v grep | cut -d' ' -f 1 | xargs kill -s INT`
|
23
|
+
@server.wait
|
24
|
+
out << @server.stdout.read
|
25
|
+
out << @server.stderr.read
|
26
|
+
end
|
27
|
+
puts "\nTest server output:\n" + out.join if @show_web_server_output
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_api_account_for(developer_name)
|
31
|
+
@rake = server("RAILS_ENV=smoke rake db:reset db:setup pairzone:test:clear_users pairzone:test:add_user[#{developer_name},#{developer_name}_password]")
|
32
|
+
@rake.wait
|
33
|
+
out << @rake.stderr.read
|
34
|
+
key = @rake.stdout.read.split.last.strip
|
35
|
+
out << "Created api account for #{developer_name}. Key: #{key}\n\n"
|
36
|
+
tokens[developer_name] = key
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
World(ServerHelper)
|
@@ -0,0 +1,24 @@
|
|
1
|
+
Before("@api_server") do
|
2
|
+
start_server
|
3
|
+
end
|
4
|
+
|
5
|
+
Before("@announce") do
|
6
|
+
@show_web_server_output = true
|
7
|
+
end
|
8
|
+
|
9
|
+
Before('@derek') do
|
10
|
+
create_api_account_for('derek')
|
11
|
+
end
|
12
|
+
|
13
|
+
Before('@bob') do
|
14
|
+
create_api_account_for('bob')
|
15
|
+
end
|
16
|
+
|
17
|
+
Before('@jim') do
|
18
|
+
create_api_account_for('jim')
|
19
|
+
end
|
20
|
+
|
21
|
+
After do
|
22
|
+
stop_server
|
23
|
+
@show_web_server_output = false
|
24
|
+
end
|
data/lib/pairzone.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'pairzone/version'
|
2
|
+
require 'pairzone/authenticate'
|
3
|
+
require 'pairzone/shell'
|
4
|
+
require 'pairzone/logger'
|
5
|
+
|
6
|
+
require 'pairzone/api/base'
|
7
|
+
require 'pairzone/api/pairzone_lifecycle'
|
8
|
+
require 'pairzone/api/pairzone_connection'
|
9
|
+
require 'pairzone/api/pairzone'
|
10
|
+
require 'pairzone/api/user'
|
11
|
+
|
12
|
+
require 'pairzone/commands/info'
|
13
|
+
require 'pairzone/commands/start'
|
14
|
+
require 'pairzone/commands/join'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'party_resource'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Pairzone
|
5
|
+
module Api
|
6
|
+
class Base
|
7
|
+
include PartyResource
|
8
|
+
|
9
|
+
def initialize(data)
|
10
|
+
Logger.debug("Received DATA: #{data}")
|
11
|
+
populate_properties(data.values.first)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.connect_to(host, options)
|
15
|
+
params = {
|
16
|
+
base_uri: host,
|
17
|
+
headers: {
|
18
|
+
'Accept' => 'application/json',
|
19
|
+
'User-agent' => 'pairzone-gem/' + VERSION
|
20
|
+
}
|
21
|
+
}.merge(options)
|
22
|
+
Logger.debug("Connecting to API server with params: #{params.inspect}")
|
23
|
+
PartyResource::Connector.add(:pairzone, params)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Pairzone
|
2
|
+
module Api
|
3
|
+
class Pairzone < Base
|
4
|
+
include PairzoneConnection
|
5
|
+
extend PairzoneLifecycle
|
6
|
+
|
7
|
+
attr :identity
|
8
|
+
|
9
|
+
property :name
|
10
|
+
property :owner
|
11
|
+
property :collaborators
|
12
|
+
property :ip
|
13
|
+
property :project_name
|
14
|
+
property :status
|
15
|
+
|
16
|
+
connect :find_by_project_name, :get => '/pairzones/:name.json', :with => :name, :on => :class, :rescue => { 'ResourceNotFound' => nil }
|
17
|
+
|
18
|
+
connect :create, :post => '/pairzones', :with => :pairzone, :on => :class
|
19
|
+
|
20
|
+
def to_str
|
21
|
+
"<%= color('This Pairzone: #{name}', CYAN + BOLD) %>\nOwner: #{owner}\nCollaborators: #{collaborators.join(', ')}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Pairzone
|
2
|
+
module Api
|
3
|
+
module PairzoneConnection
|
4
|
+
def connect(identity)
|
5
|
+
Logger.info("Connecting to Pairzone...")
|
6
|
+
shell(identity).run(%{ssh -i #{identity} -t pairzone@#{ip} "/usr/local/bin/pairzone-tmux.sh"})
|
7
|
+
end
|
8
|
+
|
9
|
+
def push_code(identity)
|
10
|
+
Logger.debug("pushing local code to pairzone instance")
|
11
|
+
shell(identity).remote(ip, "git init #{project_name} &&
|
12
|
+
cd #{project_name} &&
|
13
|
+
git config receive.denyCurrentBranch ignore")
|
14
|
+
shell(identity).git("git push --mirror #{git_location}")
|
15
|
+
shell(identity).remote(ip, "cd #{project_name} && git reset --hard")
|
16
|
+
end
|
17
|
+
|
18
|
+
def fetch_code(identity)
|
19
|
+
shell(identity).git "git fetch #{git_location} master:pairzone"
|
20
|
+
Logger.info("Your git code has been placed in a local 'pairzone' branch. To merge this code into your HEAD, run this commmand:\n\ngit merge pairzone")
|
21
|
+
end
|
22
|
+
|
23
|
+
def shell(identity)
|
24
|
+
@shell ||= Shell.new(identity)
|
25
|
+
end
|
26
|
+
|
27
|
+
def git_location
|
28
|
+
"pairzone@#{ip}:#{project_name}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
|
2
|
+
module Pairzone
|
3
|
+
module Api
|
4
|
+
module PairzoneLifecycle
|
5
|
+
attr_accessor :start_wait_interval
|
6
|
+
DEFAULT_START_WAIT_INTERVAL = 5
|
7
|
+
|
8
|
+
def start(options)
|
9
|
+
Logger.info("Starting Pairzone for project '#{options[:project_name]}'...")
|
10
|
+
pairzone = create(:project_name => options[:project_name], :collaborators => options[:collaborators])
|
11
|
+
report_starting_status(pairzone)
|
12
|
+
|
13
|
+
wait_for(pairzone)
|
14
|
+
end
|
15
|
+
|
16
|
+
def report_starting_status(pairzone)
|
17
|
+
Logger.info("Pairzone '#{pairzone.name}' started.")
|
18
|
+
pairzone.collaborators.each do |collaborator|
|
19
|
+
Logger.info("Collaborator '#{collaborator}' added.")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def wait_for(pairzone)
|
24
|
+
while pairzone.status != 'started' do
|
25
|
+
Logger.info("Waiting for pairzone to boot...")
|
26
|
+
sleep start_wait_interval || DEFAULT_START_WAIT_INTERVAL
|
27
|
+
pairzone = find_by_project_name(pairzone.name)
|
28
|
+
end
|
29
|
+
Logger.info("Pairzone booted: ip address #{pairzone.ip}")
|
30
|
+
pairzone
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Pairzone
|
2
|
+
module Api
|
3
|
+
class User < Base
|
4
|
+
property :email
|
5
|
+
property :username
|
6
|
+
property :authentication_token
|
7
|
+
|
8
|
+
connect :current_user, :get => '/user'
|
9
|
+
|
10
|
+
def to_str
|
11
|
+
"Username: #{username}\n" +
|
12
|
+
"Email: #{email}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'highline'
|
3
|
+
|
4
|
+
module Pairzone
|
5
|
+
class Authenticate
|
6
|
+
def self.retrieve_key(config, server)
|
7
|
+
@api_key_location = "#{config}/authentication_token"
|
8
|
+
Logger.debug("retrieving pairzone key")
|
9
|
+
Logger.debug("checking for file #{@api_key_location}")
|
10
|
+
if (File.exist?(@api_key_location))
|
11
|
+
key = key_from_file
|
12
|
+
else
|
13
|
+
key = key_from_server(server)
|
14
|
+
end
|
15
|
+
Logger.debug("api key discovered '#{key}'")
|
16
|
+
key
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.key_from_file
|
20
|
+
File.read(@api_key_location).strip
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.key_from_server(server)
|
24
|
+
Logger.info "<%= color('Hello, welcome to Pairzone.', CYAN + BOLD) %>"
|
25
|
+
Logger.info "We need some information so we can tie this computer to your account."
|
26
|
+
user = nil
|
27
|
+
begin
|
28
|
+
email = Logger.ask("Pairzone email: ")
|
29
|
+
password = Logger.ask("Pairzone password: ") { |q| q.echo = "." }
|
30
|
+
|
31
|
+
Pairzone::Api::Base.connect_to(server, username: email, password: password, default: false)
|
32
|
+
Logger.debug("Retrieving key from server with supplied credentials")
|
33
|
+
user = Pairzone::Api::User.current_user
|
34
|
+
unless user
|
35
|
+
Logger.info "Cannot authenticate: please try again."
|
36
|
+
end
|
37
|
+
end while user.nil?
|
38
|
+
save_token(@api_key_location, user.authentication_token)
|
39
|
+
user.authentication_token
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.save_token(location, token)
|
43
|
+
FileUtils.mkdir_p(File.dirname(location))
|
44
|
+
Logger.debug("Saving API key to #{location}")
|
45
|
+
File.open(location, "w") do |f|
|
46
|
+
f.puts(token)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Pairzone
|
2
|
+
module Commands
|
3
|
+
class Info
|
4
|
+
def initialize(project_name)
|
5
|
+
@project_name = project_name
|
6
|
+
end
|
7
|
+
|
8
|
+
def execute
|
9
|
+
Logger.info("<%= color('Pairzone Account Information', CYAN + BOLD) %>")
|
10
|
+
@user = Pairzone::Api::User.current_user
|
11
|
+
Logger.info(@user)
|
12
|
+
Logger.info("")
|
13
|
+
Logger.debug("Finding information about local pairzone: #{local_pairzone_name}")
|
14
|
+
pairzone = Pairzone::Api::Pairzone.find_by_project_name(local_pairzone_name)
|
15
|
+
Logger.info(pairzone || "No pairzone found for this directory (create one with <%= color('pairzone create', CYAN) %>).")
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def local_pairzone_name
|
21
|
+
"#{@user.username}-#{@project_name}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module Pairzone
|
4
|
+
module Commands
|
5
|
+
class Join
|
6
|
+
def initialize(pairzone_name, identity)
|
7
|
+
@pairzone_name = pairzone_name
|
8
|
+
@identity = File.expand_path(identity)
|
9
|
+
end
|
10
|
+
|
11
|
+
def execute
|
12
|
+
pairzone = Pairzone::Api::Pairzone.find_by_project_name(@pairzone_name)
|
13
|
+
if (pairzone.nil?)
|
14
|
+
Logger.error("No pairzone exists with the name '#{@pairzone_name}'.")
|
15
|
+
else
|
16
|
+
pairzone.connect(@identity)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|