Skip to content

Instantly share code, notes, and snippets.

@orta
Forked from mtitolo/contributing.md
Last active December 16, 2015 17:48
Show Gist options
  • Save orta/5472707 to your computer and use it in GitHub Desktop.
Save orta/5472707 to your computer and use it in GitHub Desktop.

How can I contribute?

Picking Up Issues

####Issue Classifications

  • Defect: These are known bugs. The issue should also contain steps to reproduce. Feel free to fix these and submit a pull request.
  • Enhancement: These are planned enhancements that have not been picked up yet. If you would like to work on one, please add a comment that you are doing so.
  • Discussion: These are issues that can be non-issues, and encompass best practices, or plans for the future.
  • Quick: These are small issues, that should be able to be fixed quickly. Normally these issues don't stay around for very long.
  • To check: These issues may not be reproduceable, or have not been vetted by a team member.
  • Workaround known: These issues have had their solutions discussed, but have yet to be implemented.

####Making the Pull Request

Before submitting your pull request, please do the following:

  1. Run rake spec and make sure all the tests pass. If you are adding new commands or features, they must include tests. If you are changing functionality, update the tests if you need to.
  2. Add a note to the changelog describing what you changed.
  3. Make your pull request. If it is related to an issue, add a link to the issue in the description.

TODO:

  • Code Style
  • Documentation Style

What are the main components?

CocoaPods

The CocoaPods gem which includes the command line support and the installer.

Cocoapods-core

The CocoaPods-Core gem provides support to work with the models of CocoaPods.

Xcodeproj

Xcodeproj lets you create and modify Xcode projects from Ruby. Script boring management tasks or build Xcode-friendly libraries. Also includes support for Xcode workspaces (.xcworkspace) and configuration files (.xcconfig).

Cocoapods-downloader

A small library that provides downloaders for various source types (HTTP/SVN/Git/Mercurial).

CLAide

I was born out of a need for a simple option and command parser, while still providing an API that allows you to quickly create a full featured command-line interface.

How does the Specs Repo work?

To ensure a high quality, reliable collection of Pods, the master repo is strict about the acceptable specifications. The CocoaPods linter (see the pod spec lint command) is used to validate specifications, and no errors or warnings are accepted.

The highest priority of the master repo is to guarantee the integrity of existing CocoaPods installations.

In general this means that:

  • A specification cannot be deleted.
  • Specifications can be updated only if they don't affect existing installations.
    • Broken specifications can be updated.
    • Subspecs can be added as they are included by the parent specification by default.
  • Only authoritative versions are accepted.

CocoaPods uses a versioning scheme known as Semantic Versioning, necessary for cross resolution of dependencies.

How do I update an existing Pod?

TODO

How do I create a new Pod?

The following file structure is suggested:

.
├── Classes
    └── ios
    └── osx
├── Resources
├── Project
    └── Podfile
├── LICENSE
├── Readme.markdown
└── NAME.podspec

The suggested Project/Podfile

 platform :ios
#platform :osx

 podspec :path => "../NAME.podspec"

The podspec is a shortcut to require all the dependencies specified in NAME.podspec.

Development

You can work on the library from its project. Alternatively you can work from an application project using the :path option:

pod 'Name', :path => '~/code/Pods/NAME.podspec'

You can also lint the pod against the files of its directory:

$ cd ~/code/Pods/NAME
$ pod spec lint --local

Release

The release workflow can be the following.

$ cd ~/code/Pods/NAME
$ edit NAME.podspec
# set the new version to 0.0.1
# set the new tag to 0.0.1
$ pod spec lint --local

$ git add -A && git commit -m "Release 0.0.1."
$ git tag '0.0.1'
$ git push --tags
$ pod push master

You can also simplify the podspec to skip a step:

 s.version = '1.0.0'
 s.source = { :git => "https://example.com/repo.git", :tag => s.version.to_s }
#s.source = { :git => "https://example.com/repo.git", :tag => "v#{s.version}" }

Creating a Pod repo

A specification repository is a simple collection of podspec files organized with the following structure:

NAME/VERSION/NAME.podspec
$ cd ~/.cocoapods/master
$ tree | head
.
└── A2DynamicDelegate
    └── 1.0
        └── A2DynamicDelegate.podspec
        1.0.1
        └── A2DynamicDelegate.podspec
        1.0.2
        └── A2DynamicDelegate.podspec
        1.0.3
        └── A2DynamicDelegate.podspec

Although the master repo is backed by a git repository, this is not required. For a repository to be valid it is only required to respect the above described file structure.

CocoaPods stores its repositories in the ~/.cocoapods/ folder.

Adding a new repo

Manually
  1. Make a folder with the name of the repo in ~/.cocoapods/.
  2. Populate the repository with podspecs respecting the required folder structure.
From an existing git remote

If you want to create a git backed repository you can use the $ pod repo add command.

Disambiguation

If during the installation process is resolved a Pod whose required version is present in more than one repository, the alphabetical order of the names is used to disambiguate.

TODO:

  • How do I podify an existing project?
  • How do I test the new Pod
  • Local Pods?

Versioning

There is, unfortunately, often an issue of developers not interpreting version numbers well or assigning emotional value to certain version numbers.

However, arbitrary revisions as version is not a good idea for a library manager instead of a proper version number (see Semantic Versioning). Let us explain how, in an ideal world, we’d prefer people to interact with it:

  • “I want to start using CocoaLumberjack, the current version will be fine for now.” So the dev adds a dependency on the lib without a version requirement and lets the manager install it which will use the latest version:

      pod 'CocoaLumberjack'
    
  • Some time into the future, the dev wants to update the dependencies, and to do so runs the install command again, which will now install the version of the lib which is the latest version at that time.

  • At some point the dev is finished on the client work (or a newer version of the lib changes the API and the changes aren’t needed) so the dev adds a version requirement to the dependency. For instance, consider that the author of the lib follows the semver guidelines, you can somewhat trust that between ‘1.0.7’ and ‘1.1.0’ no API changes will be made, but only bug fixes. So instead of requiring a specific version, the dev can specify that any ‘1.0.x’ is allowed as long as it’s higher than ‘1.0.7’:

      pod 'CocoaLumberjack', '~> 1.0.7'
    

The point is that developers can easily keep track of newer versions of dependencies, by simply running pod install again, which they might otherwise do less if they had to change everything manually.

CocoaPods Versioning Specifics

CocoaPods uses RubyGems versions for specifying pod spec versions. The RubyGems Versioning Policies describes the rules used for interpreting version numbers. The RubyGems version specifiers describes exactly how to use the comparison operators that specify dependency versions.

Following the pattern established in RubyGems, pre-release versions can also be specified in CocoaPods. A pre-release of version 1.2, for example, can be specified by '1.2.beta.3'. In this example, the dependency specifier '~> 1.2.beta' will match '1.2.beta.3'.

Documenting a Pod

TODO

Where can I ask questions?

TODO: Mailing List | Announcements and support. Feel free to ask any kind of question.

I want to create a private repository

TODO

What are CocoaPods

CocoaPods manages library dependencies for your Xcode project.

The dependencies for your project are specified in a single text file. CocoaPods resolves dependencies between libraries, fetches the source code, and creates and maintains an Xcode workspace to build your project.

Ultimately the goal is to improve discoverability of, and engagement in, third party open-source libraries by creating a more centralized ecosystem.

Installing CocoaPods

Dependencies

  • Ruby MRI 2.0.0 or 1.8.7 (ships with Mac OS X)
  • Xcode command line tools.

Installation

To install CocoaPods you can run:

$ [sudo] gem install cocoapods

To enjoy performance benefits you can install a modern Ruby like 2.0.0 through a Ruby version manager like RVM. If you are using RVM, or equivalent, we suggest not using sudo as it may have some unintended effects on other parts of your system.

Updating CocoaPods

To update CocoaPods you can run:

$ [sudo] gem update cocoapods

If you would like to try a pre-release version of CocoaPods you can run:

$ [sudo] gem update cocoapods --pre

Troubleshooting

  • The gem might not be able to compile, to solve this you might need to symlink GCC.

  • If you used an pre release version of Xcode you might need to update the command line tools.

  • CocoaPods is not compatible with MacRuby.

What is a Podfile?

The Podfile is a specification that describes the dependencies of the targets of one or more Xcode projects. The Podfile always creates an implicit target, named default, which links to the first target of the user project.

A podfile can be very simple:

 pod 'AFNetworking', '~> 1.0'

An example of a more complex podfile can be:

 platform :ios, '6.0'
 inhibit_all_warnings!

 xcodeproj `MyProject`

 pod 'ObjectiveSugar', '~> 0.5'

 target :test do
   pod 'OCMock', '~> 2.0.1'
 end

 post_install do |installer|
   installer.project.targets.each do |target|
     puts "#{target.name}"
   end
 end

When starting out with a project it is likely that you will want to use the latest version of a Pod. If this is the case, simply omit the version requirements.

pod 'SSZipArchive'

Later on in the project you may want to freeze to a specific version of a Pod, in which case you can specify that version number.

pod 'Objection', '0.9'

Besides no version, or a specific one, it is also possible to use operators:

  • > 0.1 Any version higher than 0.1
  • >= 0.1 Version 0.1 and any higher version
  • < 0.1 Any version lower than 0.1
  • <= 0.1 Version 0.1 and any lower version
  • ~> 0.1.2 Version 0.1.2 and the versions up to 0.2, not including 0.2

A list of version requirements can be specified for even more fine grained control.

For more information, regarding versioning policy, see:

Finally, instead of a version, you can specify the :head flag. This will use the pod’s latest version spec version, but force the download of the ‘bleeding edge’ version. Use this with caution, as the spec might not be compatible anymore.

pod 'Objection', :head

Using the files from a folder local to the machine.

If you wold like to use develop a Pod in tandem with its client project you can use the local option.

pod 'AFNetworking', :path => '~/Documents/AFNetworking'

Using this option CocoaPods will assume the given folder to be the root of the Pod and will link the files directly from there in the Pods project. This means that your edits will persist to CocoaPods installations.

The referenced folder can be a checkout of your your favorite SCM or even a git submodule of the current repo.

Note that the podspec of the Pod file is expected to be in the folder.

From a podspec in the root of a library repo.

Sometimes you may want to use the bleeding edge version of a Pod. Or a specific revision. If this is the case, you can specify that with your pod declaration.

To use the master branch of the repo:

pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git'

Or specify a commit:

pod 'AFNetworking', :git => 'https://github.com/gowalla/AFNetworking.git', :commit => '082f8319af'

It is important to note, though, that this means that the version will have to satisfy any other dependencies on the Pod by other Pods.

The podspec file is expected to be in the root of the repo, if this library does not have a podspec file in its repo yet, you will have to use one of the approaches outlined in the sections below.

Integrating with an Xcode project

Before you begin

  1. Check the Specs repository to make sure the libraries you would like to use are available.
  2. [Install CocoaPods on your computer][installing-cocoapods].

Installation

  1. Create a [Podfile][podfile], and add your dependencies:
    pod 'AFNetworking', '~> 1.0'  
    pod 'ObjectiveSugar', '~> 0.5'
  1. Run $ pod install in your project directory.
  2. Open App.xcworkspace and build.

TODO:

  • How do I start a new project with Cocoapods?
  • How do I add Cocoapods to my existing project that already uses a workspace?

Should I check in my pods folder?

TODO

What is a Podfile.lock

This file keeps track of what version of a Pod is installed. For example the following dependency might install RestKit 0.10.3:

pod 'RestKit'

Thanks to the Podfile.lock every machine which runs pod install on the hypothetical project will use RestKit 0.10.3 even if a newer version is available. CocoaPods will honor this version unless the dependency is updated on the Podfile or pod update is called. In this way CocoaPods avoids headaches caused by unexpected changes to dependencies.

This file should always be kept under version control.

What is happening behind the scenes?

In Xcode, it:

  1. [Creates or updates a workspace.][creating-a-workspace]
  2. [Adds your project to the workspace if needed.][adding-projects-to-workspace]
  3. [Adds the CocoaPods static library project to the workspace if needed.][adding-projects-to-workspace]
  4. [Adds libPods.a to: targets => build phases => link with libraries.][adding-build-target-dependencies]
  5. Adds the CocoaPods Xcode configuration file to your app’s project.
  6. [Changes your app's target configurations to be based on CocoaPods's.][basing-target-configurations-on-xcconfig] (Expand the ‘To add a new build configuration…’ section of the linked page for a howto.)
  7. Adds a build phase to copy resources from any pods you installed to your app bundle. i.e. a ‘Script build phase’ after all other build phases with the following:
  • Shell: /bin/sh
  • Script: ${SRCROOT}/Pods/PodsResources.sh

Note that steps 3 onwards are skipped if the CocoaPods static library is already in your project.

This is largely based on http://blog.carbonfive.com/2011/04/04/using-open-source-static-libraries-in-xcode-4.

CocoaPods Philosophy

Goal

CocoaPods' goal is to improve discoverability of, and engagement in, third party open-source libraries, by creating a more centralized ecosystem.

Common Misconceptions

1. “CocoaPods is not ready for prime-time yet.”

Correct. Version 1.0.0 will be the milestone where we feel confident that all the basic requirements of an Objective-C dependency manager are fulfilled.

Once we reach the 1.0.0 milestone, we will, for the first time ever, contact the community at large through mailing-lists such as cocoa-dev.

2. “CocoaPods doesn’t do X, so it’s unusable.”

First see point #1, then consider that unless you tell us about the missing feature and why it is important, it won’t happen at all. We don’t scour Twitter to look for work, so please file a ticket, or, better yet, start a pull-request.

3. “CocoaPods doesn’t do dependency resolution.”

CocoaPods does in fact do dependency resolution, but it does not automatically resolve conflicts. This means that when a conflict occurs, CocoaPods will raise an error and leave conflict resolving up to the user. (The user can do this by depending on a specific version of a common dependency before requiring the dependencies that lead to the conflict.)

If you’re familiar with Ruby then you can compare the former (the current CocoaPods style) to RubyGems’ style resolution and the latter (with conflict resolving) to Bundler’s.

Adding conflict resolution to CocoaPods is on our TODO list and we will try to work with the Bundler team to see if we can share their algorithm, but this will be one of the last things we’ll work on. A feature like this will require a stable basis and since we’re not there yet, working on it now would only make working on the basics more complex than necessary.

Finally, while conflict resolving is a definite must-have, you should ask yourself if you’re not using too many dependencies whenever you run into conflicts, as this is in general a good indicator. See the link to a blog post about this in #4.

4. “CocoaPods is bad for the community, because it makes it too easy for users to add many dependencies.”

This is akin to saying “guns kill people”, but everybody knows it’s really people who kill people (and psychotic bears with machetes). Furthermore, this reasoning applies to basically any means of fetching code (e.g. git) and as such is not a discussion worth having.

What is worth discussing, however, is informing the user to be responsible. Ironically enough, the original author of CocoaPods is convinced using a lot of dependencies is a really bad idea. For practical advice on how to deal with this, you should read this blog post by Manfred Stienstra.

5. “CocoaPods uses workspaces, which are considered user data. Why does it not use normal sub-projects?”

Beginning in Xcode 4, Apple introduced workspaces for this very purpose.

Since then, they have also added workspace files to each .xcodeproj document, leading people to believe that a workspace is user data only. This is simply incorrect and you should not ignore workspace documents any longer if you were doing so.

Note that CocoaPods itself does not require the use of a workspace. If you prefer to use sub-projects, you can do so by running pod install --no-integrate, which will leave integration into your project up to you as you see fit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment