fastlane-plugin-react_native_release 0.6.0 → 0.7.0

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.
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