fastlane-plugin-react_native_release 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (20) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +118 -45
  3. data/lib/fastlane/plugin/react_native_release/actions/accept_android_sdk_licenses.rb +46 -0
  4. data/lib/fastlane/plugin/react_native_release/actions/add_app_var.rb +109 -0
  5. data/lib/fastlane/plugin/react_native_release/actions/create_fastlane_session.rb +75 -0
  6. data/lib/fastlane/plugin/react_native_release/actions/decrypt_android_keystore.rb +131 -0
  7. data/lib/fastlane/plugin/react_native_release/actions/decrypt_app_vars.rb +106 -0
  8. data/lib/fastlane/plugin/react_native_release/actions/decrypt_fastlane_vars.rb +64 -0
  9. data/lib/fastlane/plugin/react_native_release/actions/decrypt_google_play_credentials.rb +62 -0
  10. data/lib/fastlane/plugin/react_native_release/actions/encrypt_app_vars.rb +110 -0
  11. data/lib/fastlane/plugin/react_native_release/actions/encrypt_fastlane_vars.rb +61 -0
  12. data/lib/fastlane/plugin/react_native_release/actions/encrypt_google_play_credentials.rb +64 -0
  13. data/lib/fastlane/plugin/react_native_release/actions/generate_android_keystore.rb +137 -0
  14. data/lib/fastlane/plugin/react_native_release/actions/{react_native_release_action.rb → react_native_release.rb} +33 -31
  15. data/lib/fastlane/plugin/react_native_release/actions/read_fastlane_session.rb +55 -0
  16. data/lib/fastlane/plugin/react_native_release/helper/react_native_release_helper.rb +14 -5
  17. data/lib/fastlane/plugin/react_native_release/version.rb +1 -1
  18. metadata +16 -6
  19. data/lib/fastlane/plugin/react_native_release/actions/create_fastlane_session_action.rb +0 -63
  20. data/lib/fastlane/plugin/react_native_release/actions/read_fastlane_session_action.rb +0 -67
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c1b56dd04e4f45053993e073fb79a804c7280c02a323b8a4d8d0faff8013bd3a
4
- data.tar.gz: a656b84729a0f3257da1699386f2cb3d1761a8dd0187f206a0a99a690fa32c41
3
+ metadata.gz: 85c358216aed69c8872ccca434dd6840958d56f9cd0d123d01df7aa623c5bbba
4
+ data.tar.gz: e76aeb88e60329c64251caf091e7806a570e985d7e915c8a96a88b1783cd4e9d
5
5
  SHA512:
6
- metadata.gz: 863e046372fedf07bde580efa5f2301afa51cb9d35ad43beaf0db0f063b8f703b7ee8f8d9ea3bbf7ba66bb98538e9a924ad17a8558e6a2f6b36a851b20ecdd7a
7
- data.tar.gz: 7eddc07b20b17f2d8fa386703172bece9c5c0a7d3577cef7df7a0be3c54f0998130a511b2b6ed35f277c21200366311908837c535621d920b6f97ce4e866aaeb
6
+ metadata.gz: d752e0955a2fa7c73e2f8a38db76cd2e8da383e203ebe743c2ed0b0bf5716812018f9d8c13311d0832eb6d59b1ce36d8e0800c8eb318b34cdc0bf799cf8b9eef
7
+ data.tar.gz: 2bfc9c7a783887edcf8ad103ac6b17c535f2ca48ab1f7dec40698644a1f6d1c37687d99fb193b5e619a11ba90fb9dd61aa956398b718c62856dfa590cbba15cb
data/README.md CHANGED
@@ -1,86 +1,159 @@
1
- # React Native Release
1
+ # React Native Release
2
2
 
3
3
  [![fastlane Plugin Badge](https://rawcdn.githack.com/fastlane/fastlane/master/fastlane/assets/plugin-badge.svg)](https://rubygems.org/gems/fastlane-plugin-react_native_release)
4
4
 
5
- ## Getting Started
5
+ Simplify releases for your React Native apps. This plugin contains many actions to help you with your release workflow.
6
6
 
7
- This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. To get started with `fastlane-plugin-react_native_release`, add it to your project by running:
7
+ It helps cut a new `beta` or `release` version of your app:
8
8
 
9
- ```bash
10
- fastlane add_plugin react_native_release
11
- ```
9
+ - Authenticates and stores an encrypted App Store Connect session that is later used for TestFlight and App Store operations
10
+ - Prompts the user for a `major/minor/patch` version bump
11
+ - Bumps the version of the iOS and Android app appropriately
12
+ - Creates a tag
13
+ - Handles hotfix releases
14
+ - Handles merging version bumps and hotfixes back to the appropriate branches
15
+
16
+ It encrypts, and on CI, decrypts values from a standalone "context" git repository:
17
+
18
+ - Android keystore file (including helping you generate one)
19
+ - Google Play Credentials to upload to the Play Store
20
+ - Fastlane config ENV variables
21
+ - App ENV variables (API_URL, feature flags, etc)
22
+
23
+ ### Philosophies
24
+
25
+ **Use Fastlane Match**
26
+
27
+ Certificates and provisioning profiles should be created and managed by Fastlane Match
28
+
29
+ **Builds Run on CI**
30
+
31
+ We support local builds for projects, but they should only be used in emergency situations.
32
+
33
+ **CI uses a machine user**
34
+
35
+ This is a best practice.
36
+
37
+ **ENV vars are managed through React Native Release**
38
+
39
+ We do this for portability and ease of configuration. Outside of the ENV vars to configure CRYPTEX, you shouldn't have to add ENV vars to CI.
40
+
41
+ For App ENV vars, we provide some additional functionality via namespaces. Valid namespaces are `alpha`, `beta`, `release`, and empty (root). Root ENV vars are "global". Namespaced variables are merged into the Root ENV vars at build time via the `decrypt_app_vars` action. This allows you to easily overwrite ENV vars for specific types of builds, all without configuring separate targets and schemes in XCode.
42
+
43
+ The main branch and tagging flow looks like this (note this may be out of date. Revisit after workflow updates):
44
+
45
+ ![Branch / Tag Flow](https://monosnap.com/image/Tn71leeWdCwwjSdwjYKHK4pnyjG1v4.png)
46
+
47
+ If a hotfix is required the flow looks like this (note this may be out of date. Revisit after workflow updates):
48
+
49
+ ![Hotfix Flow](https://monosnap.com/image/ctwlef0A3TbLbRk1xJrlVroNB8F9ot.png)
50
+
51
+ Here's what it looks like in action:
52
+ ![Releasing a beta](https://api.monosnap.com/image/download?id=IEISpG4vgMeGPl31it8GxPbiTror2i)
53
+ (this example uses `"release": "bundle exec fastlane run react_native_release"` as a yarn script)e
54
+
55
+ ## Prerequisites
12
56
 
13
57
  ### Ensure your project confirms to Semantic Versioning
58
+
14
59
  Projects using React Native Release should use Semantic Versioning. At the very least, you need major, minor, and patch numbers in your version.
15
60
 
16
61
  **iOS**
17
62
  Use `agvtool` to get and set a version across your project. From the `ios` directory, do the following:
18
- * `agvtool what-marketing-version` to see your current version
19
- * `agvtool new-marketing-version 0.1.0` to set a new version
63
+
64
+ - `agvtool what-marketing-version` to see your current version
65
+ - `agvtool new-marketing-version 0.1.0` to set a new version
20
66
 
21
67
  **Android**
22
- * Set `versionName` in `app/build.gradle`. (`versionName "0.1.0"`)
68
+
69
+ - Set `versionName` in `app/build.gradle`. (`versionName "0.1.0"`)
23
70
 
24
71
  :exclamation: If you don't complete these steps, releases will fail. :exclamation:
25
72
 
26
- ### Configuring builds to TestFlight and AppStore Connect on CI
73
+ ## Installation
74
+
75
+ This project is a [_fastlane_](https://github.com/fastlane/fastlane) plugin. Since React Native projects contain both `iOS` and `Android` apps, we need to install the plugin in multiple places:
27
76
 
28
- To upload builds to TestFlight or AppStore Connect, CI will need a cookie that was generated with a 2FA code. The `react_native_release` lane generates and stores this code securely in Github. We then use this token on CI during the IOS build upload step to TestFlight or AppStore Connect.
77
+ ### Install plugin into fastlane folders
29
78
 
30
- This is managed by the `fastlane-plugin-react_native_release` plugin in the iOS project. Start by adding the plugin to the iOS project by running:
79
+ 1. In the root of your project. This is used to run release commands over the entire project.
31
80
 
32
81
  ```bash
33
- cd ios && fastlane add_plugin react_native_release
82
+ fastlane add_plugin react_native_release
34
83
  ```
35
84
 
36
- Then add the `read_fastlane_session` command to the end of the `before_all` step in your `<root>/ios/Fastfile`:
85
+ 2. In `./android/fastlane`
37
86
 
38
- ```yaml
39
- before_all do
40
- setup_circle_ci
41
- read_fastlane_session
42
- end
87
+ ```bash
88
+ fastlane add_plugin react_native_release
43
89
  ```
44
90
 
45
- Next add an `.env` file at `<root>/fastlane/.env` with the following configuration.
91
+ 3. In `./ios/fastlane`
46
92
 
47
- | KEY | TYPE | DESCRIPTION |
48
- |-----|------|-------------|
49
- | FASTLANE_ENV_GIT_URL | String | The repository where the hashed session token will be stored. **Ensure this repository before running the release script!** (Must be a separate repository solely for securely storing the session token). |
50
- | FASTLANE_ENV_USERNAME | String | The Apple Developer Account email to authenticate with 2FA and generate a session token for. |
51
- | CRYPTEX_PASSWORD | String | The secret key used to encrypt/decrypt the `FASTLANE_SESSION` value. |
93
+ ```bash
94
+ fastlane add_plugin react_native_release
95
+ ```
52
96
 
97
+ ### Add or update .env files
53
98
 
54
- Note: Apple requires 2FA on all accounts now and the IOS build steps will fail if you attempt to upload to TestFlight or AppStore Connect without a session token.
99
+ We leverage `.env` files in a number of different places.
55
100
 
56
- ## About React Native Release
101
+ `<root>/fastlane/.env`:
57
102
 
58
- Simplify releases for React Native apps.
103
+ | KEY | TYPE | DESCRIPTION |
104
+ | ----------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
105
+ | CRYPTEX_GIT_URL | String | The repository where the hashed session token will be stored. **Ensure this repository before running the release script!** (You can leverage the same repository you use for Fastlane Match) |
106
+ | CRYPTEX_PASSWORD | String | The secret key used to encrypt/decrypt the `FASTLANE_SESSION` value. |
107
+ | CRYPTEX_SKIP_DOCS | Boolean | Force the underlying encryption plugin to skip README generation. |
59
108
 
60
- This plugin:
109
+ `<root>/android/fastlane/.env`:
61
110
 
62
- - cuts a new `beta` or `production` release
63
- - prompts the user for a `major/minor/patch` version bump
64
- - bumps the version of the iOS and Android app appropriately
65
- - tags a release based on the iOS and Android version
66
- - handles hotfix releases
67
- - handles merging version bumps and hotfixes back to the appropriate branches
111
+ | KEY | TYPE | DESCRIPTION |
112
+ | -------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
113
+ | ANDROID_KEY_PASSWORD | String | The password generated from `generate_android_keystore` or a manual keystore command.` |
114
+ | ANDROID_KEY_ALIAS | String | The alias for the keystore |
115
+ | CRYPTEX_GIT_URL | String | The repository where the hashed session token will be stored. **Ensure this repository before running the release script!** (You can leverage the same repository you use for Fastlane Match) |
116
+ | CRYPTEX_PASSWORD | String | The secret key used to encrypt/decrypt the `FASTLANE_SESSION` value. |
117
+ | CRYPTEX_SKIP_DOCS | Boolean | Force the underlying encryption plugin to skip README generation. |
68
118
 
69
- The main branch and tagging flow looks like this:
70
- ![Branch / Tag Flow](https://monosnap.com/image/Tn71leeWdCwwjSdwjYKHK4pnyjG1v4.png)
119
+ `<root>/ios/fastlane/.env`:
71
120
 
72
- If a hotfix is required the flow looks like this:
73
- ![Hotfix Flow](https://monosnap.com/image/ctwlef0A3TbLbRk1xJrlVroNB8F9ot.png)
121
+ | KEY | TYPE | DESCRIPTION |
122
+ | ----------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
123
+ | MATCH_GIT_URL | String | The repository used for Fastlane match. Typically the same as CRYPTEX_GIT_URL |
124
+ | MATCH_PASSWORD | String | The password used to encrypt / decrypt Fastlane Match certs and profiles |
125
+ | GYM_WORKSPACE | String | The name of the workspace file (Myproject.xcworkspace) |
126
+ | GYM_SCHEME | String | The scheme to build within the workspace (Myproject) |
127
+ | GYM_OUTPUT_NAME | String | The name of the `.ipa` file to output (Myproject) |
128
+ | CRYPTEX_GIT_URL | String | The repository where the hashed session token will be stored. **Ensure this repository before running the release script!** (You can leverage the same repository you use for Fastlane Match) |
129
+ | CRYPTEX_PASSWORD | String | The secret key used to encrypt/decrypt the `FASTLANE_SESSION` value. |
130
+ | CRYPTEX_SKIP_DOCS | Boolean | Force the underlying encryption plugin to skip README generation. |
74
131
 
75
- Here's what it looks like in action:
76
- ![Releasing a beta](https://api.monosnap.com/image/download?id=IEISpG4vgMeGPl31it8GxPbiTror2i)
77
- (this example uses `"release": "bundle exec fastlane run react_native_release"` as a yarn script)
132
+ **Note: In followup releases, we will add a `react-native-release init` script to generate these for you.**
78
133
 
79
- ## Example
134
+ ### Setup CI
135
+
136
+ Step 1. If you've already setup Fastlane Match, skip this section. Each provider is different, but conceptually you'll want to:
137
+
138
+ - Create a machine user account on your source code provider (GitHub or BitBucket) and invite that account to both the mobile and certs repo.
139
+ - Enable CI on the main mobile repository by pressing "Follow" or "Build"
140
+ - In an Incognito tab, log into your CI provider with the machine user account.
141
+ - Add a user key instead of the default deploy key. This will allow CI to auth as the machine user and gain access to _both_ the mobile repo and the context repo.
80
142
 
81
- Check out the [example `Fastfile`](fastlane/Fastfile) to see how to use this plugin. Try it by cloning the repo, running `fastlane install_plugins` and `bundle exec fastlane test`.
143
+ Step 2. Add the following to your CI environment variables:
144
+
145
+ - CRYPTEX_GIT_URL=(your context repo ssh git url)
146
+ - CRYPTEX_PASSWORD=(your context repo password)
147
+ - CRYPTEX_VERBOSE=true
148
+ - CRYPTEX_DIGEST=sha256 (note: if you have a pre-existing setup, you should set this to md5 - see https://github.com/hjanuschka/fastlane-plugin-cryptex/pull/10)
149
+
150
+ ### Configuring builds to upload to TestFlight and AppStore Connect on CI
151
+
152
+ To upload builds to TestFlight or AppStore Connect, CI will need to restore a previously generated session. While possible to use an Application Specific Password to upload builds, it will not have the additional permissions required for other TestFlight / App Store operations. As such, we require generating a session.
153
+
154
+ ## Example
82
155
 
83
- **Note to author:** Please set up a sample project to make it easy for users to explore what your plugin does. Provide everything that is necessary to try out the plugin in this project (including a sample Xcode/Android project if necessary)
156
+ See /example to see how to use the plugin. (TODO)
84
157
 
85
158
  ## Run tests for this plugin
86
159
 
@@ -0,0 +1,46 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane/plugin/cryptex'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class AcceptAndroidSdkLicensesAction < Action
7
+ def self.run(params)
8
+ sh("yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses || if [ $? -ne '141' ]; then exit $?; fi;")
9
+ end
10
+
11
+ #####################################################
12
+ # @!group Documentation
13
+ #####################################################
14
+
15
+ def self.description
16
+ "Accepts Android sdk licenses"
17
+ end
18
+
19
+ def self.details
20
+ # Optional:
21
+ # this is your chance to provide a more detailed description of this action
22
+ end
23
+
24
+ def self.available_options
25
+ []
26
+ end
27
+
28
+ def self.return_value
29
+ # If your method provides a return value, you can describe here what it does
30
+ end
31
+
32
+ def self.details
33
+ # "Saves the current vars in android/fastlane/.env and ios/fastlane/.env"
34
+ end
35
+
36
+ def self.authors
37
+ # So no one will ever forget your contribution to fastlane :) You are awesome btw!
38
+ ["cball", "isaiahgrey93"]
39
+ end
40
+
41
+ def self.is_supported?(platform)
42
+ [:ios, :android].include?(platform)
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,109 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane/plugin/cryptex'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class AddAppVarAction < Action
7
+ def self.run(params)
8
+ is_ci = ENV['CI'] === 'true'
9
+ namespace = params[:namespace]
10
+ key = params[:key]
11
+ value = params[:value]
12
+ cryptex_app_key = app_key_for(namespace)
13
+ existing_app_vars = {}
14
+
15
+ if !is_ci && !UI.confirm("This will add #{key}=#{value} to the #{cryptex_app_key} namespace in the encrypted context repo. Proceed?")
16
+ UI.abort_with_message!("Stepping away...")
17
+ end
18
+
19
+ begin
20
+ existing_app_vars = other_action.cryptex(
21
+ type: 'export_env',
22
+ key: cryptex_app_key,
23
+ )
24
+ rescue => ex
25
+ # If key doesn't exist cryptex will error
26
+ end
27
+
28
+ other_action.cryptex(
29
+ type: "import_env",
30
+ key: cryptex_app_key,
31
+ hash: existing_app_vars.merge({ key => value })
32
+ )
33
+
34
+ UI.success('Encrypted app ENV vars')
35
+ end
36
+
37
+ #####################################################
38
+ # @!group Documentation
39
+ #####################################################
40
+
41
+ def self.description
42
+ "Adds a single ENV var to the encrypted repository"
43
+ end
44
+
45
+ def self.details
46
+ # Optional:
47
+ # this is your chance to provide a more detailed description of this action
48
+ end
49
+
50
+ def self.available_options
51
+ [
52
+ FastlaneCore::ConfigItem.new(key: :namespace,
53
+ env_name: "FL_ADD_APP_VAR_NAMESPACE",
54
+ description: "What namespace should we use? (alpha, beta, release, ENTER = root)", # a short description of this parameter
55
+ type: String,
56
+ verify_block: lambda do |value|
57
+ unless Helper::ReactNativeReleaseHelper::VALID_NAMESPACES.include?(value)
58
+ UI.user_error!("Invalid namespace #{value}. Valid targets are #{Helper::ReactNativeReleaseHelper::VALID_NAMESPACES.join(', ')}")
59
+ next
60
+ end
61
+ end),
62
+ FastlaneCore::ConfigItem.new(key: :key,
63
+ env_name: "FL_ADD_APP_VAR_KEY",
64
+ description: "Enter the ENV name",
65
+ type: String),
66
+ FastlaneCore::ConfigItem.new(key: :value,
67
+ env_name: "FL_ADD_APP_VAR_VALUE",
68
+ description: "Enter the ENV value",
69
+ type: String),
70
+ ]
71
+ end
72
+
73
+ def self.return_value
74
+ # If your method provides a return value, you can describe here what it does
75
+ end
76
+
77
+ def self.details
78
+ # "Saves the current vars in android/fastlane/.env and ios/fastlane/.env"
79
+ end
80
+
81
+ def self.authors
82
+ # So no one will ever forget your contribution to fastlane :) You are awesome btw!
83
+ ["cball", "isaiahgrey93"]
84
+ end
85
+
86
+ def self.is_supported?(platform)
87
+ [:ios, :android].include?(platform)
88
+ end
89
+
90
+ # Returns a path for an env var. optionally namespaced
91
+ def self.env_path_for(namespace)
92
+ return default_env_path if namespace.strip.empty?
93
+ "#{default_env_path}.#{namespace}"
94
+ end
95
+
96
+ # Returns the app key for cryptex. optionally namespaced
97
+ def self.app_key_for(namespace)
98
+ default_app_key = Helper::ReactNativeReleaseHelper::APP_CRYPTEX_KEY
99
+ return default_app_key if namespace.strip.empty?
100
+
101
+ "#{namespace}_#{default_app_key}"
102
+ end
103
+
104
+ def self.default_env_path
105
+ Helper::ReactNativeReleaseHelper::APP_ENV_PATH
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,75 @@
1
+ require 'fastlane/action'
2
+ require 'fastlane/plugin/cryptex'
3
+
4
+ module Fastlane
5
+ module Actions
6
+ class CreateFastlaneSessionAction < Action
7
+ def self.run(params)
8
+ username = params[:username]
9
+ key = Helper::ReactNativeReleaseHelper::FASTLANE_SESSION_CRYPTEX_KEY
10
+ fastlane_key = Helper::ReactNativeReleaseHelper::FASTLANE_CRYPTEX_KEY
11
+ fastlane_session_cookie_path = "#{File.expand_path('~')}/.fastlane/spaceship/#{username}/cookie"
12
+
13
+ UI.message "Generating a new fastlane session."
14
+ UI.message "Please enter the 6 digit 2FA code if one is sent to your device otherwise the script will continue automatically."
15
+
16
+ sh("fastlane spaceauth -u #{username.shellescape}")
17
+
18
+ # store the session
19
+ other_action.cryptex(
20
+ type: "import",
21
+ in: fastlane_session_cookie_path,
22
+ key: key
23
+ )
24
+
25
+ # store the username that created the session in fastlane_vars
26
+ existing_fastlane_vars = other_action.cryptex(
27
+ type: 'export_env',
28
+ key: fastlane_key,
29
+ )
30
+
31
+ other_action.cryptex(
32
+ type: "import_env",
33
+ key: fastlane_key,
34
+ # PILOT_USERNAME needs to be set to the same username as the session above
35
+ hash: existing_fastlane_vars.merge({ 'PILOT_USERNAME' => username })
36
+ )
37
+
38
+ UI.success "Uploaded session for #{username} to #{key}."
39
+ end
40
+
41
+ def self.description
42
+ "Simplify 2FA authentication for App Store Connect"
43
+ end
44
+
45
+ def self.authors
46
+ ["cball", "isaiahgrey93"]
47
+ end
48
+
49
+ def self.return_value
50
+ # If your method provides a return value, you can describe here what it does
51
+ end
52
+
53
+ def self.details
54
+ "Creates a cookie for authenticating with App Store connecting. Handles generating, encrypting, and storing the cookie."
55
+ end
56
+
57
+ def self.available_options
58
+ [
59
+ FastlaneCore::ConfigItem.new(key: :username,
60
+ env_name: "FL_CREATE_FASTLANE_SESSION_USERNAME",
61
+ description: "Enter the Apple username to generate a App Store Connect session",
62
+ type: String)
63
+ ]
64
+ end
65
+
66
+ def self.is_supported?(platform)
67
+ # Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
68
+ # See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
69
+ #
70
+ [:ios, :android].include?(platform)
71
+ end
72
+
73
+ end
74
+ end
75
+ end