Commit 11616843 authored by Fabio Pelosin's avatar Fabio Pelosin

Merge pull request #219 from CocoaPods/pod-push

Pod push, pod spec lint, and minor changes
parents f9e77af9 7f7aa877
source "http://rubygems.org" source "http://rubygems.org"
gem "open4"
gem "colored" gem "colored"
gem "escape" gem "escape"
gem "json" gem "json"
......
...@@ -38,7 +38,6 @@ GEM ...@@ -38,7 +38,6 @@ GEM
faraday_middleware (~> 0.8) faraday_middleware (~> 0.8)
hashie (~> 1.2) hashie (~> 1.2)
multi_json (~> 1.0) multi_json (~> 1.0)
open4 (1.3.0)
pry (0.9.8.4) pry (0.9.8.4)
coderay (~> 1.0.5) coderay (~> 1.0.5)
method_source (~> 0.7.1) method_source (~> 0.7.1)
...@@ -64,7 +63,6 @@ DEPENDENCIES ...@@ -64,7 +63,6 @@ DEPENDENCIES
kicker kicker
mocha-on-bacon mocha-on-bacon
octokit octokit
open4
pry pry
rake rake
rb-fsevent rb-fsevent
......
...@@ -29,7 +29,6 @@ Gem::Specification.new do |s| ...@@ -29,7 +29,6 @@ Gem::Specification.new do |s|
"you are upgrading, first run: $ pod setup" "you are upgrading, first run: $ pod setup"
s.add_runtime_dependency 'xcodeproj', '~> 0.1.0' s.add_runtime_dependency 'xcodeproj', '~> 0.1.0'
s.add_runtime_dependency 'popen4', '~> 0.1.2'
s.add_runtime_dependency 'colored', '~> 1.2' s.add_runtime_dependency 'colored', '~> 1.2'
s.add_runtime_dependency 'escape', '~> 0.0.4' s.add_runtime_dependency 'escape', '~> 0.0.4'
s.add_development_dependency 'bacon', '~> 1.1' s.add_development_dependency 'bacon', '~> 1.1'
......
...@@ -39,3 +39,7 @@ class Pathname ...@@ -39,3 +39,7 @@ class Pathname
end end
end end
if ENV['COCOA_PODS_ENV'] == 'development'
require 'pry'
require 'awesome_print'
end
...@@ -6,6 +6,7 @@ module Pod ...@@ -6,6 +6,7 @@ module Pod
autoload :Install, 'cocoapods/command/install' autoload :Install, 'cocoapods/command/install'
autoload :List, 'cocoapods/command/list' autoload :List, 'cocoapods/command/list'
autoload :Presenter, 'cocoapods/command/presenter' autoload :Presenter, 'cocoapods/command/presenter'
autoload :Push, 'cocoapods/command/push'
autoload :Repo, 'cocoapods/command/repo' autoload :Repo, 'cocoapods/command/repo'
autoload :Search, 'cocoapods/command/search' autoload :Search, 'cocoapods/command/search'
autoload :Setup, 'cocoapods/command/setup' autoload :Setup, 'cocoapods/command/setup'
...@@ -18,12 +19,13 @@ module Pod ...@@ -18,12 +19,13 @@ module Pod
def message def message
[ [
@command_class.banner,
'', '',
'Options', @command_class.banner.gsub(/\$ pod (.*)/, '$ pod \1'.green),
'-------',
'', '',
options 'Options:',
'',
options,
"\n",
].join("\n") ].join("\n")
end end
...@@ -45,14 +47,10 @@ module Pod ...@@ -45,14 +47,10 @@ module Pod
end end
def self.banner def self.banner
"To see help for the available commands run:\n" \ commands = ['install', 'list', 'push', 'repo', 'search', 'setup', 'spec'].sort
"\n" \ banner = "\nTo see help for the available commands run:\n\n"
" * $ pod setup --help\n" \ commands.each {|cmd| banner << " * $ pod #{cmd.green} --help\n"}
" * $ pod search --help\n" \ banner
" * $ pod list --help\n" \
" * $ pod install --help\n" \
" * $ pod repo --help\n" \
" * $ pod spec --help"
end end
def self.options def self.options
...@@ -97,6 +95,7 @@ module Pod ...@@ -97,6 +95,7 @@ module Pod
when 'list' then List when 'list' then List
when 'setup' then Setup when 'setup' then Setup
when 'spec' then Spec when 'spec' then Spec
when 'push' then Push
end end
if show_help || command_class.nil? if show_help || command_class.nil?
......
...@@ -2,7 +2,7 @@ module Pod ...@@ -2,7 +2,7 @@ module Pod
class Command class Command
class Presenter class Presenter
def self.options def self.options
" --stats Show additional stats (like GitHub watchers and forks)\n" [["--stats", "Show additional stats (like GitHub watchers and forks)"]]
end end
autoload :CocoaPod, 'cocoapods/command/presenter/cocoa_pod' autoload :CocoaPod, 'cocoapods/command/presenter/cocoa_pod'
...@@ -43,18 +43,15 @@ module Pod ...@@ -43,18 +43,15 @@ module Pod
txt.strip.gsub(/(.{1,#{col}})( +|$)\n?|(.{#{col}})/, indent + "\\1\\3\n") txt.strip.gsub(/(.{1,#{col}})( +|$)\n?|(.{#{col}})/, indent + "\\1\\3\n")
end end
def detail(title, value, preferred_indentation = 8) def detail(title, value)
# 8 is the length of Homepage
return '' if !value return '' if !value
number_of_spaces = ((preferred_indentation - title.length) > 0) ? (preferred_indentation - title.length) : 0
spaces = ' ' * number_of_spaces
''.tap do |t| ''.tap do |t|
t << " - #{title}:" t << " - #{title}:".ljust(16)
if value.class == Array if value.class == Array
separator = "\n - " separator = "\n - "
t << separator + value.join(separator) t << separator << value.join(separator)
else else
t << " #{spaces + value.to_s}\n" t << value.to_s << "\n"
end end
end end
end end
......
require 'fileutils'
module Pod
class Command
class Push < Command
def self.banner
%{Pushing new specifications to a spec-repo:
$ pod push [REPO]
Validates `*.podspec' in the current working dir, updates
the local copy of the repository named REPO, adds specifications
to REPO, and finally it pushes REPO to its remote.}
end
def self.options
[["--allow-warnings", "Allows to push if warnings are not evitable"]].concat(super)
end
extend Executable
executable :git
def initialize(argv)
@allow_warnings = argv.option('--allow-warnings')
@repo = argv.shift_argument
super unless argv.empty? && @repo
end
def run
validate_podspec_files
check_repo_status
update_repo
add_specs_to_repo
push_repo
end
private
def update_repo
puts "Updating the `#{@repo}' repo\n".yellow unless config.silent
# show the output of git even if not verbose
Dir.chdir(repo_dir) { puts `git pull 2>&1` }
end
def push_repo
puts "\nPushing the `#{@repo}' repo\n".yellow unless config.silent
Dir.chdir(repo_dir) { puts `git push 2>&1` }
end
def repo_dir
dir = config.repos_dir + @repo
raise Informative, "[!] `#{@repo}' repo not found".red unless dir.exist?
dir
end
def check_repo_status
# TODO: add specs for staged and unstaged files (tested manually)
clean = Dir.chdir(repo_dir) { `git status --porcelain 2>&1` } == ''
raise Informative, "[!] `#{@repo}' repo not clean".red unless clean
end
def podspec_files
files = Pathname.glob("*.podspec")
raise Informative, "[!] Couldn't find .podspec file in current directory".red if files.empty?
files
end
def validate_podspec_files
puts "\nValidating specs".yellow unless config.silent
lint_argv = ["lint"]
lint_argv << "--only-errors" if @allow_warnings
lint_argv << "--silent" if config.silent
all_valid = Spec.new(ARGV.new(lint_argv)).run
end
def add_specs_to_repo
puts "\nAdding the specs to the #{@repo} repo\n".yellow unless config.silent
podspec_files.each do |spec_file|
spec = Pod::Specification.from_file(spec_file)
output_path = File.join(repo_dir, spec.name, spec.version.to_s)
if Pathname.new(output_path).exist?
message = "[Fix] #{spec}"
elsif Pathname.new(File.join(repo_dir, spec.name)).exist?
message = "[Update] #{spec}"
else
message = "[Add] #{spec}"
end
puts " - #{message}" unless config.silent
FileUtils.mkdir_p(output_path)
FileUtils.cp(Pathname.new(spec.name+'.podspec'), output_path)
Dir.chdir(repo_dir) do
git("add #{spec.name}")
git("commit -m '#{message}'")
end
end
end
end
end
end
This diff is collapsed.
...@@ -53,16 +53,12 @@ module Pod ...@@ -53,16 +53,12 @@ module Pod
end end
def ios? def ios?
require 'colored' # TODO: deprecate in 0.7
caller.find { |line| line =~ /^(.+.podspec):\d*/ }
puts "[!] The use of `config.ios?` is deprecated and will be removed in version 0.7.#{" Called from: #{$1}" if $1}".red
podfile.target_definitions[:default].platform == :ios if podfile podfile.target_definitions[:default].platform == :ios if podfile
end end
def osx? def osx?
require 'colored' # TODO: deprecate in 0.7
caller.find { |line| line =~ /^(.+.podspec):\d*/ }
puts "[!] The use of `config.osx?` is deprecated and will be removed in version 0.7.#{" Called from: #{$1}" if $1}".red
podfile.target_definitions[:default].platform == :osx if podfile podfile.target_definitions[:default].platform == :osx if podfile
end end
......
...@@ -64,7 +64,8 @@ module Pod ...@@ -64,7 +64,8 @@ module Pod
# Returns a path, which is relative to the project_root, relative to the # Returns a path, which is relative to the project_root, relative to the
# `$(SRCROOT)` of the user's project. # `$(SRCROOT)` of the user's project.
def relative_to_srcroot(path) def relative_to_srcroot(path)
(config.project_root + path).relative_path_from(xcodeproj.dirname) raise Informative, "[!] Unable to find an Xcode project to integrate".red unless xcodeproj || !config.integrate_targets
xcodeproj ? (config.project_root + path).relative_path_from(xcodeproj.dirname) : path
end end
def relative_pods_root def relative_pods_root
......
...@@ -436,7 +436,7 @@ module Pod ...@@ -436,7 +436,7 @@ module Pod
end end
# Override the getters to always return the value of the top level parent spec. # Override the getters to always return the value of the top level parent spec.
[:version, :summary, :platform, :license, :authors, :requires_arc, :compiler_flags, :documentation].each do |attr| [:version, :summary, :platform, :license, :authors, :requires_arc, :compiler_flags, :documentation, :homepage].each do |attr|
define_method(attr) { top_level_parent.send(attr) } define_method(attr) { top_level_parent.send(attr) }
end end
......
require File.expand_path('../../../spec_helper', __FILE__)
describe Pod::Command::Push do
extend SpecHelper::Command
extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory
it "complains for wrong parameters" do
lambda { run_command('push') }.should.raise Pod::Command::Help
lambda { run_command('push', '--allow-warnings') }.should.raise Pod::Command::Help
lambda { run_command('push', '--wrong-option') }.should.raise Pod::Command::Help
end
it "complains if it can't find the repo" do
repo1 = add_repo('repo1', fixture('spec-repos/master'))
Dir.chdir(fixture('banana-lib')) do
lambda { run_command('push', 'repo2') }.should.raise Pod::Informative
end
end
it "complains if it can't find a spec" do
repo1 = add_repo('repo1', fixture('spec-repos/master'))
lambda { run_command('push', 'repo1') }.should.raise Pod::Informative
end
it "it raises if the pod is not validated" do
repo1 = add_repo('repo1', fixture('spec-repos/master'))
git('repo1', 'checkout master') # checkout master, because the fixture is a submodule
repo2 = add_repo('repo2', repo1.dir)
git_config('repo2', 'remote.origin.url').should == (tmp_repos_path + 'repo1').to_s
Dir.chdir(fixture('banana-lib')) do
lambda { command('push', 'repo2', '--silent').run }.should.raise Pod::Informative
end
# (repo1.dir + 'BananaLib/1.0/BananaLib.podspec').read.should.include 'Added!'
end
before do
# prepare the repos
@upstream = add_repo('upstream', fixture('spec-repos/master'))
git('upstream', 'checkout -b master') # checkout master, because the fixture is a submodule
@local_repo = add_repo('local_repo', @upstream.dir)
git_config('local_repo', 'remote.origin.url').should == (tmp_repos_path + 'upstream').to_s
git('upstream', 'checkout -b no-master') # checkout no-master, to allow push in a non-bare repository
# prepare the spec
spec_fix = (fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec').read
spec_add = spec_fix.gsub(/https:\/\/github\.com\/johnezang\/JSONKit\.git/, fixture('integration/JSONKit').to_s)
spec_add.gsub!(/'JSONKit'/, "'PushTest'")
File.open(temporary_directory + 'JSONKit.podspec', 'w') {|f| f.write(spec_fix) }
File.open(temporary_directory + 'PushTest.podspec', 'w') {|f| f.write(spec_add) }
end
it "refuses to push if the repo is not clean" do
File.open(@local_repo.dir + 'README', 'w') {|f| f.write('Added!') }
(@local_repo.dir + 'README').read.should.include 'Added!'
cmd = command('push', 'local_repo')
cmd.expects(:validate_podspec_files).returns(true)
Dir.chdir(temporary_directory) { lambda { cmd.run }.should.raise Pod::Informative }
git('upstream', 'checkout master') # checkout master, because the fixture is a submodule
(@upstream.dir + 'PushTest/1.4/PushTest.podspec').should.not.exist?
end
it "sucessfully pushes a spec" do
cmd = command('push', 'local_repo')
cmd.expects(:validate_podspec_files).returns(true)
Dir.chdir(temporary_directory) { cmd.run }
cmd.output.should.include('[Add] PushTest (1.4)')
cmd.output.should.include('[Fix] JSONKit (1.4)')
git('upstream', 'checkout master') # checkout master, because the fixture is a submodule
(@upstream.dir + 'PushTest/1.4/PushTest.podspec').read.should.include('PushTest')
end
end
...@@ -3,6 +3,7 @@ require File.expand_path('../../../spec_helper', __FILE__) ...@@ -3,6 +3,7 @@ require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Search" do describe "Pod::Command::Search" do
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::Git extend SpecHelper::Git
extend SpecHelper::TemporaryDirectory
before do before do
config.repos_dir = fixture('spec-repos') config.repos_dir = fixture('spec-repos')
...@@ -19,6 +20,7 @@ describe "Pod::Command::Search" do ...@@ -19,6 +20,7 @@ describe "Pod::Command::Search" do
end end
it "complains for wrong parameters" do it "complains for wrong parameters" do
lambda { run_command('search') }.should.raise Pod::Command::Help
lambda { run_command('search', 'too', 'many') }.should.raise Pod::Command::Help lambda { run_command('search', 'too', 'many') }.should.raise Pod::Command::Help
lambda { run_command('search', 'too', '--wrong') }.should.raise Pod::Command::Help lambda { run_command('search', 'too', '--wrong') }.should.raise Pod::Command::Help
lambda { run_command('search', '--wrong') }.should.raise Pod::Command::Help lambda { run_command('search', '--wrong') }.should.raise Pod::Command::Help
......
require File.expand_path('../../../spec_helper', __FILE__) require File.expand_path('../../../spec_helper', __FILE__)
describe "Pod::Command::Spec" do describe Pod::Command::Spec do
extend SpecHelper::Command extend SpecHelper::Command
extend SpecHelper::Github
extend SpecHelper::TemporaryDirectory
it "runs with correct parameters" do
lambda{ run_command('spec', 'create', 'Bananas') }.should.not.raise
expect_github_repo_request
expect_github_user_request
expect_github_tags_request
lambda{ run_command('spec', 'create', 'https://github.com/lukeredpath/libPusher.git') }.should.not.raise
end
it "complains for wrong parameters" do it "complains for wrong parameters" do
lambda { run_command('spec') }.should.raise Pod::Command::Help
lambda { run_command('spec', 'create') }.should.raise Pod::Command::Help
lambda { run_command('spec', '--create') }.should.raise Pod::Command::Help lambda { run_command('spec', '--create') }.should.raise Pod::Command::Help
lambda { run_command('spec', 'NAME') }.should.raise Pod::Command::Help
lambda { run_command('spec', 'createa') }.should.raise Pod::Command::Help lambda { run_command('spec', 'createa') }.should.raise Pod::Command::Help
lambda { run_command('spec', 'create') }.should.raise Pod::Command::Help lambda { run_command('lint', 'agument1', '2') }.should.raise Pod::Command::Help
end end
end
describe "Pod::Command::Spec create" do
extend SpecHelper::Command
extend SpecHelper::Github
extend SpecHelper::TemporaryDirectory
extend SpecHelper::Git
it "creates a new podspec stub file" do it "creates a new podspec stub file" do
run_command('spec', 'create', 'Bananas') run_command('spec', 'create', 'Bananas')
...@@ -50,6 +50,22 @@ describe "Pod::Command::Spec" do ...@@ -50,6 +50,22 @@ describe "Pod::Command::Spec" do
spec.source.should == { :git => 'https://github.com/lukeredpath/libPusher.git', :tag => 'v1.3' } spec.source.should == { :git => 'https://github.com/lukeredpath/libPusher.git', :tag => 'v1.3' }
end end
it "accepts the a name when creating a podspec form github" do
expect_github_repo_request
expect_github_user_request
expect_github_tags_request
run_command('spec', 'create', 'other_name', 'https://github.com/lukeredpath/libPusher.git')
path = temporary_directory + 'other_name.podspec'
spec = Pod::Specification.from_file(path)
spec.name.should == 'other_name'
spec.license.should == { :type => "MIT", :file => "LICENSE" }
spec.version.should == Pod::Version.new('1.3')
spec.summary.should == 'An Objective-C interface to Pusher (pusherapp.com)'
spec.homepage.should == 'https://github.com/lukeredpath/libPusher'
spec.authors.should == {"Luke Redpath"=>"luke@lukeredpath.co.uk"}
spec.source.should == { :git => 'https://github.com/lukeredpath/libPusher.git', :tag => 'v1.3' }
end
it "correctly suggests the head commit if a suitable tag is not available on github" do it "correctly suggests the head commit if a suitable tag is not available on github" do
expect_github_repo_request expect_github_repo_request
expect_github_user_request expect_github_user_request
...@@ -71,8 +87,96 @@ describe "Pod::Command::Spec" do ...@@ -71,8 +87,96 @@ describe "Pod::Command::Spec" do
output.should.include 'MARKDOWN TEMPLATE' output.should.include 'MARKDOWN TEMPLATE'
output.should.include 'Please add semantic version tags' output.should.include 'Please add semantic version tags'
end end
end end
describe "Pod::Command::Spec lint" do
extend SpecHelper::Command
extend SpecHelper::TemporaryDirectory
extend SpecHelper::Git
before do
config.repos_dir = fixture('spec-repos')
end
after do
config.repos_dir = tmp_repos_path
end
it "lints a repo" do
# the fixture master repo has warnings and does not validates
lambda { run_command('spec', 'lint', 'master') }.should.raise Pod::Informative
end
it "lints a repo with --only-errors option and show the warnings" do
output = run_command('spec', 'lint', 'master', '--only-errors')
output.should.include "passed validation"
output.should.include "WARN"
end
it "complains if no repo name or url are provided and there a no specs in the current working directory" do
Dir.chdir(fixture('spec-repos') + 'master/JSONKit/') do
lambda { command('spec', 'lint').run }.should.raise Pod::Informative
end
end
it "lints the current working directory" do
Dir.chdir(fixture('spec-repos') + 'master/JSONKit/1.4/') do
output = command('spec', 'lint', '--quick', '--only-errors').run
output.should.include "passed validation"
end
end
it "lints a givent podspec" do
spec_file = fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec'
output = run_command('spec', 'lint', '--quick', spec_file)
output.should.include "passed validation"
end
before do
spec = (fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec').read
spec.gsub!(/https:\/\/github\.com\/johnezang\/JSONKit\.git/, fixture('integration/JSONKit').to_s)
spec.gsub!(/s\.source_files = 'JSONKit\.\*'/, "s.source_files = 'JSONKit.*'\ns.resources = 'WRONG_FOLDER'")
File.open(temporary_directory + 'JSONKit.podspec', 'w') {|f| f.write(spec) }
end
it "fails if there are warnings" do
cmd = command('spec', 'lint', '--quick')
Dir.chdir(temporary_directory) { lambda { cmd.run }.should.raise Pod::Informative }
cmd.output.should.include "- WARN | Missing license[:file] or [:text]"
end
it "respects the --only-errors option" do
cmd = command('spec', 'lint', '--quick', '--only-errors')
Dir.chdir(temporary_directory) { lambda { cmd.run }.should.not.raise Pod::Informative }
cmd.output.should.include "- WARN | Missing license[:file] or [:text]"
cmd.output.should.include "passed validation"
end
it "respects the --quick option" do
cmd = command('spec', '--quick', 'lint')
Dir.chdir(temporary_directory) { lambda { cmd.run }.should.raise Pod::Informative }
cmd.output.should.not.include "JSONKit/JSONKit.m:1640:27: warning: equality comparison with extraneous parentheses"
end
it "uses xcodebuild to generate warnings and checks for file patterns" do
# those two checks are merged because pod install is computationally expensive
cmd = command('spec', 'lint')
Dir.chdir(temporary_directory) { lambda { cmd.run }.should.raise Pod::Informative }
unless `which xcodebuild`.strip.empty?
cmd.output.should.include "JSONKit/JSONKit.m:1640:27: warning: equality comparison with extraneous parentheses"
end
cmd.output.should.include "- ERROR | [resources = 'WRONG_FOLDER'] -> did not match any file"
end
before do
spec = (fixture('spec-repos') + 'master/JSONKit/1.4/JSONKit.podspec').read
spec.gsub!(/s\.source_files = 'JSONKit\.\*'/, "s.source_files = 'JSONKit.*'\n if config.ios?\nend")
File.open(temporary_directory + 'JSONKit.podspec', 'w') {|f| f.write(spec) }
end
it "produces deprecation notices" do
cmd = command('spec', '--quick', 'lint')
Dir.chdir(temporary_directory) { lambda { cmd.run }.should.raise Pod::Informative }
cmd.output.should.include "- WARN | `config.ios?' and `config.osx' will be removed in version 0.7"
end
end
...@@ -260,6 +260,15 @@ describe "Pod::Podfile" do ...@@ -260,6 +260,15 @@ describe "Pod::Podfile" do
@target_definition.relative_pods_root.should == '${SRCROOT}/../Pods' @target_definition.relative_pods_root.should == '${SRCROOT}/../Pods'
end end
it "simply returns the $(PODS_ROOT) path if no xcodeproj file is available and doesn't needs to integrate" do
config.integrate_targets.should.equal true
config.integrate_targets = false
@target_definition.relative_pods_root.should == '${SRCROOT}/../Pods'
@target_definition.stubs(:xcodeproj).returns(nil)
@target_definition.relative_pods_root.should == '${SRCROOT}/Pods'
config.integrate_targets = true
end
it "returns the xcconfig file path relative to the project's $(SRCROOT)" do it "returns the xcconfig file path relative to the project's $(SRCROOT)" do
@target_definition.xcconfig_relative_path.should == '../Pods/Pods.xcconfig' @target_definition.xcconfig_relative_path.should == '../Pods/Pods.xcconfig'
end end
...@@ -271,6 +280,17 @@ describe "Pod::Podfile" do ...@@ -271,6 +280,17 @@ describe "Pod::Podfile" do
end end
describe "concerning validations" do describe "concerning validations" do
it "raises if it should integrate and can't find an xcodeproj" do
config.integrate_targets.should.equal true
target_definition = Pod::Podfile.new {}.target_definitions[:default]
target_definition.stubs(:xcodeproj).returns(nil)
exception = lambda {
target_definition.relative_pods_root
}.should.raise Pod::Informative
exception.message.should.include "Xcode project"
end
xit "raises if no platform is specified" do xit "raises if no platform is specified" do
exception = lambda { exception = lambda {
Pod::Podfile.new {}.validate! Pod::Podfile.new {}.validate!
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment