module Pod class Command class Trunk # @CocoaPods 0.33.0 # class Push < Trunk self.summary = 'Publish a podspec' self.description = <<-DESC Publish the podspec at `PATH` to make it available to all users of the ‘trunk’ spec-repo. If `PATH` is not provided, defaults to the current directory. Before pushing the podspec to cocoapods.org, this will perform a local lint of the podspec, including a build of the library. However, it remains *your* responsibility to ensure that the published podspec will actually work for your users. Thus it is recommended that you *first* try to use the podspec to integrate the library into your demo and/or real application. If this is the first time you publish a spec for this pod, you will automatically be registered as the ‘owner’ of this pod. (Note that ‘owner’ in this case implies a person that is allowed to publish new versions and add other ‘owners’, not necessarily the library author.) DESC self.arguments = [ CLAide::Argument.new('PATH', false), ] def self.options [ ['--allow-warnings', 'Allows push even if there are lint warnings'], ['--use-libraries', 'Linter uses static libraries to install the spec'], ['--use-modular-headers', 'Lint uses modular headers during installation'], ['--swift-version=VERSION', 'The SWIFT_VERSION that should be used to lint the spec. ' \ 'This takes precedence over a .swift-version file.'], ['--skip-import-validation', 'Lint skips validating that the pod can be imported'], ['--skip-tests', 'Lint skips building and running tests during validation'], ].concat(super) end def initialize(argv) @allow_warnings = argv.flag?('allow-warnings', false) @use_frameworks = !argv.flag?('use-libraries') @use_modular_headers = argv.flag?('use-modular-headers') @swift_version = argv.option('swift-version', nil) @skip_import_validation = argv.flag?('skip-import-validation', false) @skip_tests = argv.flag?('skip-tests', false) @path = argv.shift_argument || '.' find_podspec_file if File.directory?(@path) super end def validate! super unless token help! 'You need to run `pod trunk register` to register a session first.' end unless @path help! 'Please specify the path to the podspec file.' end unless File.exist?(@path) && !File.directory?(@path) help! "The specified path `#{@path}` does not point to " \ 'an existing podspec file.' end end def run update_master_repo validate_podspec status, json = push_to_trunk update_master_repo if (400...600).cover?(status) print_messages(json['data_url'], json['messages'], nil) else print_messages(json['data_url'], json['messages'], spec, 'published') end end private def push_to_trunk spec.attributes_hash[:pushed_with_swift_version] = @swift_version if @swift_version response = request_path(:post, "pods?allow_warnings=#{@allow_warnings}", spec.to_json, auth_headers) url = response.headers['location'].first return response.status_code, json(request_url(:get, url, default_headers)) rescue REST::Error => e raise Informative, 'There was an error pushing a new version ' \ "to trunk: #{e.message}" end def find_podspec_file podspecs = Dir[Pathname(@path) + '*.podspec{.json,}'] case podspecs.count when 0 UI.notice "No podspec found in directory `#{@path}`" when 1 UI.notice "Found podspec `#{podspecs[0]}`" else UI.notice "Multiple podspec files in directory `#{@path}`. " \ 'You need to explicitly specify which one to use.' end @path = (podspecs.count == 1) ? podspecs[0] : nil end def spec @spec ||= Pod::Specification.from_file(@path) rescue Informative => e # TODO: this should be a more specific error raise Informative, 'Unable to interpret the specified path ' \ "#{UI.path(@path)} as a podspec (#{e})." end # Performs a full lint against the podspecs. # # TODO: Currently copied verbatim from `pod push`. def validate_podspec UI.puts 'Validating podspec'.yellow validator = Validator.new(spec, [master_repo_url]) validator.allow_warnings = @allow_warnings validator.use_frameworks = @use_frameworks if validator.respond_to?(:use_modular_headers=) validator.use_modular_headers = @use_modular_headers end if validator.respond_to?(:swift_version=) validator.swift_version = @swift_version end validator.skip_import_validation = @skip_import_validation validator.skip_tests = @skip_tests validator.validate unless validator.validated? raise Informative, "The spec did not pass validation, due to #{validator.failure_reason}." end # Let the validator's logic for the swift version # set the value for the trunk JSON uploader @swift_version = validator.respond_to?(:used_swift_version) && validator.used_swift_version end def update_master_repo # more robust Trunk setup logic: # - if Trunk exists, updates it # - if Trunk doesn't exist, add it and update it # trunk = sources_manager.find_or_create_source_with_url(Pod::TrunkSource::TRUNK_REPO_URL) sources_manager.update(trunk.name) end def master_repo_name sources_manager.master.first.name end def master_repo_url sources_manager.master.first.url end def sources_manager if defined?(Pod::SourcesManager) Pod::SourcesManager else config.sources_manager end end end end end end