capistrano-calendar 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ .credentials.yml
4
+ pkg/*
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm ruby-1.8.7
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ gem 'json', '1.6.1'
6
+ gem 'gdata', '1.1.2'
7
+ gem 'daemons', '1.1.4'
8
+
9
+
10
+ gem 'rspec', '2.6.0'
@@ -0,0 +1,47 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ capistrano-calendar (0.0.1)
5
+ capistrano (>= 2.5.5)
6
+ gdata (>= 1.1.0)
7
+ json
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ capistrano (2.9.0)
13
+ highline
14
+ net-scp (>= 1.0.0)
15
+ net-sftp (>= 2.0.0)
16
+ net-ssh (>= 2.0.14)
17
+ net-ssh-gateway (>= 1.1.0)
18
+ daemons (1.1.4)
19
+ diff-lcs (1.1.2)
20
+ gdata (1.1.2)
21
+ highline (1.6.2)
22
+ json (1.6.1)
23
+ net-scp (1.0.4)
24
+ net-ssh (>= 1.99.1)
25
+ net-sftp (2.0.5)
26
+ net-ssh (>= 2.0.9)
27
+ net-ssh (2.2.1)
28
+ net-ssh-gateway (1.1.0)
29
+ net-ssh (>= 1.99.1)
30
+ rspec (2.6.0)
31
+ rspec-core (~> 2.6.0)
32
+ rspec-expectations (~> 2.6.0)
33
+ rspec-mocks (~> 2.6.0)
34
+ rspec-core (2.6.4)
35
+ rspec-expectations (2.6.0)
36
+ diff-lcs (~> 1.1.2)
37
+ rspec-mocks (2.6.0)
38
+
39
+ PLATFORMS
40
+ ruby
41
+
42
+ DEPENDENCIES
43
+ capistrano-calendar!
44
+ daemons (= 1.1.4)
45
+ gdata (= 1.1.2)
46
+ json (= 1.6.1)
47
+ rspec (= 2.6.0)
@@ -0,0 +1,91 @@
1
+ # Capistrano Calendar
2
+
3
+ ## Introduction
4
+
5
+ capistrano-calendar is extension for capistrano that allows your create different deployment notification in calendar service. Currently supported services:
6
+
7
+ * google calendar
8
+
9
+ ## Installation
10
+
11
+ gem install capistrano-calendar
12
+
13
+ Add to your Capfile
14
+
15
+ require 'capistrano/calendar/recipes'
16
+
17
+ ## How it works
18
+
19
+ This gem provides:
20
+
21
+ * capistrano recipe *calendar:create_event*
22
+ * ruby binary script *capistrano-calendar*
23
+
24
+ Capistrano recipe should be used in some :after hooks (e.g. after deploy). Recipe reads calendar configurations and run capistrano-calendar binary on some host specified in *capistrano_runner* option. So you **need to install** *capistrano-calendar* gem also on that calendar host. Also please ensure that you properly configured calendar_runner otherwise you may have **duplicated events** in calender.
25
+
26
+ ## Calendar configuration
27
+
28
+ * *:calendar_service* (:google) - calendar service to use e.g. ':google'
29
+ * **:calendar_username** (nil) - calendar service username e.g 'vasya.pupkin@gmail.com'
30
+ * **:calendar_password** (nil) - calendar service password e.g 'qwery123456'
31
+ * *:calendar_name* (default) - calendar name to use for events
32
+ * *:calendar_summary* (nil) - calendar summary for new calendar
33
+ * *:calendar_location* (nil) - calendar location for new calendar
34
+ * *:calendar_timezone* ('UTC') - calendar timezone for new calendar
35
+ * *:calendar_color* ('#A32929') - calendar color for new calendar
36
+ * **:calendar_event_name** (nil) - calendar event name
37
+ * *:calendar_event_summary* (nil) - calendar event summary
38
+ * *:calendar_event_location* (nil) - calendar event location
39
+ * *:calendar_event_time* (Time.now) - calendar event time
40
+ * *:calendar_event_status* ('confirmed') - calendar event status
41
+
42
+ Bold means required options. Value in brackets means default value.
43
+
44
+ ## Calendar runner configuration
45
+
46
+ Calendar event creation will be executed by default on the one of application servers (specified in :app roles)
47
+ You can change this behavior via *calendar_runner* option. Examples:
48
+
49
+ set(:calendar_runner, { :roles => :calendar_notifier, :once => true )
50
+ # or
51
+ set(:calendar_runner, { :hosts => 'notification.example.com' })
52
+
53
+ Be sure to pass `:once => true` option if you use *:roles* !
54
+
55
+ ## Configuration example
56
+
57
+ set :calendar_service, :google
58
+ set :calendar_username, 'vasya.pupkin@my.company.com'
59
+ set :calendar_password, '123456'
60
+
61
+ set :calendar_name { stage }
62
+ set :calendar_summary { "" }
63
+ set :calendar_timezone, 'UTC'
64
+ set :calendar_color, { stage == 'production' ? '#ff000' : '#00ff00' }
65
+
66
+ set :calendar_event_summary { "Bla" }
67
+ set :calendar_event_time { Time.now }
68
+
69
+ after 'deploy' do
70
+ set :calendar_event_title "[Deployed] #{application} #{branch}: #{real_revision}"
71
+ top.calendar.create_event
72
+ end
73
+
74
+ after 'deploy:rollback' do
75
+ set :calendar_event_title "[Rollback] #{application} #{branch}: #{real_revision}"
76
+ top.calendar.create_event
77
+ end
78
+
79
+ #
80
+ # Extra configurations if you are using capistrano-patch:
81
+ #
82
+ after 'patch:apply' do
83
+ set :calendar_event_title "[Pathed] #{application} #{branch}: #{patch_strategy.revision_to}"
84
+ calendar_client.create_event
85
+ end
86
+
87
+ after 'patch:revert' do
88
+ set :calendar_event_title "[Patch rollback] #{application} #{branch}: #{patch_strategy.revision_from}"
89
+ top.calendar.create_event
90
+ end
91
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'capistrano/calendar'
4
+
5
+ Capistrano::Calendar::Runner.new(ARGV).run!
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require "capistrano/calendar/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "capistrano-calendar"
8
+ s.version = Capistrano::Calendar::VERSION
9
+ s.authors = ["Andriy Yanko"]
10
+ s.email = ["andriy.yanko@gmail.com"]
11
+ s.homepage = "https://github.com/railsware/capistrano-calendar/"
12
+ s.summary = %q{Deployment event creation on (google) calendar service}
13
+
14
+ s.rubyforge_project = "capistrano-calendar"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_runtime_dependency "capistrano", ">=2.5.5"
22
+ s.add_runtime_dependency "gdata", ">=1.1.0"
23
+ s.add_runtime_dependency "json"
24
+ end
@@ -0,0 +1,7 @@
1
+ module Capistrano
2
+ module Calendar
3
+ autoload :Client, 'capistrano/calendar/client'
4
+ autoload :Configuration, 'capistrano/calendar/configuration'
5
+ autoload :Runner, 'capistrano/calendar/runner'
6
+ end
7
+ end
@@ -0,0 +1,20 @@
1
+ require 'capistrano/errors'
2
+
3
+ module Capistrano
4
+ module Calendar
5
+ module Client
6
+ def self.new(config)
7
+ name = config[:calendar_service] || :google
8
+
9
+ require "capistrano/calendar/client/#{name}"
10
+
11
+ client_const = name.to_s.capitalize.gsub(/_(.)/) { $1.upcase }
12
+
13
+ const_get(client_const).new(config)
14
+
15
+ rescue LoadError
16
+ raise Capistrano::Error, "could not find any client named '#{name}'"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,31 @@
1
+ module Capistrano
2
+ module Calendar
3
+ module Client
4
+ class Base
5
+ def initialize(config)
6
+ @configuration = config
7
+ end
8
+
9
+ attr_reader :configuration
10
+
11
+ def calendar_username
12
+ configuration.fetch(:calendar_username)
13
+ end
14
+
15
+ def calendar_password
16
+ configuration.fetch(:calendar_password)
17
+ end
18
+
19
+ def authenticate
20
+ raise NotImplementedError, "`authenticate' is not implemented by #{self.class.name}"
21
+ end
22
+
23
+ def create_event
24
+ raise NotImplementedError, "`create_event' is not implemented by #{self.class.name}"
25
+ end
26
+
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,105 @@
1
+ require 'capistrano/calendar/client/base'
2
+
3
+ require 'gdata'
4
+ require 'json'
5
+ require 'time'
6
+
7
+ module Capistrano
8
+ module Calendar
9
+ module Client
10
+ class Google < Base
11
+
12
+ #
13
+ # http://code.google.com/apis/calendar/data/2.0/developers_guide_protocol.html
14
+ #
15
+
16
+ OWN_CALENDARS_URL = "https://www.google.com/calendar/feeds/default/owncalendars/full"
17
+ CALENDAR_EVENTS_URL = "https://www.google.com/calendar/feeds/default/private/full"
18
+
19
+ def authenticate
20
+ client.clientlogin(calendar_username, calendar_password)
21
+ end
22
+
23
+ def create_event
24
+ response = client.post(events_url, json_event_entity)
25
+ JSON.parse(response.body)['data']
26
+ end
27
+
28
+ def events_url
29
+ if configuration[:calendar_name]
30
+ calendar = find_or_create_calendar(configuration[:calendar_name])
31
+ calendar['eventFeedLink']
32
+ else
33
+ CALENDAR_EVENTS_URL
34
+ end
35
+ end
36
+
37
+ def find_or_create_calendar(calendar_name)
38
+ find_calendar(calendar_name) || create_calendar(calendar_name)
39
+ end
40
+
41
+ def find_calendar(calendar_name)
42
+ response = client.get(OWN_CALENDARS_URL + '?alt=jsonc')
43
+ JSON.parse(response.body)['data']['items'].find { |item|
44
+ item['title'] == calendar_name
45
+ }
46
+ end
47
+
48
+ def create_calendar(calendar_name)
49
+ response = client.post(OWN_CALENDARS_URL, json_calendar_entity)
50
+ JSON.parse(response.body)['data']
51
+ end
52
+
53
+ def delete_calendar(calendar)
54
+ calendar.is_a?(Hash) or calendar = find_calendar(calendar)
55
+ calendar or raise Capistrano::Error, "Calendar #{calendar.inspect} not found"
56
+ client.delete(calendar['selfLink'])
57
+ end
58
+
59
+ protected
60
+
61
+ def client
62
+ @client ||= GData::Client::Calendar.new({
63
+ :headers => { 'Content-Type' => 'application/json' },
64
+ :source => 'capistrano-calendar'
65
+ })
66
+ end
67
+
68
+ def json_calendar_entity
69
+ data = {
70
+ 'title' => configuration.fetch(:calendar_name),
71
+ 'timeZone' => configuration.fetch(:calendar_timezone, 'UTC'),
72
+ 'color' => configuration.fetch(:calendar_color, '#A32929'),
73
+ 'hidden' => false
74
+ }
75
+
76
+ value = configuration[:calendar_summary] and data['details'] = value
77
+ value = configuration[:calendar_location] and data['location'] = value
78
+
79
+ { 'data' => data }.to_json
80
+ end
81
+
82
+ def json_event_entity
83
+ event_time = configuration.fetch(:calendar_event_time, Time.now).utc.xmlschema
84
+
85
+ data = {
86
+ 'title' => configuration.fetch(:calendar_event_name),
87
+ 'status' => configuration.fetch(:calendar_event_status, 'confirmed'),
88
+ 'when' => [
89
+ {
90
+ 'start' => event_time,
91
+ 'stop' => event_time
92
+ }
93
+ ]
94
+ }
95
+
96
+ value = configuration[:calendar_event_summary] and data['details'] = value
97
+ value = configuration[:calendar_event_location] and data['location'] = value
98
+
99
+ { 'data' => data }.to_json
100
+ end
101
+
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,41 @@
1
+ require 'yaml'
2
+ require 'base64'
3
+
4
+ module Capistrano
5
+ module Calendar
6
+ class Configuration
7
+
8
+ def self.collect(hash)
9
+ [
10
+ :calendar_service,
11
+ :calendar_username,
12
+ :calendar_password,
13
+
14
+ :calendar_name,
15
+ :calendar_summary,
16
+ :calendar_location,
17
+ :calendar_timezone,
18
+ :calendar_color,
19
+
20
+ :calendar_event_name,
21
+ :calendar_event_summary,
22
+ :calendar_event_location,
23
+ :calendar_event_time,
24
+ :calendar_event_status
25
+ ].inject({}) { |result, key|
26
+ result[key] = hash[key] if hash.exists?(key)
27
+ result
28
+ }
29
+ end
30
+
31
+ def self.encode(hash)
32
+ Base64.encode64(hash.to_yaml).gsub("\n", '')
33
+ end
34
+
35
+ def self.decode(string)
36
+ YAML.load(Base64.decode64(string))
37
+ end
38
+
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,22 @@
1
+ require 'capistrano/calendar'
2
+
3
+ Capistrano::Configuration.instance.load do
4
+
5
+ set(:calendar_runner) do
6
+ {
7
+ :roles => :app,
8
+ :once => true
9
+ }
10
+ end
11
+
12
+ namespace :calendar do
13
+ desc "Create calendar event"
14
+ task :create_event do
15
+ configuration = Capistrano::Calendar::Configuration.collect(self)
16
+ string = Capistrano::Calendar::Configuration.encode(configuration)
17
+
18
+ run("capistrano-calendar create_event #{string}", calendar_runner)
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,88 @@
1
+ require 'optparse'
2
+
3
+ module Capistrano
4
+ module Calendar
5
+ class Runner
6
+ def self.run(*args)
7
+ new(*args).run!
8
+ end
9
+
10
+ def initialize(argv)
11
+ @argv = argv
12
+ end
13
+
14
+ attr_reader :client
15
+
16
+ def run!
17
+ parser = OptionParser.new do |o|
18
+ o.banner = "Usage: capistrano-calendar [options] COMMAND [CONFIGURATION_DATA]"
19
+ o.separator ""
20
+ o.separator "Commands:"
21
+ o.separator ""
22
+ o.separator " create_event - create calendar event"
23
+ o.separator ""
24
+ o.separator "CONFIGURATION_DATA is base64 encoded yaml data"
25
+ o.separator ""
26
+ o.separator "Common options:"
27
+ o.on_tail("-h", "--help", "Show this message") { puts o; exit }
28
+ o.on_tail('-v', '--version', "Show version") { puts Capistrano::Calendar::VERSION; exit }
29
+ end
30
+
31
+ parser.parse!(@argv)
32
+
33
+ @command = @argv.shift
34
+ @configuration = @argv.shift
35
+
36
+ case @command
37
+ when 'create_event'
38
+ @configuration or abort(parser.help)
39
+ @configuration = Capistrano::Calendar::Configuration.decode(@configuration)
40
+ @configuration.is_a?(Hash) or abort("Bad configuration given")
41
+
42
+ @client = Capistrano::Calendar::Client.new(@configuration)
43
+
44
+ daemonize { create_event }
45
+ else
46
+ abort parser.help
47
+ end
48
+
49
+ end
50
+
51
+ protected
52
+
53
+ def create_event
54
+ client.authenticate
55
+ client.create_event
56
+ end
57
+
58
+ def daemonize
59
+ Process.fork do
60
+ # Detach the child process from the parent's session.
61
+ Process.setsid
62
+
63
+ # Re-fork. This is recommended for System V-based
64
+ # system as it guarantees that the daemon is not a
65
+ # session leader, which prevents it from aquiring
66
+ # a controlling terminal under the System V rules.
67
+ exit if fork
68
+
69
+ # Rename the process
70
+ $0 = "capistrano-calendar"
71
+
72
+ # Flush all buffers
73
+ $stdout.sync = $stderr.sync = true
74
+
75
+ # Set all standard files to `/dev/null/` in order
76
+ # to be sure that any output from the daemon will
77
+ # not appear in any terminals.
78
+ $stdin.reopen("/dev/null")
79
+ $stdout.reopen("/tmp/capistrano-calendar.stdout")
80
+ $stderr.reopen("/tmp/capistrano-calendar.stderr")
81
+
82
+ yield
83
+ end
84
+ end
85
+
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,5 @@
1
+ module Capistrano
2
+ module Calendar
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+
3
+ describe Capistrano::Calendar::Client, "#create_event for google calendar" do
4
+
5
+ let(:configuration) do
6
+ {
7
+ :calendar_service => :google,
8
+ :calendar_username => Helper.credentials[:google][:username],
9
+ :calendar_password => Helper.credentials[:google][:password],
10
+ :calendar_name => "Capistrano Calendar",
11
+ :calendar_event_name => 'Test Deploy!'
12
+ }
13
+ end
14
+
15
+ let(:client) {
16
+ client = Capistrano::Calendar::Client.new(configuration)
17
+ client.authenticate
18
+ client
19
+ }
20
+
21
+ before(:each) do
22
+ sleep(1)
23
+ configuration[:calendar_name] << " #{Time.now.to_f}"
24
+ end
25
+
26
+ it "should create calendar and event" do
27
+ event = client.create_event
28
+
29
+ event.should be_kind_of(Hash)
30
+ event['title'].should == configuration[:calendar_event_name]
31
+
32
+ calendar = client.find_calendar(configuration[:calendar_name])
33
+ calendar.should be_kind_of(Hash)
34
+ calendar['title'].should == configuration[:calendar_name]
35
+ calendar['timeZone'].should == 'UTC'
36
+ end
37
+
38
+ context "when calendar exists" do
39
+ before(:each) do
40
+ @calendar = client.create_calendar(configuration[:calendar_name])
41
+ end
42
+
43
+ it "should create event and does NOT create another calendar" do
44
+ event = client.create_event
45
+
46
+ event.should be_kind_of(Hash)
47
+ event['title'].should == configuration[:calendar_event_name]
48
+
49
+ calendar = client.find_calendar(configuration[:calendar_name])
50
+ calendar.should be_kind_of(Hash)
51
+ calendar['id'].should == @calendar['id']
52
+ end
53
+ end
54
+
55
+ context "when calendar_name is nil" do
56
+ before(:each) do
57
+ configuration.delete(:calendar_name)
58
+ end
59
+
60
+ it "should create event in default calendar" do
61
+ event = client.create_event
62
+
63
+ event.should be_kind_of(Hash)
64
+ event['title'].should == configuration[:calendar_event_name]
65
+ event['selfLink'].should include(Capistrano::Calendar::Client::Google::CALENDAR_EVENTS_URL)
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,26 @@
1
+ require 'capistrano'
2
+ require 'capistrano/calendar/client'
3
+
4
+ require 'yaml'
5
+
6
+ module Helper
7
+ def self.load_credentials!
8
+ @credentials = YAML.load_file('.credentials.yml')
9
+ rescue Errno::ENOENT => e
10
+ puts "Put your credentials into '.credentials.yml'. Example:"
11
+ puts({
12
+ :google => {
13
+ :username => 'vasya.pukin@gmail.com',
14
+ :password => '123456'
15
+ }
16
+ }.to_yaml)
17
+
18
+ exit(1)
19
+ end
20
+
21
+ def self.credentials
22
+ @credentials
23
+ end
24
+ end
25
+
26
+ Helper.load_credentials!
metadata ADDED
@@ -0,0 +1,129 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: capistrano-calendar
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Andriy Yanko
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-10-26 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: capistrano
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ hash: 17
29
+ segments:
30
+ - 2
31
+ - 5
32
+ - 5
33
+ version: 2.5.5
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: gdata
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 19
45
+ segments:
46
+ - 1
47
+ - 1
48
+ - 0
49
+ version: 1.1.0
50
+ type: :runtime
51
+ version_requirements: *id002
52
+ - !ruby/object:Gem::Dependency
53
+ name: json
54
+ prerelease: false
55
+ requirement: &id003 !ruby/object:Gem::Requirement
56
+ none: false
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ hash: 3
61
+ segments:
62
+ - 0
63
+ version: "0"
64
+ type: :runtime
65
+ version_requirements: *id003
66
+ description:
67
+ email:
68
+ - andriy.yanko@gmail.com
69
+ executables:
70
+ - capistrano-calendar
71
+ extensions: []
72
+
73
+ extra_rdoc_files: []
74
+
75
+ files:
76
+ - .gitignore
77
+ - .rvmrc
78
+ - Gemfile
79
+ - Gemfile.lock
80
+ - README.md
81
+ - Rakefile
82
+ - bin/capistrano-calendar
83
+ - capistrano-calendar.gemspec
84
+ - lib/capistrano/calendar.rb
85
+ - lib/capistrano/calendar/client.rb
86
+ - lib/capistrano/calendar/client/base.rb
87
+ - lib/capistrano/calendar/client/google.rb
88
+ - lib/capistrano/calendar/configuration.rb
89
+ - lib/capistrano/calendar/recipes.rb
90
+ - lib/capistrano/calendar/runner.rb
91
+ - lib/capistrano/calendar/version.rb
92
+ - spec/google_calendar_spec.rb
93
+ - spec/spec_helper.rb
94
+ homepage: https://github.com/railsware/capistrano-calendar/
95
+ licenses: []
96
+
97
+ post_install_message:
98
+ rdoc_options: []
99
+
100
+ require_paths:
101
+ - lib
102
+ required_ruby_version: !ruby/object:Gem::Requirement
103
+ none: false
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ hash: 3
108
+ segments:
109
+ - 0
110
+ version: "0"
111
+ required_rubygems_version: !ruby/object:Gem::Requirement
112
+ none: false
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ hash: 3
117
+ segments:
118
+ - 0
119
+ version: "0"
120
+ requirements: []
121
+
122
+ rubyforge_project: capistrano-calendar
123
+ rubygems_version: 1.8.6
124
+ signing_key:
125
+ specification_version: 3
126
+ summary: Deployment event creation on (google) calendar service
127
+ test_files:
128
+ - spec/google_calendar_spec.rb
129
+ - spec/spec_helper.rb