class Pod::Command::Repo::Publish
Public Class Methods
# File lib/pod/command/repo/publish.rb, line 43 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).join(',')).split(',') @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) super end
# File lib/pod/command/repo/publish.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'], ].concat(super) end
Public Instance Methods
# File lib/pod/command/repo/publish.rb, line 73 def run open_editor if @commit_message && @message.nil? check_if_push_allowed validate_podspec_files check_repo_status update_repo add_specs_to_repo push_repo unless @local_only end
# File lib/pod/command/repo/publish.rb, line 63 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
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/pod/command/repo/publish.rb, line 188 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
Temporary check to ensure that users do not push accidentally private specs to the master repo.
# File lib/pod/command/repo/publish.rb, line 108 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
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/pod/command/repo/publish.rb, line 166 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
@return [Integer] The number of the podspec files to push.
# File lib/pod/command/repo/publish.rb, line 271 def count podspec_files.count end
Open default editor to allow users to enter commit message
# File lib/pod/command/repo/publish.rb, line 94 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
@return [Array<Pathname>] The path of the specifications to push.
# File lib/pod/command/repo/publish.rb, line 257 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
Pushes the git repo against the remote.
@return [void]
# File lib/pod/command/repo/publish.rb, line 232 def push_repo UI.puts "\nPushing the `#{@repo}' repo\n".yellow repo_git('push', 'origin', 'HEAD') end
@return [Pathname] The directory of the repository.
# File lib/pod/command/repo/publish.rb, line 251 def repo_dir @source.specs_dir end
@return result of calling the git! with args in repo_dir
# File lib/pod/command/repo/publish.rb, line 245 def repo_git(*args) git!(['-C', repo_dir] + args) end
Returns source for @repo
@note If URL is invalid or repo doesn't exist, validate! will throw the error
@return [Source]
# File lib/pod/command/repo/publish.rb, line 281 def source_for_repo config.sources_manager.source_with_name_or_url(@repo) unless @repo.nil? rescue nil end
Updates the git repo against the remote.
@return [void]
# File lib/pod/command/repo/publish.rb, line 176 def update_repo UI.puts "Updating the `#{@repo}' repo\n".yellow git!(%W(-C #{repo_dir} pull)) end
Performs a full lint against the podspecs.
# File lib/pod/command/repo/publish.rb, line 133 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.quick = true 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