class Pod::Command::Repo::Push

Public Class Methods

new(argv) click to toggle source
Calls superclass method Pod::Command::new
# File lib/cocoapods/command/repo/push.rb, line 45
def initialize(argv)
  @allow_warnings = argv.flag?('allow-warnings')
  @local_only = argv.flag?('local-only')
  @repo = argv.shift_argument
  @source = source_for_repo
  @source_urls = argv.option('sources', config.sources_manager.all.map(&:url).append(Pod::TrunkSource::TRUNK_REPO_URL).uniq.join(',')).split(',')
  @update_sources = argv.flag?('update-sources')
  @podspec = argv.shift_argument
  @use_frameworks = !argv.flag?('use-libraries')
  @use_modular_headers = argv.flag?('use-modular-headers', false)
  @private = argv.flag?('private', true)
  @message = argv.option('commit-message')
  @commit_message = argv.flag?('commit-message', false)
  @use_json = argv.flag?('use-json')
  @swift_version = argv.option('swift-version', nil)
  @skip_import_validation = argv.flag?('skip-import-validation', false)
  @skip_tests = argv.flag?('skip-tests', false)
  @allow_overwrite = argv.flag?('overwrite', true)
  @validation_dir = argv.option('validation-dir', nil)
  super
end
options() click to toggle source
Calls superclass method Pod::Command::options
# File lib/cocoapods/command/repo/push.rb, line 23
def self.options
  [
    ['--allow-warnings', 'Allows pushing even if there are warnings'],
    ['--use-libraries', 'Linter uses static libraries to install the spec'],
    ['--use-modular-headers', 'Lint uses modular headers during installation'],
    ["--sources=#{Pod::TrunkSource::TRUNK_REPO_URL}", 'The sources from which to pull dependent pods ' \
     '(defaults to all available repos). Multiple sources must be comma-delimited'],
    ['--local-only', 'Does not perform the step of pushing REPO to its remote'],
    ['--no-private', 'Lint includes checks that apply only to public repos'],
    ['--skip-import-validation', 'Lint skips validating that the pod can be imported'],
    ['--skip-tests', 'Lint skips building and running tests during validation'],
    ['--commit-message="Fix bug in pod"', 'Add custom commit message. Opens default editor if no commit ' \
      'message is specified'],
    ['--use-json', 'Convert the podspec to JSON before pushing it to the repo'],
    ['--swift-version=VERSION', 'The `SWIFT_VERSION` that should be used when linting the spec. ' \
     'This takes precedence over the Swift versions specified by the spec or a `.swift-version` file'],
    ['--no-overwrite', 'Disallow pushing that would overwrite an existing spec'],
    ['--update-sources', 'Make sure sources are up-to-date before a push'],
    ['--validation-dir', 'The directory to use for validation. If none is specified a temporary directory will be used.'],
  ].concat(super)
end

Public Instance Methods

run() click to toggle source
# File lib/cocoapods/command/repo/push.rb, line 77
def run
  open_editor if @commit_message && @message.nil?
  check_if_push_allowed
  update_sources if @update_sources
  validate_podspec_files
  check_repo_status
  update_repo
  add_specs_to_repo
  push_repo unless @local_only
end
validate!() click to toggle source
Calls superclass method
# File lib/cocoapods/command/repo/push.rb, line 67
def validate!
  super
  help! 'A spec-repo name or url is required.' unless @repo
  unless @source && @source.repo.directory?
    raise Informative,
          "Unable to find the `#{@repo}` repo. " \
          'If it has not yet been cloned, add it via `pod repo add`.'
  end
end

Private Instance Methods

add_specs_to_repo() click to toggle source

Commits the podspecs to the source, which should be a git repo.

@note The pre commit hook of the repo is skipped as the podspecs have

already been linted.

@return [void]

# File lib/cocoapods/command/repo/push.rb, line 207
def add_specs_to_repo
  UI.puts "\nAdding the #{'spec'.pluralize(count)} to the `#{@repo}' repo\n".yellow
  podspec_files.each do |spec_file|
    spec = Pod::Specification.from_file(spec_file)
    output_path = @source.pod_path(spec.name) + spec.version.to_s
    message = if @message && !@message.empty?
                @message
              elsif output_path.exist?
                "[Fix] #{spec}"
              elsif output_path.dirname.directory?
                "[Update] #{spec}"
              else
                "[Add] #{spec}"
              end

    if output_path.exist? && !@allow_overwrite
      raise Informative, "#{spec} already exists and overwriting has been disabled."
    end

    FileUtils.mkdir_p(output_path)

    if @use_json
      json_file_name = "#{spec.name}.podspec.json"
      json_file = File.join(output_path, json_file_name)
      File.open(json_file, 'w') { |file| file.write(spec.to_pretty_json) }
    else
      FileUtils.cp(spec_file, output_path)
    end

    # only commit if modified
    if repo_git('status', '--porcelain').include?(spec.name)
      UI.puts " - #{message}"
      repo_git('add', spec.name)
      repo_git('commit', '--no-verify', '-m', message)
    else
      UI.puts " - [No change] #{spec}"
    end
  end
end
check_if_push_allowed() click to toggle source

Temporary check to ensure that users do not push accidentally private specs to the master repo.

# File lib/cocoapods/command/repo/push.rb, line 113
def check_if_push_allowed
  if @source.is_a?(CDNSource)
    raise Informative, 'Cannot push to a CDN source, as it is read-only.'
  end

  remotes, = Executable.capture_command('git', %w(remote --verbose), :capture => :merge, :chdir => repo_dir)
  master_repo_urls = [
    'git@github.com:CocoaPods/Specs.git',
    'https://github.com/CocoaPods/Specs.git',
  ]
  is_master_repo = master_repo_urls.any? do |url|
    remotes.include?(url)
  end

  if is_master_repo
    raise Informative, 'To push to the CocoaPods master repo use ' \
      "the `pod trunk push` command.\n\nIf you are using a fork of " \
      'the master repo for private purposes we recommend to migrate ' \
      'to a clean private repo. To disable this check remove the ' \
      'remote pointing to the CocoaPods master repo.'
  end
end
check_repo_status() click to toggle source

Checks that the repo is clean.

@raise If the repo is not clean.

@todo Add specs for staged and unstaged files.

@todo Gracefully handle the case where source is not under git

source control.

@return [void]

# File lib/cocoapods/command/repo/push.rb, line 171
def check_repo_status
  porcelain_status, = Executable.capture_command('git', %w(status --porcelain), :capture => :merge, :chdir => repo_dir)
  clean = porcelain_status == ''
  raise Informative, "The repo `#{@repo}` at #{UI.path repo_dir} is not clean" unless clean
end
count() click to toggle source

@return [Integer] The number of the podspec files to push.

# File lib/cocoapods/command/repo/push.rb, line 290
def count
  podspec_files.count
end
open_editor() click to toggle source

Open default editor to allow users to enter commit message

# File lib/cocoapods/command/repo/push.rb, line 99
def open_editor
  return if ENV['EDITOR'].nil?

  file = Tempfile.new('cocoapods')
  File.chmod(0777, file.path)
  file.close

  system("#{ENV['EDITOR']} #{file.path}")
  @message = File.read file.path
end
podspec_files() click to toggle source

@return [Array<Pathname>] The path of the specifications to push.

# File lib/cocoapods/command/repo/push.rb, line 276
def podspec_files
  if @podspec
    path = Pathname(@podspec)
    raise Informative, "Couldn't find #{@podspec}" unless path.exist?
    [path]
  else
    files = Pathname.glob('*.podspec{,.json}')
    raise Informative, "Couldn't find any podspec files in current directory" if files.empty?
    files
  end
end
push_repo() click to toggle source

Pushes the git repo against the remote.

@return [void]

# File lib/cocoapods/command/repo/push.rb, line 251
def push_repo
  UI.puts "\nPushing the `#{@repo}' repo\n".yellow
  repo_git('push', 'origin', 'HEAD')
end
repo_dir() click to toggle source

@return [Pathname] The directory of the repository.

# File lib/cocoapods/command/repo/push.rb, line 270
def repo_dir
  @source.specs_dir
end
repo_git(*args) click to toggle source

@return result of calling the git! with args in repo_dir

# File lib/cocoapods/command/repo/push.rb, line 264
def repo_git(*args)
  git!(['-C', repo_dir] + args)
end
source_for_repo() click to toggle source

Returns source for @repo

@note If URL is invalid or repo doesn’t exist, validate! will throw the error

@return [Source]

# File lib/cocoapods/command/repo/push.rb, line 300
def source_for_repo
  config.sources_manager.source_with_name_or_url(@repo) unless @repo.nil?
rescue
  nil
end
update_repo() click to toggle source

Updates the git repo against the remote.

@return [void]

# File lib/cocoapods/command/repo/push.rb, line 181
def update_repo
  UI.puts "Updating the `#{@repo}' repo\n".yellow
  git!(%W(-C #{repo_dir} pull))
end
update_sources() click to toggle source

Update sources if present

@return [void]

# File lib/cocoapods/command/repo/push.rb, line 190
def update_sources
  return if @source_urls.nil?
  @source_urls.each do |source_url|
    source = config.sources_manager.source_with_name_or_url(source_url)
    dir = source.specs_dir
    UI.puts "Updating a source at #{dir} for #{source}"
    git!(%W(-C #{dir} pull))
  end
end
validate_podspec_files() click to toggle source

Performs a full lint against the podspecs.

# File lib/cocoapods/command/repo/push.rb, line 138
def validate_podspec_files
  UI.puts "\nValidating #{'spec'.pluralize(count)}".yellow
  podspec_files.each do |podspec|
    validator = Validator.new(podspec, @source_urls)
    validator.allow_warnings = @allow_warnings
    validator.use_frameworks = @use_frameworks
    validator.use_modular_headers = @use_modular_headers
    validator.ignore_public_only_results = @private
    validator.swift_version = @swift_version
    validator.skip_import_validation = @skip_import_validation
    validator.skip_tests = @skip_tests
    validator.validation_dir = @validation_dir
    begin
      validator.validate
    rescue => e
      raise Informative, "The `#{podspec}` specification does not validate." \
                         "\n\n#{e.message}"
    end
    raise Informative, "The `#{podspec}` specification does not validate." unless validator.validated?
  end
end