spaceship 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/LICENSE +21 -0
- data/README.md +390 -17
- data/lib/spaceship.rb +69 -3
- data/lib/spaceship/app.rb +96 -0
- data/lib/spaceship/base.rb +86 -0
- data/lib/spaceship/certificate.rb +270 -0
- data/lib/spaceship/client.rb +399 -0
- data/lib/spaceship/device.rb +100 -0
- data/lib/spaceship/helper/net_http_generic_request.rb +12 -0
- data/lib/spaceship/helper/plist_middleware.rb +15 -0
- data/lib/spaceship/launcher.rb +89 -0
- data/lib/spaceship/profile_types.rb +39 -0
- data/lib/spaceship/provisioning_profile.rb +352 -0
- data/lib/spaceship/ui.rb +28 -0
- data/lib/spaceship/ui/select_team.rb +55 -0
- data/lib/spaceship/version.rb +2 -2
- metadata +179 -33
- data/.gitignore +0 -14
- data/Gemfile +0 -4
- data/LICENSE.txt +0 -22
- data/Rakefile +0 -3
- data/lib/spaceship/ship.rb +0 -7
- data/spaceship.gemspec +0 -24
- data/spec/ship_spec.rb +0 -16
- data/spec/spec_helper.rb +0 -1
- data/tasks/rspec.rake +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 404634d202a34615660b5239a2fc6b9edb449197
|
4
|
+
data.tar.gz: 0d6101044d0e1b639234ee2611b979a4f5ccc204
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 066a803865cc2b93315969b270837c7c3204880e8a8cee1b5a27d60d29c0dfbef5c81544f27b348e1fffbc848e52a26899f35fc3977d05f323911753c7984d61
|
7
|
+
data.tar.gz: 3b3b7cf7ab39726200c01fb5d866c15bac3c81e359a335c797bd6f51ad72112ba5307b34dfc21621f77b901bb76b2ecbc26b83030f9a66b48b222a49a21ee1b6
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Felix Krause
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
data/README.md
CHANGED
@@ -1,31 +1,404 @@
|
|
1
|
-
|
1
|
+
<h3 align="center">
|
2
|
+
<a href="https://github.com/KrauseFx/fastlane">
|
3
|
+
<img src="assets/fastlane.png" width="150" />
|
4
|
+
<br />
|
5
|
+
spaceship
|
6
|
+
</a>
|
7
|
+
</h3>
|
8
|
+
<p align="center">
|
9
|
+
<a href="https://github.com/KrauseFx/deliver">deliver</a> •
|
10
|
+
<a href="https://github.com/KrauseFx/snapshot">snapshot</a> •
|
11
|
+
<a href="https://github.com/KrauseFx/frameit">frameit</a> •
|
12
|
+
<a href="https://github.com/KrauseFx/PEM">PEM</a> •
|
13
|
+
<a href="https://github.com/KrauseFx/sigh">sigh</a> •
|
14
|
+
<a href="https://github.com/KrauseFx/produce">produce</a> •
|
15
|
+
<a href="https://github.com/KrauseFx/cert">cert</a> •
|
16
|
+
<a href="https://github.com/KrauseFx/codes">codes</a>
|
17
|
+
</p>
|
18
|
+
-------
|
2
19
|
|
3
|
-
|
20
|
+
<p align="center">
|
21
|
+
<img src="assets/spaceship.png">
|
22
|
+
</p>
|
4
23
|
|
5
|
-
|
24
|
+
spaceship
|
25
|
+
============
|
6
26
|
|
7
|
-
|
27
|
+
[](https://twitter.com/KrauseFx)
|
28
|
+
[](https://github.com/KrauseFx/spaceship/blob/master/LICENSE)
|
29
|
+
[](https://coveralls.io/r/KrauseFx/spaceship?branch=master)
|
30
|
+
[](http://rubygems.org/gems/spaceship)
|
31
|
+
[](https://codeship.com/projects/73801)
|
8
32
|
|
33
|
+
|
34
|
+
Get in contact with the developers on Twitter: [@snatchev](https://twitter.com/snatchev/) and [@KrauseFx](https://twitter.com/KrauseFx)
|
35
|
+
|
36
|
+
|
37
|
+
-------
|
38
|
+
<p align="center">
|
39
|
+
<a href="#why">Why?</a> •
|
40
|
+
<a href="#usage">Usage</a> •
|
41
|
+
<a href="#installation">Installation</a> •
|
42
|
+
<a href="#technical-details">Technical Details</a> •
|
43
|
+
<a href="#need-help">Need help?</a>
|
44
|
+
</p>
|
45
|
+
|
46
|
+
-------
|
47
|
+
|
48
|
+
<h5 align="center"><code>spaceship</code> is part of <a href="https://fastlane.tools">fastlane</a>: connect all deployment tools into one streamlined workflow.</h5>
|
49
|
+
|
50
|
+
##### [Like this tool? Be the first to know about updates and new fastlane tools](https://tinyletter.com/krausefx)
|
51
|
+
|
52
|
+
# What's Spaceship?
|
53
|
+
|
54
|
+
> `spaceship` is named after the new Apple HQ in Cupertino. It allows you to seamlessly interact with the Apple Developer Portal using very simple Ruby code.
|
55
|
+
|
56
|
+
`spaceship` uses simple HTTPs requests without any sort of web scraping.
|
57
|
+
|
58
|
+
Using `spaceship`, the execution time of [sigh](https://github.com/KrauseFx/sigh) was reduced from over 1 minute to less than 5 seconds :rocket:
|
59
|
+
|
60
|
+
`spaceship` uses a combination of 3 different API endpoints, used by the Apple Developer Portal and Xcode. As no API offers everything we need, `spaceship` combines all APIs for you. [More details about the APIs](#technical-details).
|
61
|
+
|
62
|
+
Up until now, the [fastlane tools](https://fastlane.tools) used web scraping to interact with Apple's web services. By upgrading them to use `spaceship` all [fastlane tools](https://fastlane.tools) will be even faster and much more stable.
|
63
|
+
|
64
|
+
> No matter how many apps or profiles you have, `spaceship` **can** handle your scale.
|
65
|
+
|
66
|
+
Enough words, here is some code:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
Spaceship.login
|
70
|
+
|
71
|
+
# Create a new app
|
72
|
+
app = Spaceship.app.create!(bundle_id: "com.krausefx.app", name: "Spaceship App")
|
73
|
+
|
74
|
+
# Use an existing certificate
|
75
|
+
cert = Spaceship.certificate.production.all.first
|
76
|
+
|
77
|
+
# Create a new provisioning profile
|
78
|
+
profile = Spaceship.provisioning_profile.app_store.create!(bundle_id: app.bundle_id,
|
79
|
+
certificate: cert)
|
80
|
+
|
81
|
+
# Print the name and download the new profile
|
82
|
+
puts "Created Profile " + profile.name
|
83
|
+
profile.download
|
84
|
+
```
|
85
|
+
|
86
|
+
## Speed
|
87
|
+
|
88
|
+
How fast are tools using `spaceship` compared to web scraping?
|
89
|
+
|
90
|
+

|
91
|
+
|
92
|
+
# Installation
|
93
|
+
|
94
|
+
sudo gem install spaceship
|
95
|
+
|
96
|
+
# Usage
|
97
|
+
|
98
|
+
To quickly play around with `spaceship` launch `irb` in your terminal and execute `require "spaceship"`.
|
99
|
+
|
100
|
+
## Login
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
Spaceship.login("felix@krausefx.com", "password")
|
104
|
+
|
105
|
+
Spaceship.select_team # call this method to let the user select a team
|
106
|
+
```
|
107
|
+
|
108
|
+
## Apps
|
109
|
+
|
110
|
+
```ruby
|
111
|
+
# Fetch all available apps
|
112
|
+
all_apps = Spaceship.app.all
|
113
|
+
|
114
|
+
# Find a specific app based on the bundle identifier
|
115
|
+
app = Spaceship.app.find("com.krausefx.app")
|
116
|
+
|
117
|
+
# Show the names of all your apps
|
118
|
+
Spaceship.app.all.each do |app|
|
119
|
+
puts app.name
|
120
|
+
end
|
121
|
+
|
122
|
+
# Create a new app
|
123
|
+
app = Spaceship.app.create!(bundle_id: "com.krausefx.app_name", name: "fastlane App")
|
124
|
+
```
|
125
|
+
|
126
|
+
## Certificates
|
127
|
+
|
128
|
+
```ruby
|
129
|
+
# Fetch all available certificates (includes signing and push profiles)
|
130
|
+
certificates = Spaceship.certificate.all
|
131
|
+
```
|
132
|
+
|
133
|
+
### Code Signing Certificates
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
# Production identities
|
137
|
+
prod_certs = Spaceship.certificate.production.all
|
138
|
+
|
139
|
+
# Development identities
|
140
|
+
dev_certs = Spaceship.certificate.development.all
|
141
|
+
|
142
|
+
# Download a certificate
|
143
|
+
cert_content = prod_certs.first.download
|
144
|
+
```
|
145
|
+
|
146
|
+
### Push Certificates
|
147
|
+
```ruby
|
148
|
+
# Production push profiles
|
149
|
+
prod_push_certs = Spaceship.certificate.production_push.all
|
150
|
+
|
151
|
+
# Development push profiles
|
152
|
+
dev_push_certs = Spaceship.certificate.development_push.all
|
153
|
+
|
154
|
+
# Download a push profile
|
155
|
+
cert_content = dev_push_certs.first.download
|
156
|
+
```
|
157
|
+
|
158
|
+
### Create a Certificate
|
159
|
+
|
160
|
+
```ruby
|
161
|
+
# Create a new certificate signing request
|
162
|
+
csr, pkey = Spaceship.certificate.create_certificate_signing_request
|
163
|
+
|
164
|
+
# Use the signing request to create a new distribution certificate
|
165
|
+
Spaceship.certificate.production.create!(csr: csr)
|
166
|
+
|
167
|
+
# Use the signing request to create a new push certificate
|
168
|
+
Spaceship.certificate.production_push.create!(csr: csr, bundle_id: "com.krausefx.app")
|
169
|
+
```
|
170
|
+
|
171
|
+
## Provisioning Profiles
|
172
|
+
|
173
|
+
### Receiving profiles
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
##### Finding #####
|
177
|
+
|
178
|
+
# Get all available provisioning profiles
|
179
|
+
profiles = Spaceship.provisioning_profile.all
|
180
|
+
|
181
|
+
# Get all App Store profiles
|
182
|
+
profiles_appstore = Spaceship.provisioning_profile.app_store.all
|
183
|
+
|
184
|
+
# Get all AdHoc profiles
|
185
|
+
profiles_adhoc = Spaceship.provisioning_profile.ad_hoc.all
|
186
|
+
|
187
|
+
# Get all Development profiles
|
188
|
+
profiles_dev = Spaceship.provisioning_profile.development.all
|
189
|
+
|
190
|
+
# Fetch all profiles for a specific app identifier for the App Store
|
191
|
+
filtered_profiles = Spaceship.provisioning_profile.app_store.find_by_bundle_id("com.krausefx.app")
|
192
|
+
|
193
|
+
##### Downloading #####
|
194
|
+
|
195
|
+
# Download a profile
|
196
|
+
profile_content = profiles.first.download
|
197
|
+
|
198
|
+
# Download a specific profile as file
|
199
|
+
my_profile = Spaceship.provisioning_profile.app_store.find_by_bundle_id("com.krausefx.app")
|
200
|
+
File.write("output.mobileprovision", my_profile.download)
|
201
|
+
```
|
202
|
+
|
203
|
+
### Create a Provisioning Profile
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
# Choose the certificate to use
|
207
|
+
cert = Spaceship.certificate.production.all.first
|
208
|
+
|
209
|
+
# Create a new provisioning profile with a default name
|
210
|
+
# The name of the new profile is "com.krausefx.app AppStore"
|
211
|
+
profile = Spaceship.provisioning_profile.app_store.create!(bundle_id: "com.krausefx.app",
|
212
|
+
certificate: cert)
|
213
|
+
|
214
|
+
# AdHoc Profiles will add all devices by default
|
215
|
+
profile = Spaceship.provisioning_profile.ad_hoc.create!(bundle_id: "com.krausefx.app",
|
216
|
+
certificate: cert,
|
217
|
+
name: "Profile Name")
|
218
|
+
|
219
|
+
# Store the new profile on the filesystem
|
220
|
+
File.write("NewProfile.mobileprovision", profile.download)
|
221
|
+
```
|
222
|
+
|
223
|
+
### Repair a broken provisioning profile
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
# Select all 'Invalid' or 'Expired' provisioning profiles
|
227
|
+
broken_profiles = Spaceship.provisioning_profile.all.find_all do |profile|
|
228
|
+
(profile.status == "Invalid" or profile.status == "Expired")
|
229
|
+
end
|
230
|
+
|
231
|
+
# Iterate over all broken profiles and repair them
|
232
|
+
broken_profiles.each do |profile|
|
233
|
+
profile.repair! # yes, that's all you need to repair a profile
|
234
|
+
end
|
235
|
+
|
236
|
+
# or to make the same thing, just more Ruby like:
|
237
|
+
Spaceship.provisioning_profile.all.find_all { |p| %w[Invalid Expired].include?p.status}.map(&:repair!)
|
238
|
+
```
|
239
|
+
|
240
|
+
## Devices
|
241
|
+
|
242
|
+
```ruby
|
243
|
+
all_devices = Spaceship.device.all
|
244
|
+
|
245
|
+
# Register a new device
|
246
|
+
Spaceship.device.create!(name: "Private iPhone 6", udid: "5814abb3...")
|
247
|
+
```
|
248
|
+
|
249
|
+
## Enterprise
|
250
|
+
|
251
|
+
```ruby
|
252
|
+
# Use the InHouse class to get all enterprise certificates
|
253
|
+
cert = Spaceship.certificate.in_house.all.first
|
254
|
+
|
255
|
+
# Create a new InHouse Enterprise distribution profile
|
256
|
+
profile = Spaceship.provisioning_profile.app_store.create!(bundle_id: "com.krausefx.*",
|
257
|
+
certificate: cert)
|
258
|
+
```
|
259
|
+
|
260
|
+
## Multiple Spaceships
|
261
|
+
|
262
|
+
Sometimes one `spaceship` just isn't enough. That's why this library has its own Spaceship Launcher to launch and use multiple `spaceships` at the same time :rocket:
|
263
|
+
|
264
|
+
```ruby
|
265
|
+
# Launch 2 spaceships
|
266
|
+
spaceship1 = Spaceship::Launcher.new("felix@krausefx.com", "password")
|
267
|
+
spaceship2 = Spaceship::Launcher.new("stefan@spaceship.airforce", "password")
|
268
|
+
|
269
|
+
# Fetch all registered devices from spaceship1
|
270
|
+
devices = spaceship1.device.all
|
271
|
+
|
272
|
+
# Iterate over the list of available devices
|
273
|
+
# and register each device from the first account also on the second one
|
274
|
+
devices.each do |device|
|
275
|
+
spaceship2.device.create!(name: device.name, udid: device.udid)
|
276
|
+
end
|
277
|
+
```
|
278
|
+
|
279
|
+
## More cool things you can do
|
9
280
|
```ruby
|
10
|
-
|
281
|
+
# Find a profile with a specific name
|
282
|
+
profile = Spaceship.provisioning_profile.development.all.find { |p| p.name == "Name" }
|
283
|
+
|
284
|
+
# Add all available devices to the profile
|
285
|
+
profile.devices = Spaceship.device.all
|
286
|
+
|
287
|
+
# Push the changes back to the Apple Developer Portal
|
288
|
+
profile.update!
|
289
|
+
|
290
|
+
# Get the currently used team_id
|
291
|
+
Spaceship.client.team_id
|
292
|
+
|
293
|
+
# We generally don't want to be destructive, but you can also delete things
|
294
|
+
# This method might fail for various reasons, e.g. app is already in the store
|
295
|
+
app = Spaceship.app.find("com.krausefx.app")
|
296
|
+
app.delete!
|
11
297
|
```
|
12
298
|
|
13
|
-
|
299
|
+
## Spaceship in use
|
300
|
+
|
301
|
+
The beta version of [sigh](https://github.com/KrauseFx/sigh) is already using `spaceship` to communicate with Apple's web services. You can see all relevant source code in [runner.rb](https://github.com/KrauseFx/sigh/blob/feature/spaceship/lib/sigh/spaceship/runner.rb).
|
302
|
+
|
303
|
+
## Full Documentation
|
304
|
+
|
305
|
+
The detailed documentation of all available classes is available on [RubyDoc](http://www.rubydoc.info/github/fastlane/spaceship/frames).
|
306
|
+
|
307
|
+
## Example Data
|
308
|
+
|
309
|
+
Some unnecessary information was removed, check out [provisioning_profile.rb](https://github.com/KrauseFx/spaceship/blob/master/lib/spaceship/provisioning_profile.rb) for all available attributes.
|
310
|
+
|
311
|
+
The example data below is a provisioning profile, containing a device, certificate and app.
|
312
|
+
|
313
|
+
```
|
314
|
+
#<Spaceship::ProvisioningProfile::AdHoc
|
315
|
+
@devices=[
|
316
|
+
#<Spaceship::Device
|
317
|
+
@id="5YTNZ5A9AA",
|
318
|
+
@name="Felix iPhone 6",
|
319
|
+
@udid="39d2cab02642dc2bfdbbff4c0cb0e50c8632faaa"
|
320
|
+
>, ...],
|
321
|
+
@certificates=[
|
322
|
+
#<Spaceship::Certificate::Production
|
323
|
+
@id="LHNT9C2AAA",
|
324
|
+
@name="iOS Distribution",
|
325
|
+
@expires=#<DateTime: 2016-02-10T23:44:20>
|
326
|
+
],
|
327
|
+
@id="72SRVUNAAA",
|
328
|
+
@uuid="43cda0d6-04a5-4964-89c0-a24b5f258aaa",
|
329
|
+
@expires=#<DateTime: 2016-02-10T23:44:20>,
|
330
|
+
@distribution_method="adhoc",
|
331
|
+
@name="com.krausefx.app AppStore",
|
332
|
+
@status="Active",
|
333
|
+
@platform="ios",
|
334
|
+
@app=#<Spaceship::App
|
335
|
+
@app_id="2UMR2S6AAA",
|
336
|
+
@name="App Name",
|
337
|
+
@platform="ios",
|
338
|
+
@bundle_id="com.krausefx.app",
|
339
|
+
@is_wildcard=false>
|
340
|
+
>
|
341
|
+
>
|
342
|
+
```
|
343
|
+
|
344
|
+
# Technical Details
|
345
|
+
|
346
|
+
## HTTP Client
|
347
|
+
|
348
|
+
Up until now all [fastlane tools](https://fastlane.tools) used web scraping to interact with Apple's web services. `spaceship` uses a simple HTTP client only, resulting in much less overhead and extremely improved speed.
|
349
|
+
|
350
|
+
Advantages of `spaceship` (HTTP client) over web scraping:
|
351
|
+
|
352
|
+
- Blazing fast :rocket: 90% faster than previous methods
|
353
|
+
- No more overhead by loading images, HTML, JS and CSS files on each page load
|
354
|
+
- Great test coverage by stubbing server responses
|
355
|
+
- Resistant against design changes of the Apple Developer Portal
|
356
|
+
- Automatic re-trying of requests in case a timeout occurs
|
357
|
+
- By stubbing the `spaceship` objects it is possible to also implement tests for tools like [sigh](https://github.com/KrauseFx/sigh)
|
358
|
+
|
359
|
+
## API Endpoints
|
360
|
+
|
361
|
+
I won't go into too much technical details about the various API endpoints, but just to give you an idea:
|
362
|
+
|
363
|
+
- `https://idmsa.apple.com`: Used to authenticate to get a valid session
|
364
|
+
- `https://developerservices2.apple.com`:
|
365
|
+
- Get a detailed list of all available provisioning profiles
|
366
|
+
- This API returns the devices, certificates and app for each of the profiles
|
367
|
+
- Register new devices
|
368
|
+
- `https://developer.apple.com`:
|
369
|
+
- List all devices, certificates and apps
|
370
|
+
- Create new certificates, provisioning profiles and apps
|
371
|
+
- Delete certificates and apps
|
372
|
+
- Repair provisioning profiles
|
373
|
+
- Download provisioning profiles
|
374
|
+
- Team selection
|
375
|
+
|
376
|
+
`spaceship` uses all those API points to offer this seamless experience.
|
377
|
+
|
378
|
+
## Magic involved
|
14
379
|
|
15
|
-
|
380
|
+
`spaceship` does a lot of magic to get everything working so neatly:
|
16
381
|
|
17
|
-
|
382
|
+
- **Sensible Defaults**: You only have to provide the mandatory information (e.g. new provisioning profiles contain all devices by default)
|
383
|
+
- **Local Validation**: When pushing changes back to the Apple Dev Portal `spaceship` will make sure only valid data is sent to Apple (e.g. automatic repairing of provisioning profiles)
|
384
|
+
- **Various request/response types**: When working with the different API endpoints, `spaceship` has to deal with `JSON`, `XML`, `txt`, `plist` and sometimes even `HTML` responses and requests.
|
385
|
+
- **Automatic Pagination**: Even if you have thousands of apps, profiles or certificates, `spaceship` **can** handle your scale. It was heavily tested by first using `spaceship` to create hundreds of profiles and then accessing them using `spaceship`.
|
386
|
+
- **Session, Cookie and CSRF token**: All the security aspects are handled by `spaceship`.
|
387
|
+
- **Profile Magic**: Create and upload code signing requests, all managed by `spaceship`
|
388
|
+
- **Multiple Spaceship**: You can launch multiple `spaceships` with different Apple accounts to do things like syncing the registered devices.
|
18
389
|
|
19
|
-
|
390
|
+
# Credits
|
20
391
|
|
21
|
-
|
392
|
+
This project has been sponsored by [ZeroPush](https://zeropush.com). `spaceship` was developed by [@snatchev](https://twitter.com/snatchev/) and [@KrauseFx](https://twitter.com/KrauseFx).
|
22
393
|
|
23
|
-
|
394
|
+
# License
|
395
|
+
This project is licensed under the terms of the MIT license. See the LICENSE file.
|
24
396
|
|
25
|
-
|
397
|
+
# Contributing
|
26
398
|
|
27
|
-
1.
|
28
|
-
2.
|
29
|
-
3.
|
30
|
-
4.
|
31
|
-
5.
|
399
|
+
1. Create an issue to start a discussion about your idea
|
400
|
+
2. Fork it (https://github.com/KrauseFx/fastlane/fork)
|
401
|
+
3. Create your feature branch (`git checkout -b my-new-feature`)
|
402
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
403
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
404
|
+
6. Create a new Pull Request
|