├── .gitignore ├── .travis.yml ├── .rspec ├── .simplecov ├── Rakefile ├── Gemfile ├── lib ├── updater.rb └── updater │ ├── command.rb │ ├── version.rb │ ├── git.rb │ ├── pod.rb │ ├── configuration.rb │ ├── specs.rb │ └── synchronize.rb ├── bin └── pod-synchronize ├── spec ├── fixtures │ ├── api_client_config.yml │ ├── config.yml │ ├── specs_other │ │ └── NBNPhotoChooser │ │ │ ├── 0.0.1 │ │ │ └── NBNPhotoChooser.podspec.json │ │ │ ├── 0.0.2 │ │ │ └── NBNPhotoChooser.podspec.json │ │ │ ├── 0.0.6 │ │ │ └── NBNPhotoChooser.podspec.json │ │ │ ├── 0.1.0 │ │ │ └── NBNPhotoChooser.podspec.json │ │ │ ├── 0.2.0 │ │ │ └── NBNPhotoChooser.podspec.json │ │ │ └── 0.2.1 │ │ │ └── NBNPhotoChooser.podspec.json │ └── specs │ │ ├── XNGOAuth1Client │ │ ├── 0.0.1 │ │ │ └── XNGOAuth1Client.podspec.json │ │ ├── 0.0.2 │ │ │ └── XNGOAuth1Client.podspec.json │ │ ├── 1.0.0 │ │ │ └── XNGOAuth1Client.podspec.json │ │ ├── 2.0.0 │ │ │ └── XNGOAuth1Client.podspec.json │ │ └── 2.0.1 │ │ │ └── XNGOAuth1Client.podspec.json │ │ ├── XNGAPIClient │ │ ├── 0.1.0 │ │ │ └── XNGAPIClient.podspec.json │ │ ├── 0.2.0 │ │ │ └── XNGAPIClient.podspec.json │ │ ├── 1.0.0 │ │ │ └── XNGAPIClient.podspec.json │ │ ├── 1.1.0 │ │ │ └── XNGAPIClient.podspec.json │ │ ├── 1.1.1 │ │ │ └── XNGAPIClient.podspec.json │ │ ├── 1.2.0 │ │ │ └── XNGAPIClient.podspec.json │ │ ├── 0.2.1 │ │ │ └── XNGAPIClient.podspec.json │ │ ├── 0.2.2 │ │ │ └── XNGAPIClient.podspec.json │ │ ├── 0.3.0 │ │ │ └── XNGAPIClient.podspec.json │ │ ├── 0.3.1 │ │ │ └── XNGAPIClient.podspec.json │ │ └── 0.4.0 │ │ │ └── XNGAPIClient.podspec.json │ │ └── NBNRealmBrowser │ │ ├── 0.2.0 │ │ └── NBNRealmBrowser.podspec.json │ │ ├── 0.3.0 │ │ └── NBNRealmBrowser.podspec.json │ │ └── 0.1.0 │ │ └── NBNRealmBrowser.podspec.json ├── synchronize_spec.rb ├── version_spec.rb ├── pod_spec.rb ├── specs_spec.rb ├── git_spec.rb ├── configuration_spec.rb └── spec_helper.rb ├── pod-synchronize.gemspec ├── LICENSE ├── Gemfile.lock └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | coverage/ 2 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: ruby 2 | rvm: 3 | - 2.0 4 | -------------------------------------------------------------------------------- /.rspec: -------------------------------------------------------------------------------- 1 | --color 2 | --require spec_helper 3 | --format d 4 | -------------------------------------------------------------------------------- /.simplecov: -------------------------------------------------------------------------------- 1 | SimpleCov.start do 2 | add_filter 'spec/' 3 | end 4 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rspec/core/rake_task" 3 | 4 | RSpec::Core::RakeTask.new(:spec) 5 | 6 | task :default => :spec 7 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | group :development do 6 | gem 'rspec' 7 | gem 'coveralls', :require => false 8 | end 9 | -------------------------------------------------------------------------------- /lib/updater.rb: -------------------------------------------------------------------------------- 1 | require 'updater/pod.rb' 2 | require 'updater/version.rb' 3 | require 'updater/specs.rb' 4 | require 'updater/git.rb' 5 | require 'updater/configuration.rb' 6 | require 'updater/command.rb' 7 | require 'updater/synchronize.rb' 8 | -------------------------------------------------------------------------------- /bin/pod-synchronize: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | if $PROGRAM_NAME == __FILE__ 4 | ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__) 5 | require 'rubygems' 6 | require 'bundler/setup' 7 | $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__) 8 | end 9 | 10 | require 'updater' 11 | PodSynchronize::Command.run(ARGV) 12 | -------------------------------------------------------------------------------- /lib/updater/command.rb: -------------------------------------------------------------------------------- 1 | require 'claide' 2 | require 'colored' 3 | 4 | module PodSynchronize 5 | class PlainInformative < StandardError 6 | include CLAide::InformativeError 7 | end 8 | 9 | class Informative < PlainInformative 10 | def message 11 | "[!] #{super}".red 12 | end 13 | end 14 | 15 | class Command < CLAide::Command 16 | require "updater" 17 | 18 | self.abstract_command = true 19 | self.command = 'pod-synchronize' 20 | self.version = '0.1.0' 21 | self.description = 'Pods Synchronizer' 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/fixtures/api_client_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | master_repo: https://github.com/CocoaPods/Specs.git 3 | mirror: 4 | specs_push_url: git@git.hooli.xyz:pods-mirror/Specs.git 5 | source_push_url: git@git.hooli.xyz:pods-mirror 6 | source_clone_url: git://git.hooli.xyz/pods-mirror 7 | github: 8 | acccess_token: 0y83t1ihosjklgnuioa 9 | organisation: pods-mirror 10 | endpoint: https://git.hooli.xyz/api/v3 11 | podfiles: 12 | - "https://raw.githubusercontent.com/xing/XNGAPIClient/master/Example/Podfile.lock" 13 | pods: 14 | - Google-Mobile-Ads-SDK 15 | excluded_pods: 16 | - SAMKeychain 17 | -------------------------------------------------------------------------------- /spec/synchronize_spec.rb: -------------------------------------------------------------------------------- 1 | describe PodSynchronize::Command::Synchronize do 2 | 3 | before :all do 4 | @sync = PodSynchronize::Command::Synchronize.new(CLAide::ARGV.new(['./spec/fixtures/api_client_config.yml'])) 5 | Dir.mktmpdir { |dir| @sync.setup(dir) } 6 | end 7 | 8 | describe "#dependencies" do 9 | it "resolves the dependencies correctly" do 10 | expected_result = [ 11 | "AFNetworking", 12 | "Expecta", 13 | "OCMock", 14 | "OHHTTPStubs", 15 | "XNGAPIClient", 16 | "XNGOAuth1Client", 17 | "Google-Mobile-Ads-SDK", 18 | ] 19 | expect(@sync.dependencies).to eql(expected_result) 20 | end 21 | end 22 | 23 | end 24 | -------------------------------------------------------------------------------- /spec/fixtures/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | master_repo: https://github.com/CocoaPods/Specs.git 3 | mirror: 4 | specs_push_url: git@git.hooli.xyz:pods-mirror/Specs.git 5 | source_push_url: git@git.hooli.xyz:pods-mirror 6 | source_clone_url: git://git.hooli.xyz/pods-mirror 7 | github: 8 | acccess_token: 0y83t1ihosjklgnuioa 9 | organisation: pods-mirror 10 | endpoint: https://git.hooli.xyz/api/v3 11 | podfiles: 12 | - "https://git.hooli.xyz/ios/moonshot/raw/master/Podfile.lock" 13 | - "https://git.hooli.xyz/ios/nucleus/raw/master/Podfile.lock" 14 | - "https://git.hooli.xyz/ios/bro2bro/raw/master/Podfile.lock" 15 | pods: 16 | - Google-Mobile-Ads-SDK 17 | excluded_pods: 18 | - BABCropperView 19 | -------------------------------------------------------------------------------- /spec/fixtures/specs_other/NBNPhotoChooser/0.0.1/NBNPhotoChooser.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NBNPhotoChooser", 3 | "version": "0.0.1", 4 | "platforms": { 5 | "ios": null 6 | }, 7 | "summary": "NBNPhotoChooser is an example implementation of the Tumblr Photo Chooser.", 8 | "homepage": "https://github.com/nerdishbynature/NBNPhotoChooser", 9 | "license": { 10 | "type": "MIT", 11 | "file": "LICENSE" 12 | }, 13 | "authors": { 14 | "Piet Brauer": "piet@nerdishbynature.com" 15 | }, 16 | "source": { 17 | "git": "git://source.xing.com/ios-pods-external/NBNPhotoChooser.git", 18 | "tag": "0.0.1" 19 | }, 20 | "source_files": [ 21 | "Classes", 22 | "Classes/**/*.{h,m}" 23 | ], 24 | "requires_arc": true 25 | } -------------------------------------------------------------------------------- /spec/fixtures/specs_other/NBNPhotoChooser/0.0.2/NBNPhotoChooser.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NBNPhotoChooser", 3 | "version": "0.0.2", 4 | "platforms": { 5 | "ios": null 6 | }, 7 | "summary": "NBNPhotoChooser is an example implementation of the Tumblr Photo Chooser.", 8 | "homepage": "https://github.com/nerdishbynature/NBNPhotoChooser", 9 | "license": { 10 | "type": "MIT", 11 | "file": "LICENSE" 12 | }, 13 | "authors": { 14 | "Piet Brauer": "piet@nerdishbynature.com" 15 | }, 16 | "source": { 17 | "git": "git://source.xing.com/ios-pods-external/NBNPhotoChooser.git", 18 | "tag": "0.0.2" 19 | }, 20 | "source_files": [ 21 | "Classes", 22 | "Classes/**/*.{h,m}" 23 | ], 24 | "requires_arc": true 25 | } -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGOAuth1Client/0.0.1/XNGOAuth1Client.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGOAuth1Client", 3 | "version": "0.0.1", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.8" 8 | }, 9 | "summary": "A OAuth1 client based on AFNetworking 2.0 for use in the XNGAPIClient", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "git://source.xing.com/ios-pods-external/XNGOAuth1Client.git", 15 | "tag": "0.0.1" 16 | }, 17 | "source_files": "XNGOAuth1Client/*.{h,m}", 18 | "requires_arc": true, 19 | "homepage": "https://www.xing.com", 20 | "dependencies": { 21 | "AFNetworking": [ 22 | "~> 2.0.3" 23 | ] 24 | }, 25 | "frameworks": "Security" 26 | } -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGOAuth1Client/0.0.2/XNGOAuth1Client.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGOAuth1Client", 3 | "version": "0.0.2", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.8" 8 | }, 9 | "summary": "A OAuth1 client based on AFNetworking 2.0 for use in the XNGAPIClient", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "git://source.xing.com/ios-pods-external/XNGOAuth1Client.git", 15 | "tag": "0.0.2" 16 | }, 17 | "source_files": "XNGOAuth1Client/*.{h,m}", 18 | "requires_arc": true, 19 | "homepage": "https://www.xing.com", 20 | "dependencies": { 21 | "AFNetworking": [ 22 | "~> 2.0.3" 23 | ] 24 | }, 25 | "frameworks": "Security" 26 | } -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGOAuth1Client/1.0.0/XNGOAuth1Client.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGOAuth1Client", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.8" 8 | }, 9 | "summary": "A OAuth1 client based on AFNetworking 2.0 for use in the XNGAPIClient", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "git://source.xing.com/ios-pods-external/XNGOAuth1Client.git", 15 | "tag": "1.0.0" 16 | }, 17 | "source_files": "XNGOAuth1Client/*.{h,m}", 18 | "requires_arc": true, 19 | "homepage": "https://www.xing.com", 20 | "dependencies": { 21 | "AFNetworking": [ 22 | "~> 2.0" 23 | ] 24 | }, 25 | "frameworks": "Security" 26 | } -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGOAuth1Client/2.0.0/XNGOAuth1Client.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGOAuth1Client", 3 | "version": "2.0.0", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.8" 8 | }, 9 | "summary": "A OAuth1 client based on AFNetworking 2.0 for use in the XNGAPIClient", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "git://source.xing.com/ios-pods-external/XNGOAuth1Client.git", 15 | "tag": "2.0.0" 16 | }, 17 | "source_files": "XNGOAuth1Client/*.{h,m}", 18 | "requires_arc": true, 19 | "homepage": "https://www.xing.com", 20 | "dependencies": { 21 | "AFNetworking": [ 22 | "~> 2.0" 23 | ] 24 | }, 25 | "frameworks": "Security" 26 | } -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGOAuth1Client/2.0.1/XNGOAuth1Client.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGOAuth1Client", 3 | "version": "2.0.1", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.8" 8 | }, 9 | "summary": "A OAuth1 client based on AFNetworking 2.0 for use in the XNGAPIClient", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "git://source.xing.com/ios-pods-external/XNGOAuth1Client.git", 15 | "tag": "2.0.1" 16 | }, 17 | "source_files": "XNGOAuth1Client/*.{h,m}", 18 | "requires_arc": true, 19 | "homepage": "https://www.xing.com", 20 | "dependencies": { 21 | "AFNetworking": [ 22 | "~> 2.0" 23 | ] 24 | }, 25 | "frameworks": "Security" 26 | } -------------------------------------------------------------------------------- /spec/fixtures/specs_other/NBNPhotoChooser/0.0.6/NBNPhotoChooser.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NBNPhotoChooser", 3 | "version": "0.0.6", 4 | "platforms": { 5 | "ios": 6.0 6 | }, 7 | "summary": "NBNPhotoChooser is an example implementation of the Tumblr Photo Chooser.", 8 | "homepage": "https://github.com/nerdishbynature/NBNPhotoChooser", 9 | "license": { 10 | "type": "MIT", 11 | "file": "LICENSE" 12 | }, 13 | "authors": { 14 | "Piet Brauer": "piet@nerdishbynature.com" 15 | }, 16 | "source": { 17 | "git": "git://source.xing.com/ios-pods-external/NBNPhotoChooser.git", 18 | "tag": "0.0.6" 19 | }, 20 | "source_files": "Classes/**/*.{h,m}", 21 | "resource_bundles": { 22 | "NBNPhotoChooser": "Assets/*" 23 | }, 24 | "requires_arc": true 25 | } -------------------------------------------------------------------------------- /spec/fixtures/specs_other/NBNPhotoChooser/0.1.0/NBNPhotoChooser.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NBNPhotoChooser", 3 | "version": "0.1.0", 4 | "platforms": { 5 | "ios": 6.0 6 | }, 7 | "summary": "NBNPhotoChooser is an example implementation of the Tumblr Photo Chooser.", 8 | "homepage": "https://github.com/nerdishbynature/NBNPhotoChooser", 9 | "license": { 10 | "type": "MIT", 11 | "file": "LICENSE" 12 | }, 13 | "authors": { 14 | "Piet Brauer": "piet@nerdishbynature.com" 15 | }, 16 | "source": { 17 | "git": "git://source.xing.com/ios-pods-external/NBNPhotoChooser.git", 18 | "tag": "0.1.0" 19 | }, 20 | "source_files": "Classes/**/*.{h,m}", 21 | "resource_bundles": { 22 | "NBNPhotoChooser": "Assets/*" 23 | }, 24 | "requires_arc": true 25 | } -------------------------------------------------------------------------------- /spec/fixtures/specs_other/NBNPhotoChooser/0.2.0/NBNPhotoChooser.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NBNPhotoChooser", 3 | "version": "0.2.0", 4 | "platforms": { 5 | "ios": 7.0 6 | }, 7 | "summary": "NBNPhotoChooser is an example implementation of the Tumblr Photo Chooser.", 8 | "homepage": "https://github.com/nerdishbynature/NBNPhotoChooser", 9 | "license": { 10 | "type": "MIT", 11 | "file": "LICENSE" 12 | }, 13 | "authors": { 14 | "Piet Brauer": "piet@nerdishbynature.com" 15 | }, 16 | "source": { 17 | "git": "git://source.xing.com/ios-pods-external/NBNPhotoChooser.git", 18 | "tag": "0.2.0" 19 | }, 20 | "source_files": "Classes/**/*.{h,m}", 21 | "resource_bundles": { 22 | "NBNPhotoChooser": "Assets/*" 23 | }, 24 | "requires_arc": true 25 | } -------------------------------------------------------------------------------- /spec/fixtures/specs_other/NBNPhotoChooser/0.2.1/NBNPhotoChooser.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NBNPhotoChooser", 3 | "version": "0.2.1", 4 | "platforms": { 5 | "ios": 7.0 6 | }, 7 | "summary": "NBNPhotoChooser is an example implementation of the Tumblr Photo Chooser.", 8 | "homepage": "https://github.com/nerdishbynature/NBNPhotoChooser", 9 | "license": { 10 | "type": "MIT", 11 | "file": "LICENSE" 12 | }, 13 | "authors": { 14 | "Piet Brauer": "piet@nerdishbynature.com" 15 | }, 16 | "source": { 17 | "git": "git://source.xing.com/ios-pods-external/NBNPhotoChooser.git", 18 | "tag": "0.2.1" 19 | }, 20 | "source_files": "Classes/**/*.{h,m}", 21 | "resource_bundles": { 22 | "NBNPhotoChooser": "Assets/*" 23 | }, 24 | "requires_arc": true 25 | } -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/0.1.0/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "0.1.0", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.7" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "0.1.0" 16 | }, 17 | "source_files": "XNGAPIClient/*.{h,m}", 18 | "requires_arc": true, 19 | "homepage": "https://www.xing.com", 20 | "dependencies": { 21 | "AFNetworking": [ 22 | "~> 1.3.0" 23 | ], 24 | "SSKeychain": [ 25 | "= 1.2.0" 26 | ], 27 | "AFOAuth1Client": [ 28 | "= 0.3.1" 29 | ] 30 | }, 31 | "frameworks": [ 32 | "Security", 33 | "SystemConfiguration" 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/0.2.0/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "0.2.0", 4 | "license": "MIT", 5 | "social_media_url": "https://twitter.com/xingdevs", 6 | "platforms": { 7 | "ios": "6.0", 8 | "osx": "10.7" 9 | }, 10 | "summary": "The official Objective-C client for the XING API", 11 | "authors": { 12 | "XING iOS Team": "iphonedev@xing.com" 13 | }, 14 | "source": { 15 | "git": "https://github.com/xing/XNGAPIClient.git", 16 | "tag": "0.2.0" 17 | }, 18 | "source_files": "XNGAPIClient/*.{h,m}", 19 | "requires_arc": true, 20 | "homepage": "https://www.xing.com", 21 | "dependencies": { 22 | "AFNetworking": [ 23 | "~> 1.3.0" 24 | ], 25 | "SSKeychain": [ 26 | "= 1.2.0" 27 | ], 28 | "AFOAuth1Client": [ 29 | "= 0.3.1" 30 | ] 31 | }, 32 | "frameworks": [ 33 | "Security", 34 | "SystemConfiguration" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /lib/updater/version.rb: -------------------------------------------------------------------------------- 1 | require 'json' 2 | 3 | class Version 4 | attr_reader :path, :version 5 | attr_accessor :contents 6 | 7 | def initialize(path) 8 | @path = path 9 | @version = @path.split(File::SEPARATOR).last 10 | @contents = fetch_podspec 11 | end 12 | 13 | def save 14 | File.write(podspec_path, JSON.pretty_generate(@contents)) 15 | end 16 | 17 | def <=>(other) 18 | own_version = @version.split('.').map(&:to_i) 19 | other_version = other.version.split('.').map(&:to_i) 20 | own_version <=> other_version 21 | end 22 | 23 | private 24 | 25 | def podspec_path 26 | filepath = Dir.glob(File.join(@path, '*')).first 27 | unless filepath.end_with? 'podspec.json' 28 | raise "Couldn't find podspec file, got #{filepath}" 29 | end 30 | filepath 31 | end 32 | 33 | def fetch_podspec 34 | file = File.read(podspec_path) 35 | JSON.parse(file) 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /lib/updater/git.rb: -------------------------------------------------------------------------------- 1 | class Git 2 | attr_accessor :path 3 | 4 | def initialize(path = Dir.pwd) 5 | @path = path 6 | end 7 | 8 | def commit(message) 9 | execute('git add', '--all') 10 | execute('git commit', '-m', "'#{message}'") 11 | end 12 | 13 | def push(remote = 'origin master', options = nil) 14 | execute('git push', remote, options) 15 | end 16 | 17 | def clone(url, options = '.') 18 | execute('git clone', url, options) 19 | end 20 | 21 | def set_origin(url) 22 | execute('git remote', 'set-url origin', url) 23 | end 24 | 25 | def create_github_repo(access_token, org, name, endpoint) 26 | execute('curl', 27 | "#{endpoint}/orgs/#{org}/repos?access_token=#{access_token}", 28 | '-d', "'{\"name\":\"#{name}\"}'") 29 | end 30 | 31 | private 32 | 33 | def execute(*command) 34 | FileUtils.mkdir_p(path) unless Dir.exists?(path) 35 | Dir.chdir(path) do 36 | system(*command.join(" ").strip) 37 | end 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /lib/updater/pod.rb: -------------------------------------------------------------------------------- 1 | require 'uri' 2 | 3 | class Pod 4 | attr_reader :path, :name 5 | 6 | def initialize(path) 7 | @path = path 8 | @name = @path.split(File::SEPARATOR).last 9 | end 10 | 11 | def versions 12 | @versions ||= Dir.glob(File.join(@path, '*')).map do |version_path| 13 | Version.new(version_path) 14 | end 15 | end 16 | 17 | def git_source 18 | source = versions.sort.last.contents["source"]["git"] 19 | source ||= begin 20 | http_source = versions.sort.last.contents["source"]["http"] 21 | uri = URI.parse(http_source) 22 | return nil unless uri.host.include? "github.com" 23 | host = uri.host.match(/www.(.*)/).captures.first 24 | scheme = "git" 25 | path = uri.path.split("/").take(3).join("/").concat(".git") 26 | URI::Generic.build({scheme: scheme, host: host, path: path}).to_s 27 | end 28 | end 29 | 30 | def save 31 | versions.each(&:save) 32 | end 33 | 34 | def git 35 | @git ||= Git.new(@path) 36 | end 37 | 38 | end 39 | -------------------------------------------------------------------------------- /spec/fixtures/specs/NBNRealmBrowser/0.2.0/NBNRealmBrowser.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NBNRealmBrowser", 3 | "version": "0.2.0", 4 | "summary": "NBNRealmBrowser is the iOS companion to the Realm Browser for Mac.", 5 | "description": " NBNRealmBrowser is the iOS companion to the\n Realm Browser for Mac.\n It displays all information for your current\n Realm for debugging purposes.\n", 6 | "homepage": "https://github.com/nerdishbynature/NBNRealmBrowser", 7 | "license": "MIT", 8 | "authors": { 9 | "Piet Brauer": "piet@nerdishbynature.com" 10 | }, 11 | "source": { 12 | "git": "https://github.com/nerdishbynature/NBNRealmBrowser.git", 13 | "tag": "0.2.0" 14 | }, 15 | "social_media_url": "https://twitter.com/pietbrauer", 16 | "platforms": { 17 | "ios": "7.0" 18 | }, 19 | "requires_arc": true, 20 | "source_files": "Pod/Classes", 21 | "dependencies": { 22 | "Realm": [ 23 | "~> 0.85" 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /spec/fixtures/specs/NBNRealmBrowser/0.3.0/NBNRealmBrowser.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NBNRealmBrowser", 3 | "version": "0.3.0", 4 | "summary": "NBNRealmBrowser is the iOS companion to the Realm Browser for Mac.", 5 | "description": " NBNRealmBrowser is the iOS companion to the\n Realm Browser for Mac.\n It displays all information for your current\n Realm for debugging purposes.\n", 6 | "homepage": "https://github.com/nerdishbynature/NBNRealmBrowser", 7 | "license": "MIT", 8 | "authors": { 9 | "Piet Brauer": "piet@nerdishbynature.com" 10 | }, 11 | "source": { 12 | "git": "https://github.com/nerdishbynature/NBNRealmBrowser.git", 13 | "tag": "0.3.0" 14 | }, 15 | "social_media_url": "https://twitter.com/pietbrauer", 16 | "platforms": { 17 | "ios": "7.0" 18 | }, 19 | "requires_arc": true, 20 | "source_files": "Pod/Classes", 21 | "dependencies": { 22 | "Realm": [ 23 | "~> 0.91" 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /spec/fixtures/specs/NBNRealmBrowser/0.1.0/NBNRealmBrowser.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "NBNRealmBrowser", 3 | "version": "0.1.0", 4 | "summary": "NBNRealmBrowser is the iOS companion to the\n Realm Browser for Mac.", 5 | "description": " NBNRealmBrowser is the iOS companion to the\n Realm Browser for Mac.\n It displays all information for your current\n Realm for debugging purposes.\n", 6 | "homepage": "https://github.com/nerdishbynature/NBNRealmBrowser", 7 | "license": "MIT", 8 | "authors": { 9 | "Piet Brauer": "piet@nerdishbynature.com" 10 | }, 11 | "source": { 12 | "git": "https://github.com/nerdishbynature/NBNRealmBrowser.git", 13 | "tag": "0.1.0" 14 | }, 15 | "social_media_url": "https://twitter.com/pietbrauer", 16 | "platforms": { 17 | "ios": "7.0" 18 | }, 19 | "requires_arc": true, 20 | "source_files": "Pod/Classes", 21 | "dependencies": { 22 | "Realm": [ 23 | "~> 0.85" 24 | ] 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /lib/updater/configuration.rb: -------------------------------------------------------------------------------- 1 | require 'yaml' 2 | require 'erb' 3 | 4 | class Configuration 5 | attr_reader :yaml 6 | Mirror = Struct.new(:specs_push_url, :source_push_url, :source_clone_url, :github) 7 | Github = Struct.new(:access_token, :organisation, :endpoint) 8 | 9 | def initialize(path) 10 | @yaml = YAML.load(ERB.new(File.new(path).read).result) 11 | end 12 | 13 | def master_repo 14 | @yaml['master_repo'] 15 | end 16 | 17 | def podfiles 18 | @yaml['podfiles'] 19 | end 20 | 21 | def pods 22 | @yaml['pods'] 23 | end 24 | 25 | def excluded_pods 26 | @yaml['excluded_pods'] 27 | end 28 | 29 | def mirror 30 | context = @yaml['mirror'] 31 | Mirror.new( 32 | context['specs_push_url'], 33 | context['source_push_url'], 34 | context['source_clone_url'], 35 | github) 36 | end 37 | 38 | private 39 | 40 | def github 41 | context = @yaml['mirror']['github'] 42 | Github.new( 43 | context['acccess_token'], 44 | context['organisation'], 45 | context['endpoint']) 46 | end 47 | 48 | end 49 | -------------------------------------------------------------------------------- /pod-synchronize.gemspec: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | Gem::Specification.new do |spec| 3 | spec.name = "pod-synchronize" 4 | spec.version = "0.5.0" 5 | spec.authors = ["Matthias Männich", "Piet Brauer", "Renzo Crisostomo"] 6 | spec.email = ["matthias.maennich@xing.com", "piet.brauer@xing.com", "renzo.crisostomo@xing.com"] 7 | spec.summary = %q{Mirrors CocoaPods specs} 8 | spec.description = %q{Synchronizes the public CocoaPods Specs repo with your internal mirror.} 9 | spec.homepage = "https://github.com/xing/XNGPodsSynchronizer" 10 | spec.license = "MIT" 11 | 12 | spec.files = `git ls-files -z`.split("\x0") 13 | spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } 14 | spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) 15 | spec.require_paths = ["lib"] 16 | 17 | spec.add_dependency "claide", "~> 0.8.1" 18 | spec.add_dependency "colored", "~> 1.2" 19 | 20 | spec.add_development_dependency "bundler", "~> 1.7" 21 | spec.add_development_dependency "rake", "~> 10.0" 22 | 23 | spec.required_ruby_version = '>= 2.0.0' 24 | end 25 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/1.0.0/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "1.0.0", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.8" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "1.0.0" 16 | }, 17 | "requires_arc": true, 18 | "homepage": "https://www.xing.com", 19 | "default_subspecs": "Core", 20 | "subspecs": [ 21 | { 22 | "name": "Core", 23 | "source_files": "XNGAPIClient/*.{h,m}", 24 | "dependencies": { 25 | "SSKeychain": [ 26 | "~> 1.2.0" 27 | ], 28 | "XNGOAuth1Client": [ 29 | "~> 1.0.0" 30 | ] 31 | }, 32 | "frameworks": [ 33 | "Security", 34 | "SystemConfiguration" 35 | ] 36 | }, 37 | { 38 | "name": "NSDictionary-Typecheck", 39 | "source_files": "XNGAPIClient/NSDictionary+Typecheck.{h,m}" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/1.1.0/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "1.1.0", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.8" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "1.1.0" 16 | }, 17 | "requires_arc": true, 18 | "homepage": "https://www.xing.com", 19 | "default_subspecs": "Core", 20 | "subspecs": [ 21 | { 22 | "name": "Core", 23 | "source_files": "XNGAPIClient/*.{h,m}", 24 | "dependencies": { 25 | "SSKeychain": [ 26 | "~> 1.2.0" 27 | ], 28 | "XNGOAuth1Client": [ 29 | "~> 2.0.0" 30 | ] 31 | }, 32 | "frameworks": [ 33 | "Security", 34 | "SystemConfiguration" 35 | ] 36 | }, 37 | { 38 | "name": "NSDictionary-Typecheck", 39 | "source_files": "XNGAPIClient/NSDictionary+Typecheck.{h,m}" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/1.1.1/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "1.1.1", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.8" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "1.1.1" 16 | }, 17 | "requires_arc": true, 18 | "homepage": "https://www.xing.com", 19 | "default_subspecs": "Core", 20 | "subspecs": [ 21 | { 22 | "name": "Core", 23 | "source_files": "XNGAPIClient/*.{h,m}", 24 | "dependencies": { 25 | "SSKeychain": [ 26 | "~> 1.2.0" 27 | ], 28 | "XNGOAuth1Client": [ 29 | "~> 2.0.0" 30 | ] 31 | }, 32 | "frameworks": [ 33 | "Security", 34 | "SystemConfiguration" 35 | ] 36 | }, 37 | { 38 | "name": "NSDictionary-Typecheck", 39 | "source_files": "XNGAPIClient/NSDictionary+Typecheck.{h,m}" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/1.2.0/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "1.2.0", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.8" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "1.2.0" 16 | }, 17 | "requires_arc": true, 18 | "homepage": "https://www.xing.com", 19 | "default_subspecs": "Core", 20 | "subspecs": [ 21 | { 22 | "name": "Core", 23 | "source_files": "XNGAPIClient/*.{h,m}", 24 | "dependencies": { 25 | "SSKeychain": [ 26 | "~> 1.2.0" 27 | ], 28 | "XNGOAuth1Client": [ 29 | "~> 2.0.0" 30 | ] 31 | }, 32 | "frameworks": [ 33 | "Security", 34 | "SystemConfiguration" 35 | ] 36 | }, 37 | { 38 | "name": "NSDictionary-Typecheck", 39 | "source_files": "XNGAPIClient/NSDictionary+Typecheck.{h,m}" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015 XING AG 2 | 3 | MIT License 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 20 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /lib/updater/specs.rb: -------------------------------------------------------------------------------- 1 | require 'fileutils' 2 | 3 | class Specs 4 | attr_reader :path, :whitelist, :specs_root 5 | 6 | def initialize(path, whitelist = [], specs_root = '') 7 | @path = path 8 | @whitelist = whitelist 9 | @specs_root = File.join(@path, specs_root) 10 | end 11 | 12 | def pods 13 | @pods ||= traverse(@specs_root).flatten.map do |pod_path| 14 | pod = Pod.new(pod_path) 15 | @whitelist.any? && !@whitelist.include?(pod.name) ? nil : pod 16 | end.compact 17 | end 18 | 19 | def merge_pods(other_pods) 20 | other_pods.each do |pod| 21 | FileUtils.cp_r(pod.path, @path) 22 | end 23 | @pods = nil 24 | end 25 | 26 | def git 27 | @git ||= Git.new(@path) 28 | end 29 | 30 | private 31 | 32 | def traverse(working_dir) 33 | whitelist = %w{0 1 2 3 4 5 6 7 8 9 a b c d e f} 34 | pods = [] 35 | Dir.glob(File.join(working_dir, '*')).map do |dir| 36 | dir_name = dir.split(File::SEPARATOR).last 37 | if whitelist.include? dir_name 38 | pods << traverse(dir) 39 | else 40 | pods << dir 41 | end 42 | end 43 | pods 44 | end 45 | 46 | end 47 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/0.2.1/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "0.2.1", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.7" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "0.2.1" 16 | }, 17 | "requires_arc": true, 18 | "homepage": "https://www.xing.com", 19 | "default_subspec": "Core", 20 | "subspecs": [ 21 | { 22 | "name": "Core", 23 | "source_files": "XNGAPIClient/*.{h,m}", 24 | "dependencies": { 25 | "AFNetworking": [ 26 | "~> 1.3.0" 27 | ], 28 | "SSKeychain": [ 29 | "= 1.2.0" 30 | ], 31 | "AFOAuth1Client": [ 32 | "= 0.3.1" 33 | ] 34 | }, 35 | "frameworks": [ 36 | "Security", 37 | "SystemConfiguration" 38 | ] 39 | }, 40 | { 41 | "name": "NSDictionary-Typecheck", 42 | "source_files": "XNGAPIClient/NSDictionary+Typecheck.{h,m}" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/0.2.2/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "0.2.2", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.7" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "0.2.2" 16 | }, 17 | "requires_arc": true, 18 | "homepage": "https://www.xing.com", 19 | "default_subspecs": "Core", 20 | "subspecs": [ 21 | { 22 | "name": "Core", 23 | "source_files": "XNGAPIClient/*.{h,m}", 24 | "dependencies": { 25 | "AFNetworking": [ 26 | "~> 1.3.0" 27 | ], 28 | "SSKeychain": [ 29 | "~> 1.2.0" 30 | ], 31 | "AFOAuth1Client": [ 32 | "~> 0.3.1" 33 | ] 34 | }, 35 | "frameworks": [ 36 | "Security", 37 | "SystemConfiguration" 38 | ] 39 | }, 40 | { 41 | "name": "NSDictionary-Typecheck", 42 | "source_files": "XNGAPIClient/NSDictionary+Typecheck.{h,m}" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/0.3.0/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "0.3.0", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.7" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "0.3.0" 16 | }, 17 | "requires_arc": true, 18 | "homepage": "https://www.xing.com", 19 | "default_subspecs": "Core", 20 | "subspecs": [ 21 | { 22 | "name": "Core", 23 | "source_files": "XNGAPIClient/*.{h,m}", 24 | "dependencies": { 25 | "AFNetworking": [ 26 | "~> 1.3.0" 27 | ], 28 | "SSKeychain": [ 29 | "~> 1.2.0" 30 | ], 31 | "AFOAuth1Client": [ 32 | "~> 0.3.1" 33 | ] 34 | }, 35 | "frameworks": [ 36 | "Security", 37 | "SystemConfiguration" 38 | ] 39 | }, 40 | { 41 | "name": "NSDictionary-Typecheck", 42 | "source_files": "XNGAPIClient/NSDictionary+Typecheck.{h,m}" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/0.3.1/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "0.3.1", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.7" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "0.3.1" 16 | }, 17 | "requires_arc": true, 18 | "homepage": "https://www.xing.com", 19 | "default_subspecs": "Core", 20 | "subspecs": [ 21 | { 22 | "name": "Core", 23 | "source_files": "XNGAPIClient/*.{h,m}", 24 | "dependencies": { 25 | "AFNetworking": [ 26 | "~> 1.3.0" 27 | ], 28 | "SSKeychain": [ 29 | "~> 1.2.0" 30 | ], 31 | "AFOAuth1Client": [ 32 | "~> 0.3.1" 33 | ] 34 | }, 35 | "frameworks": [ 36 | "Security", 37 | "SystemConfiguration" 38 | ] 39 | }, 40 | { 41 | "name": "NSDictionary-Typecheck", 42 | "source_files": "XNGAPIClient/NSDictionary+Typecheck.{h,m}" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /spec/fixtures/specs/XNGAPIClient/0.4.0/XNGAPIClient.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "XNGAPIClient", 3 | "version": "0.4.0", 4 | "license": "MIT", 5 | "platforms": { 6 | "ios": "6.0", 7 | "osx": "10.7" 8 | }, 9 | "summary": "The official Objective-C client for the XING API", 10 | "authors": { 11 | "XING iOS Team": "iphonedev@xing.com" 12 | }, 13 | "source": { 14 | "git": "https://github.com/xing/XNGAPIClient.git", 15 | "tag": "0.4.0" 16 | }, 17 | "requires_arc": true, 18 | "homepage": "https://www.xing.com", 19 | "default_subspecs": "Core", 20 | "subspecs": [ 21 | { 22 | "name": "Core", 23 | "source_files": "XNGAPIClient/*.{h,m}", 24 | "dependencies": { 25 | "AFNetworking": [ 26 | "~> 1.3.0" 27 | ], 28 | "SSKeychain": [ 29 | "~> 1.2.0" 30 | ], 31 | "AFOAuth1Client": [ 32 | "~> 0.3.1" 33 | ] 34 | }, 35 | "frameworks": [ 36 | "Security", 37 | "SystemConfiguration" 38 | ] 39 | }, 40 | { 41 | "name": "NSDictionary-Typecheck", 42 | "source_files": "XNGAPIClient/NSDictionary+Typecheck.{h,m}" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | PATH 2 | remote: . 3 | specs: 4 | pod-synchronize (0.5.0) 5 | claide (~> 0.8.1) 6 | colored (~> 1.2) 7 | 8 | GEM 9 | remote: https://rubygems.org/ 10 | specs: 11 | claide (0.8.2) 12 | colored (1.2) 13 | coveralls (0.8.1) 14 | json (~> 1.8) 15 | rest-client (>= 1.6.8, < 2) 16 | simplecov (~> 0.10.0) 17 | term-ansicolor (~> 1.3) 18 | thor (~> 0.19.1) 19 | diff-lcs (1.2.5) 20 | docile (1.1.5) 21 | domain_name (0.5.24) 22 | unf (>= 0.0.5, < 1.0.0) 23 | http-cookie (1.0.2) 24 | domain_name (~> 0.5) 25 | json (1.8.2) 26 | mime-types (2.5) 27 | netrc (0.10.3) 28 | rake (10.4.2) 29 | rest-client (1.8.0) 30 | http-cookie (>= 1.0.2, < 2.0) 31 | mime-types (>= 1.16, < 3.0) 32 | netrc (~> 0.7) 33 | rspec (3.2.0) 34 | rspec-core (~> 3.2.0) 35 | rspec-expectations (~> 3.2.0) 36 | rspec-mocks (~> 3.2.0) 37 | rspec-core (3.2.3) 38 | rspec-support (~> 3.2.0) 39 | rspec-expectations (3.2.1) 40 | diff-lcs (>= 1.2.0, < 2.0) 41 | rspec-support (~> 3.2.0) 42 | rspec-mocks (3.2.1) 43 | diff-lcs (>= 1.2.0, < 2.0) 44 | rspec-support (~> 3.2.0) 45 | rspec-support (3.2.2) 46 | simplecov (0.10.0) 47 | docile (~> 1.1.0) 48 | json (~> 1.8) 49 | simplecov-html (~> 0.10.0) 50 | simplecov-html (0.10.0) 51 | term-ansicolor (1.3.0) 52 | tins (~> 1.0) 53 | thor (0.19.1) 54 | tins (1.5.1) 55 | unf (0.1.4) 56 | unf_ext 57 | unf_ext (0.0.7.1) 58 | 59 | PLATFORMS 60 | ruby 61 | 62 | DEPENDENCIES 63 | bundler (~> 1.7) 64 | coveralls 65 | pod-synchronize! 66 | rake (~> 10.0) 67 | rspec 68 | 69 | BUNDLED WITH 70 | 1.15.1 71 | -------------------------------------------------------------------------------- /spec/version_spec.rb: -------------------------------------------------------------------------------- 1 | describe Version do 2 | before :all do 3 | @path_to_version_dir = File.join('spec', 'fixtures', 'specs', 'XNGAPIClient', '1.2.0') 4 | end 5 | 6 | describe '::new' do 7 | it 'initializes with a versions dir' do 8 | version = Version.new(@path_to_version_dir) 9 | 10 | expect(version.path).to eql(@path_to_version_dir) 11 | end 12 | end 13 | 14 | describe '#podspec_path' do 15 | it 'gets the corred podspec filepath' do 16 | version = Version.new(@path_to_version_dir) 17 | expected_path = File.join(@path_to_version_dir, 'XNGAPIClient.podspec.json') 18 | actual_path = version.send(:podspec_path) 19 | expect(actual_path).to eql(expected_path) 20 | end 21 | end 22 | 23 | describe '#contents' do 24 | it 'gets the fetches the podspec correctly' do 25 | version = Version.new(@path_to_version_dir) 26 | expected_contents = { 27 | "name"=>"XNGAPIClient", 28 | "version"=>"1.2.0", 29 | "license"=>"MIT", 30 | "platforms"=>{"ios"=>"6.0", 31 | "osx"=>"10.8"}, "summary"=>"The official Objective-C client for the XING API", 32 | "authors"=>{"XING iOS Team"=>"iphonedev@xing.com"}, "source"=>{"git"=>"https://github.com/xing/XNGAPIClient.git", 33 | "tag"=>"1.2.0"}, "requires_arc"=>true, "homepage"=>"https://www.xing.com", 34 | "default_subspecs"=>"Core", 35 | "subspecs"=>[{"name"=>"Core", 36 | "source_files"=>"XNGAPIClient/*.{h,m}", 37 | "dependencies"=>{"SSKeychain"=>["~> 1.2.0"], "XNGOAuth1Client"=>["~> 2.0.0"]}, "frameworks"=>["Security", 38 | "SystemConfiguration"]}, {"name"=>"NSDictionary-Typecheck", 39 | "source_files"=>"XNGAPIClient/NSDictionary+Typecheck.{h,m}"}] 40 | } 41 | 42 | expect(version.contents).to eql(expected_contents) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/pod_spec.rb: -------------------------------------------------------------------------------- 1 | describe Pod do 2 | before :all do 3 | @path_to_podspecs_dir = File.join('spec', 'fixtures', 'specs', 'XNGAPIClient') 4 | end 5 | 6 | describe '::new' do 7 | it 'init with podspec dir' do 8 | class_under_test = Pod.new(@path_to_podspecs_dir) 9 | expect(class_under_test.path).to eql(@path_to_podspecs_dir) 10 | end 11 | end 12 | 13 | describe '#name' do 14 | it 'gets the correct pod name' do 15 | class_under_test = Pod.new(@path_to_podspecs_dir) 16 | expect(class_under_test.name).to eql("XNGAPIClient") 17 | end 18 | end 19 | 20 | describe '#source' do 21 | it 'gets the correct source url' do 22 | class_under_test = Pod.new(@path_to_podspecs_dir) 23 | expect(class_under_test.git_source).to eql("https://github.com/xing/XNGAPIClient.git") 24 | end 25 | end 26 | 27 | describe '#versions' do 28 | it 'should return all versions for that pod' do 29 | class_under_test = Pod.new(@path_to_podspecs_dir) 30 | versions = class_under_test.versions 31 | expected_versions = [ 32 | '0.1.0', '0.2.0', '0.2.1', '0.2.2', '0.3.0', '0.3.1', 33 | '0.4.0', '1.0.0', '1.1.0', '1.1.1', '1.2.0' 34 | ] 35 | 36 | actual_versions = versions.map(&:version) 37 | expect(actual_versions.sort).to eql(expected_versions.sort) 38 | end 39 | end 40 | 41 | describe '#git' do 42 | it 'should add the pod path as the default git path' do 43 | class_under_test = Pod.new(@path_to_podspecs_dir) 44 | expect(class_under_test.git.path).to eql(@path_to_podspecs_dir) 45 | end 46 | 47 | it 'should be able to set a custom path' do 48 | class_under_test = Pod.new(@path_to_podspecs_dir) 49 | expected_path = "./some/other/path" 50 | class_under_test.git.path = expected_path 51 | expect(class_under_test.git.path).to eql(expected_path) 52 | end 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /spec/specs_spec.rb: -------------------------------------------------------------------------------- 1 | describe Specs do 2 | 3 | before :all do 4 | @specs_path = File.join('spec', 'fixtures', 'specs') 5 | @other_specs_path = File.join('spec', 'fixtures', 'specs_other') 6 | end 7 | 8 | describe '::new' do 9 | it 'should init with a path' do 10 | class_under_test = Specs.new(@specs_path) 11 | expect(class_under_test.path).to eql(@specs_path) 12 | end 13 | end 14 | 15 | describe '#pods' do 16 | it 'should fetch all pods' do 17 | class_under_test = Specs.new(@specs_path) 18 | expect(class_under_test.pods.count).to eql(3) 19 | expect(class_under_test.pods.map(&:name)).to eql(['NBNRealmBrowser', 'XNGAPIClient', 'XNGOAuth1Client']) 20 | end 21 | 22 | it 'should fetch 1 pod from whitelist' do 23 | class_under_test = Specs.new(@specs_path, ['XNGAPIClient']) 24 | expect(class_under_test.pods.count).to eql(1) 25 | expect(class_under_test.pods.map(&:name)).to eql(['XNGAPIClient']) 26 | end 27 | 28 | it 'should fetch 2 pods from whitelist' do 29 | class_under_test = Specs.new(@specs_path, ['XNGAPIClient', 'XNGOAuth1Client']) 30 | expect(class_under_test.pods.count).to eql(2) 31 | expect(class_under_test.pods.map(&:name)).to eql(['XNGAPIClient', 'XNGOAuth1Client']) 32 | end 33 | 34 | it 'should fetch no pods that are not on the whitelist' do 35 | class_under_test = Specs.new(@specs_path, ['PodThatDoesntExist']) 36 | expect(class_under_test.pods.count).to eql(0) 37 | end 38 | end 39 | 40 | describe '#merge_pods' do 41 | it 'should add all pods from one spec to another' do 42 | specs = Specs.new(@specs_path) 43 | other_specs = Specs.new(@other_specs_path, ['NBNPhotoChooser']) 44 | expected_path = File.join(@other_specs_path, 'NBNPhotoChooser') 45 | 46 | expect(FileUtils).to receive(:cp_r).with(expected_path, specs.path) 47 | specs.merge_pods(other_specs.pods) 48 | end 49 | end 50 | 51 | end 52 | -------------------------------------------------------------------------------- /spec/git_spec.rb: -------------------------------------------------------------------------------- 1 | describe Git do 2 | describe Specs do 3 | 4 | before :all do 5 | @specs_path = File.join('spec', 'fixtures', 'specs') 6 | @specs = Specs.new(@specs_path) 7 | end 8 | 9 | describe "::commit" do 10 | it 'commits with a message' do 11 | class_under_test = @specs.git 12 | 13 | message = "Become a programmer, they said. It'll be fun, they said." 14 | expect(class_under_test).to receive(:system).with("git add --all") 15 | expect(class_under_test).to receive(:system).with("git commit -m '#{message}'") 16 | class_under_test.commit(message) 17 | end 18 | end 19 | 20 | describe "::create_github_repo" do 21 | it 'creates a github repo' do 22 | class_under_test = @specs.git 23 | expect(class_under_test).to receive(:system).with("curl https://github.com/api/v3/orgs/ios-pods-external/repos?access_token=123 -d '{\"name\":\"mega-pod\"}'") 24 | class_under_test.create_github_repo( 25 | '123', 26 | 'ios-pods-external', 27 | 'mega-pod', 28 | 'https://github.com/api/v3' 29 | ) 30 | end 31 | end 32 | 33 | describe "::push" do 34 | it 'push on default remote "origin master"' do 35 | class_under_test = @specs.git 36 | expect(class_under_test).to receive(:system).with("git push origin master") 37 | class_under_test.push 38 | end 39 | 40 | it 'push on custom remote "production"' do 41 | class_under_test = @specs.git 42 | expect(class_under_test).to receive(:system).with("git push production") 43 | class_under_test.push('production') 44 | end 45 | 46 | it 'push on custom remote with options' do 47 | class_under_test = @specs.git 48 | expect(class_under_test).to receive(:system).with("git push develop --force") 49 | class_under_test.push('develop', '--force') 50 | end 51 | 52 | it 'push on default remote with options' do 53 | class_under_test = @specs.git 54 | expect(class_under_test).to receive(:system).with("git push origin master --force") 55 | class_under_test.push('origin master', '--force') 56 | end 57 | end 58 | end 59 | 60 | end 61 | -------------------------------------------------------------------------------- /spec/configuration_spec.rb: -------------------------------------------------------------------------------- 1 | describe Configuration do 2 | 3 | describe "#initialize" do 4 | it "loads the yaml config at the specified path" do 5 | config = Configuration.new(File.join('spec', 'fixtures', 'config.yml')) 6 | expect(config.yaml).to_not be_empty 7 | end 8 | 9 | it "throws an exception if the file at the path does not exist" do 10 | expect { Configuration.new('invalid/path') }.to raise_exception 11 | end 12 | end 13 | 14 | before :all do 15 | @config = Configuration.new('spec/fixtures/config.yml') 16 | end 17 | 18 | it '#master_repo should exist' do 19 | expect(@config.master_repo).to eql("https://github.com/CocoaPods/Specs.git") 20 | end 21 | 22 | describe '#podfiles' do 23 | it 'should parse the podfiles correctly' do 24 | expected_result = [ 25 | "https://git.hooli.xyz/ios/moonshot/raw/master/Podfile.lock", 26 | "https://git.hooli.xyz/ios/nucleus/raw/master/Podfile.lock", 27 | "https://git.hooli.xyz/ios/bro2bro/raw/master/Podfile.lock"] 28 | expect(@config.podfiles).to eql(expected_result) 29 | end 30 | end 31 | 32 | describe '#pods' do 33 | it 'should parse the pods correctly' do 34 | expected_result = ["Google-Mobile-Ads-SDK"] 35 | expect(@config.pods).to eql(expected_result) 36 | end 37 | end 38 | 39 | describe '#excluded_pods' do 40 | it 'should parse the excluded_pods list correctly' do 41 | expected_result = ["BABCropperView"] 42 | expect(@config.excluded_pods).to eql(expected_result) 43 | end 44 | end 45 | 46 | describe "#mirror" do 47 | it 'should have the correct @specs_push_url' do 48 | expect(@config.mirror.specs_push_url).to eql("git@git.hooli.xyz:pods-mirror/Specs.git") 49 | end 50 | 51 | it 'should have the correct @source_push_url' do 52 | expect(@config.mirror.source_push_url).to eql("git@git.hooli.xyz:pods-mirror") 53 | end 54 | 55 | it 'should have the correct @source_clone_url' do 56 | expect(@config.mirror.source_clone_url).to eql("git://git.hooli.xyz/pods-mirror") 57 | end 58 | 59 | describe '#github' do 60 | it 'should have the correct @source_clone_url' do 61 | expect(@config.mirror.github.access_token).to eql("0y83t1ihosjklgnuioa") 62 | end 63 | 64 | it 'should have the correct @organisation' do 65 | expect(@config.mirror.github.organisation).to eql("pods-mirror") 66 | end 67 | 68 | it 'should have the correct @endpoint' do 69 | expect(@config.mirror.github.endpoint).to eql("https://git.hooli.xyz/api/v3") 70 | end 71 | end 72 | end 73 | 74 | end 75 | -------------------------------------------------------------------------------- /lib/updater/synchronize.rb: -------------------------------------------------------------------------------- 1 | require 'open-uri' 2 | require 'openssl' 3 | 4 | module PodSynchronize 5 | class Command 6 | class Synchronize < Command 7 | self.command = 'synchronize' 8 | self.summary = 'Synchronize the public CocoaPods repository with your mirror' 9 | 10 | self.arguments = [ 11 | CLAide::Argument.new('CONFIG', :true), 12 | ] 13 | 14 | def initialize(argv) 15 | @yml_path = argv.shift_argument 16 | end 17 | 18 | def validate! 19 | raise Informative, "Please specify a valid CONFIG path" unless @yml_path 20 | end 21 | 22 | def setup(temp_path) 23 | @config = Configuration.new(@yml_path) 24 | @master_specs = Specs.new(File.join(temp_path, 'master'), dependencies, 'Specs') 25 | @internal_specs = Specs.new(File.join(temp_path, 'local'), [], '.') 26 | end 27 | 28 | def bootstrap 29 | @internal_specs.git.clone(@config.mirror.specs_push_url) 30 | @master_specs.git.clone(@config.master_repo, '. --depth 1') 31 | end 32 | 33 | def update_specs 34 | @internal_specs.merge_pods(@master_specs.pods) 35 | 36 | @internal_specs.pods.each do |pod| 37 | pod.versions.each do |version| 38 | if version.contents["source"]["git"] 39 | version.contents["source"]["git"] = "#{@config.mirror.source_clone_url}/#{pod.name}.git" 40 | end 41 | end 42 | pod.save 43 | end 44 | @internal_specs.git.commit(commit_message) 45 | @internal_specs.git.push 46 | end 47 | 48 | def commit_message 49 | time_str = Time.now.strftime('%c') 50 | "Update #{time_str}" 51 | end 52 | 53 | def update_sources(temp_path) 54 | @master_specs.pods.each do |pod| 55 | pod.git.path = File.join(temp_path, 'source_cache', pod.name) 56 | pod.git.clone(pod.git_source, ". --bare") 57 | pod.git.create_github_repo( 58 | @config.mirror.github.access_token, 59 | @config.mirror.github.organisation, 60 | pod.name, 61 | @config.mirror.github.endpoint 62 | ) 63 | pod.git.set_origin("#{@config.mirror.source_push_url}/#{pod.name}.git") 64 | pod.git.push(nil, '--mirror') 65 | end 66 | end 67 | 68 | def dependencies 69 | pods_dependencies = [] 70 | 71 | @config.podfiles.each do |podfile| 72 | podfile_contents = open(podfile, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}) { |io| io.read } 73 | pods_dependencies << YAML.load(podfile_contents)["SPEC CHECKSUMS"].keys 74 | end 75 | pods_dependencies << @config.pods 76 | 77 | pods_dependencies.flatten!.uniq! 78 | 79 | pods_dependencies.reject! { |dependency| @config.excluded_pods.include? dependency } unless @config.excluded_pods.nil? 80 | 81 | pods_dependencies 82 | end 83 | 84 | def run 85 | Dir.mktmpdir do |dir| 86 | self.setup(dir) 87 | self.bootstrap 88 | self.update_specs 89 | self.update_sources(dir) 90 | end 91 | end 92 | end 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XNGPodSynchronizer 2 | 3 | [![Build Status](https://travis-ci.org/xing/XNGPodsSynchronizer.svg?branch=master)](https://travis-ci.org/xing/XNGPodSynchronizer) 4 | [![Coverage Status](https://coveralls.io/repos/xing/XNGPodsSynchronizer/badge.svg?branch=master)](https://coveralls.io/r/xing/XNGPodSynchronizer?branch=master) 5 | 6 | XNGPodSynchronizer reads `Podfile.locks` of your projects, copies the `.podspec`s from the CocoaPods master repository and mirrors it to your own `git` repository (e.g. GitHub Enterprise). This helps you get independent from `github.com` and avoids the need of cloning the full CocoaPods master repository, which might speed up your builds on CI. 7 | 8 | ## Installation 9 | 10 | XNGPodSynchronizer is distributed as a Ruby gem and can be installed using the following command: 11 | 12 | ```bash 13 | $ gem install pod-synchronize 14 | ``` 15 | 16 | ## Usage 17 | 18 | XNGPodSynchronizer takes a `config.yml` as an argument an example `Yaml` would look like this: 19 | 20 | ```yaml 21 | # config.yml 22 | --- 23 | master_repo: https://github.com/CocoaPods/Specs.git 24 | mirror: 25 | specs_push_url: git@git.hooli.xyz:pods-mirror/Specs.git 26 | source_push_url: git@git.hooli.xyz:pods-mirror 27 | source_clone_url: git://git.hooli.xyz/pods-mirror 28 | github: 29 | acccess_token: 0y83t1ihosjklgnuioa 30 | organisation: pods-mirror 31 | endpoint: https://git.hooli.xyz/api/v3 32 | podfiles: 33 | - "https://git.hooli.xyz/ios/moonshot/raw/master/Podfile.lock" 34 | - "https://git.hooli.xyz/ios/nucleus/raw/master/Podfile.lock" 35 | - "https://git.hooli.xyz/ios/bro2bro/raw/master/Podfile.lock" 36 | pods: 37 | - Google-Mobile-Ads-SDK 38 | exclude: 39 | - BABCropperView 40 | ``` 41 | 42 | |key|meaning| 43 | |:----|:----| 44 | |master_repo|CocoaPods master repository (usually: https://github.com/CocoaPods/Specs.git)| 45 | |mirror.specs_push_url|Git URL used to clone & push the mirrored specs| 46 | |mirror.source_push_url|Git URL used to push the mirrored repositories| 47 | |mirror.source_clone_url|Git URL used to change the download URLs in the podspecs| 48 | |mirror.github.access_token|Access token used to create new repositories| 49 | |mirror.github.organisation|The GitHub organization used for mirrored repositories| 50 | |mirror.github.endpoint|API Endpoint of your GitHub api| 51 | |podfiles|List of __Podfile.lock__ in __Plain Text__ format| 52 | |pods|List of additional Pods you would like to add| 53 | |exclude|List of Pods you would like to exclude| 54 | 55 | We use Jenkins to run the synchronize process twice daily. To do that use the following command: 56 | 57 | ``` 58 | $ pod-synchronize synchronize config.yml 59 | ``` 60 | 61 | ## Known issues 62 | 63 | At the moment this gem only handles `git` [sources](https://guides.cocoapods.org/syntax/podspec.html#source) correctly. `HTTP` sources are partly supported (see [#12](https://github.com/xing/XNGPodsSynchronizer/pull/12)) and `svn`, `hg` support is missing. 64 | 65 | ## TODO 66 | 67 | * Support Gitlab [#1](https://github.com/xing/XNGPodSynchronizer/issue/1) 68 | 69 | ## Contributing 70 | 71 | 1. Fork it ( https://github.com/xing/XNGPodSynchronizer/fork ) 72 | 2. Create your feature branch (`git checkout -b my-new-feature`) 73 | 3. Commit your changes (`git commit -am 'Add some feature'`) 74 | 4. Push to the branch (`git push origin my-new-feature`) 75 | 5. Create a new Pull Request 76 | 77 | ## Authors 78 | 79 | [Matthias Männich](https://github.com/matthias-maennich) and [Piet Brauer](https://github.com/pietbrauer) 80 | 81 | Copyright (c) 2015 [XING AG](https://xing.com/) 82 | 83 | Released under the MIT license. For full details see LICENSE included in this distribution. 84 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'coveralls' 2 | Coveralls.wear! 3 | 4 | require 'pathname' 5 | ROOT = Pathname.new(File.expand_path('../../', __FILE__)) 6 | $:.unshift((ROOT + 'lib').to_s) 7 | $:.unshift((ROOT + 'spec').to_s) 8 | 9 | require 'bundler/setup' 10 | require 'updater' 11 | 12 | # This file was generated by the `rspec --init` command. Conventionally, all 13 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 14 | # The generated `.rspec` file contains `--require spec_helper` which will cause 15 | # this file to always be loaded, without a need to explicitly require it in any 16 | # files. 17 | # 18 | # Given that it is always loaded, you are encouraged to keep this file as 19 | # light-weight as possible. Requiring heavyweight dependencies from this file 20 | # will add to the boot time of your test suite on EVERY test run, even for an 21 | # individual file that may not need all of that loaded. Instead, consider making 22 | # a separate helper file that requires the additional dependencies and performs 23 | # the additional setup, and require it from the spec files that actually need 24 | # it. 25 | # 26 | # The `.rspec` file also contains a few flags that are not defaults but that 27 | # users commonly want. 28 | # 29 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 30 | RSpec.configure do |config| 31 | # rspec-expectations config goes here. You can use an alternate 32 | # assertion/expectation library such as wrong or the stdlib/minitest 33 | # assertions if you prefer. 34 | config.expect_with :rspec do |expectations| 35 | # This option will default to `true` in RSpec 4. It makes the `description` 36 | # and `failure_message` of custom matchers include text for helper methods 37 | # defined using `chain`, e.g.: 38 | # be_bigger_than(2).and_smaller_than(4).description 39 | # # => "be bigger than 2 and smaller than 4" 40 | # ...rather than: 41 | # # => "be bigger than 2" 42 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 43 | end 44 | 45 | # rspec-mocks config goes here. You can use an alternate test double 46 | # library (such as bogus or mocha) by changing the `mock_with` option here. 47 | config.mock_with :rspec do |mocks| 48 | # Prevents you from mocking or stubbing a method that does not exist on 49 | # a real object. This is generally recommended, and will default to 50 | # `true` in RSpec 4. 51 | mocks.verify_partial_doubles = true 52 | end 53 | 54 | # The settings below are suggested to provide a good initial experience 55 | # with RSpec, but feel free to customize to your heart's content. 56 | =begin 57 | # These two settings work together to allow you to limit a spec run 58 | # to individual examples or groups you care about by tagging them with 59 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 60 | # get run. 61 | config.filter_run :focus 62 | config.run_all_when_everything_filtered = true 63 | 64 | # Limits the available syntax to the non-monkey patched syntax that is 65 | # recommended. For more details, see: 66 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 67 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 68 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 69 | config.disable_monkey_patching! 70 | 71 | # This setting enables warnings. It's recommended, but in some cases may 72 | # be too noisy due to issues in dependencies. 73 | config.warnings = true 74 | 75 | # Many RSpec users commonly either run the entire suite or an individual 76 | # file, and it's useful to allow more verbose output when running an 77 | # individual spec file. 78 | if config.files_to_run.one? 79 | # Use the documentation formatter for detailed output, 80 | # unless a formatter has already been configured 81 | # (e.g. via a command-line flag). 82 | config.default_formatter = 'doc' 83 | end 84 | 85 | # Print the 10 slowest examples and example groups at the 86 | # end of the spec run, to help surface which specs are running 87 | # particularly slow. 88 | config.profile_examples = 10 89 | 90 | # Run specs in random order to surface order dependencies. If you find an 91 | # order dependency and want to debug it, you can fix the order by providing 92 | # the seed, which is printed after each run. 93 | # --seed 1234 94 | config.order = :random 95 | 96 | # Seed global randomization in this process using the `--seed` CLI option. 97 | # Setting this allows you to use `--seed` to deterministically reproduce 98 | # test failures related to randomization by passing the same `--seed` value 99 | # as the one that triggered the failure. 100 | Kernel.srand config.seed 101 | =end 102 | end 103 | --------------------------------------------------------------------------------