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.
- checksums.yaml +4 -4
- data/README.md +118 -45
- data/lib/fastlane/plugin/react_native_release/actions/accept_android_sdk_licenses.rb +46 -0
- data/lib/fastlane/plugin/react_native_release/actions/add_app_var.rb +109 -0
- data/lib/fastlane/plugin/react_native_release/actions/create_fastlane_session.rb +75 -0
- data/lib/fastlane/plugin/react_native_release/actions/decrypt_android_keystore.rb +131 -0
- data/lib/fastlane/plugin/react_native_release/actions/decrypt_app_vars.rb +106 -0
- data/lib/fastlane/plugin/react_native_release/actions/decrypt_fastlane_vars.rb +64 -0
- data/lib/fastlane/plugin/react_native_release/actions/decrypt_google_play_credentials.rb +62 -0
- data/lib/fastlane/plugin/react_native_release/actions/encrypt_app_vars.rb +110 -0
- data/lib/fastlane/plugin/react_native_release/actions/encrypt_fastlane_vars.rb +61 -0
- data/lib/fastlane/plugin/react_native_release/actions/encrypt_google_play_credentials.rb +64 -0
- data/lib/fastlane/plugin/react_native_release/actions/generate_android_keystore.rb +137 -0
- data/lib/fastlane/plugin/react_native_release/actions/{react_native_release_action.rb → react_native_release.rb} +33 -31
- data/lib/fastlane/plugin/react_native_release/actions/read_fastlane_session.rb +55 -0
- data/lib/fastlane/plugin/react_native_release/helper/react_native_release_helper.rb +14 -5
- data/lib/fastlane/plugin/react_native_release/version.rb +1 -1
- metadata +16 -6
- data/lib/fastlane/plugin/react_native_release/actions/create_fastlane_session_action.rb +0 -63
- data/lib/fastlane/plugin/react_native_release/actions/read_fastlane_session_action.rb +0 -67
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'fastlane/plugin/cryptex'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class EncryptFastlaneVarsAction < Action
|
7
|
+
ANDROID_ENV_PATH = "./android/fastlane/.env"
|
8
|
+
IOS_ENV_PATH = './ios/fastlane/.env'
|
9
|
+
FASTLANE_CRYPTEX_KEY = 'fastlane_vars'
|
10
|
+
|
11
|
+
def self.run(params)
|
12
|
+
if !File.exists?(IOS_ENV_PATH)
|
13
|
+
UI.user_error!("No .env found in ios directory!")
|
14
|
+
end
|
15
|
+
|
16
|
+
if !File.exists?(ANDROID_ENV_PATH)
|
17
|
+
UI.user_error!("No .env found in Android directory")
|
18
|
+
end
|
19
|
+
|
20
|
+
if !UI.confirm("This will save values from your #{IOS_ENV_PATH} and #{ANDROID_ENV_PATH} to the encrypted context repo. Proceed?")
|
21
|
+
UI.abort_with_message!("Stepping away...")
|
22
|
+
end
|
23
|
+
|
24
|
+
android_env_vars = Dotenv.parse(ANDROID_ENV_PATH)
|
25
|
+
ios_env_vars = Dotenv.parse(IOS_ENV_PATH)
|
26
|
+
vars = android_env_vars.merge(ios_env_vars)
|
27
|
+
|
28
|
+
other_action.cryptex(
|
29
|
+
type: "import_env",
|
30
|
+
key: FASTLANE_CRYPTEX_KEY,
|
31
|
+
hash: vars,
|
32
|
+
)
|
33
|
+
|
34
|
+
UI.success "ENV vars set in context repo."
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.description
|
38
|
+
"Encrypt fastlane vars for CI"
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.authors
|
42
|
+
["cball", "isaiahgrey93"]
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.return_value
|
46
|
+
# If your method provides a return value, you can describe here what it does
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.details
|
50
|
+
"Saves the current vars in android/fastlane/.env and ios/fastlane/.env"
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.is_supported?(platform)
|
54
|
+
# Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
|
55
|
+
# See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
|
56
|
+
#
|
57
|
+
[:ios, :android].include?(platform)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'fastlane/plugin/cryptex'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class EncryptGooglePlayCredentialsAction < Action
|
7
|
+
def self.run(params)
|
8
|
+
key = Helper::ReactNativeReleaseHelper::GOOGLE_PLAY_CREDENTIALS_CRYPTEX_KEY
|
9
|
+
json_path = params[:json_path]
|
10
|
+
|
11
|
+
begin
|
12
|
+
other_action.cryptex(
|
13
|
+
type: "import",
|
14
|
+
key: key,
|
15
|
+
in: json_path
|
16
|
+
)
|
17
|
+
rescue => ex
|
18
|
+
UI.abort_with_message!('Error encrypting Google Play Credentials.')
|
19
|
+
end
|
20
|
+
|
21
|
+
UI.success("Encrypted #{json_path} as #{key}")
|
22
|
+
end
|
23
|
+
|
24
|
+
#####################################################
|
25
|
+
# @!group Documentation
|
26
|
+
#####################################################
|
27
|
+
|
28
|
+
def self.description
|
29
|
+
"Encrypts credentials from Google Play and stores in the context repo."
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.details
|
33
|
+
# Optional:
|
34
|
+
# this is your chance to provide a more detailed description of this action
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.available_options
|
38
|
+
[
|
39
|
+
FastlaneCore::ConfigItem.new(key: :json_path,
|
40
|
+
env_name: "FL_ENCRYPT_GOOGLE_PLAY_CREDENTIALS_JSON_PATH",
|
41
|
+
description: "Enter path to the json you downloaded from Google, or drop the file here",
|
42
|
+
type: String)
|
43
|
+
]
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.return_value
|
47
|
+
# If your method provides a return value, you can describe here what it does
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.details
|
51
|
+
# "Saves the current vars in android/fastlane/.env and ios/fastlane/.env"
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.authors
|
55
|
+
# So no one will ever forget your contribution to fastlane :) You are awesome btw!
|
56
|
+
["cball", "isaiahgrey93"]
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.is_supported?(platform)
|
60
|
+
[:ios, :android].include?(platform)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'fastlane/plugin/cryptex'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class GenerateAndroidKeystoreAction < Action
|
7
|
+
def self.run(params)
|
8
|
+
encrypt_in_repo = params[:encrypt_in_repo]
|
9
|
+
key = Helper::ReactNativeReleaseHelper::ANDROID_KEYSTORE_CRYPTEX_KEY
|
10
|
+
|
11
|
+
# Confirm if there is an existing key in the repo... we don't want to overwrite prod!
|
12
|
+
begin
|
13
|
+
existing_remote_key = other_action.cryptex(
|
14
|
+
type: "export",
|
15
|
+
key: key
|
16
|
+
)
|
17
|
+
# If we don't have a keystore, cryptex will throw an exception.
|
18
|
+
rescue => ex
|
19
|
+
# create a new keystore and encrypt it
|
20
|
+
UI.message('no keystore found in repo. creating it.')
|
21
|
+
keystore = create_keystore_with_params(params)
|
22
|
+
message = 'Created keystore'
|
23
|
+
|
24
|
+
if encrypt_in_repo
|
25
|
+
encrypt_keystore(keystore)
|
26
|
+
message.concat(' and saved to repo.')
|
27
|
+
end
|
28
|
+
|
29
|
+
UI.success(message)
|
30
|
+
end
|
31
|
+
|
32
|
+
# If encrypting, confirm remote overwrite
|
33
|
+
if (encrypt_in_repo && UI.confirm("This will overwrite your existing keystore! Are you sure?"))
|
34
|
+
keystore_path = create_keystore_with_params(params)
|
35
|
+
encrypt_keystore(keystore_path)
|
36
|
+
UI.success('Created keystore and saved to repo.')
|
37
|
+
elsif encrypt_in_repo
|
38
|
+
# The user does not want to proceed
|
39
|
+
UI.abort_with_message!("Stepping away...")
|
40
|
+
else
|
41
|
+
# Create, but don't encrypt
|
42
|
+
create_keystore_with_params(params)
|
43
|
+
|
44
|
+
UI.success('Created keystore, but did not save it to the repo.')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Creates a new android keystore based on the provided params. Wraps Cryptex.
|
49
|
+
def self.create_keystore_with_params(params)
|
50
|
+
begin
|
51
|
+
other_action.cryptex_generate_keystore(
|
52
|
+
destination: params[:destination],
|
53
|
+
password: params[:password],
|
54
|
+
fullname: params[:fullname],
|
55
|
+
city: params[:city],
|
56
|
+
alias: params[:alias]
|
57
|
+
)
|
58
|
+
rescue => ex
|
59
|
+
UI.abort_with_message!("Could not create keystore. Do you already have one with this alias?")
|
60
|
+
end
|
61
|
+
|
62
|
+
params[:destination]
|
63
|
+
end
|
64
|
+
|
65
|
+
# Saves a keystore to the repo. Note this will overwrite it!
|
66
|
+
def self.encrypt_keystore(keystore_path)
|
67
|
+
key = Helper::ReactNativeReleaseHelper::ANDROID_KEYSTORE_CRYPTEX_KEY
|
68
|
+
|
69
|
+
other_action.cryptex(
|
70
|
+
type: "import",
|
71
|
+
in: keystore_path,
|
72
|
+
key: key
|
73
|
+
)
|
74
|
+
end
|
75
|
+
|
76
|
+
#####################################################
|
77
|
+
# @!group Documentation
|
78
|
+
#####################################################
|
79
|
+
|
80
|
+
def self.description
|
81
|
+
"Decrypts app env vars and sets the values in the root .env file"
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.details
|
85
|
+
# Optional:
|
86
|
+
# this is your chance to provide a more detailed description of this action
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.available_options
|
90
|
+
[
|
91
|
+
FastlaneCore::ConfigItem.new(key: :encrypt_in_repo,
|
92
|
+
env_name: "FL_GENERATE_ANDROID_KEYSTORE_ENCRYPT_IN_REPO",
|
93
|
+
description: "If the new keystore should be encrypted and saved",
|
94
|
+
type: Boolean,
|
95
|
+
default_value: false),
|
96
|
+
FastlaneCore::ConfigItem.new(key: :password,
|
97
|
+
env_name: "FL_GENERATE_ANDROID_KEYSTORE_PASSWORD",
|
98
|
+
description: "Password for the Keystore",
|
99
|
+
type: String),
|
100
|
+
FastlaneCore::ConfigItem.new(key: :alias,
|
101
|
+
env_name: "FL_GENERATE_ANDROID_KEYSTORE_ALIAS",
|
102
|
+
description: "ALIAS for the Keystore",
|
103
|
+
type: String),
|
104
|
+
FastlaneCore::ConfigItem.new(key: :destination,
|
105
|
+
env_name: "FL_GENERATE_ANDROID_KEYSTORE_DESTINATION",
|
106
|
+
description: "Where to put decrypted keystore",
|
107
|
+
default_value: Helper::ReactNativeReleaseHelper::ANDROID_KEYSTORE_PATH),
|
108
|
+
FastlaneCore::ConfigItem.new(key: :fullname,
|
109
|
+
env_name: "FL_GENERATE_ANDROID_KEYSTORE_FULLNAME",
|
110
|
+
description: "Fullname of keystore owner",
|
111
|
+
type: String),
|
112
|
+
FastlaneCore::ConfigItem.new(key: :city,
|
113
|
+
env_name: "FL_GENERATE_ANDROID_KEYSTORE_CITY",
|
114
|
+
description: "City of keystore owner",
|
115
|
+
type: String),
|
116
|
+
]
|
117
|
+
end
|
118
|
+
|
119
|
+
def self.return_value
|
120
|
+
# If your method provides a return value, you can describe here what it does
|
121
|
+
end
|
122
|
+
|
123
|
+
def self.details
|
124
|
+
# "Saves the current vars in android/fastlane/.env and ios/fastlane/.env"
|
125
|
+
end
|
126
|
+
|
127
|
+
def self.authors
|
128
|
+
# So no one will ever forget your contribution to fastlane :) You are awesome btw!
|
129
|
+
["cball", "isaiahgrey93"]
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.is_supported?(platform)
|
133
|
+
[:ios, :android].include?(platform)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -4,45 +4,39 @@ require_relative '../helper/react_native_release_helper'
|
|
4
4
|
module Fastlane
|
5
5
|
module Actions
|
6
6
|
class ReactNativeReleaseAction < Action
|
7
|
-
|
7
|
+
VALID_RELEASE_TYPES = %w{beta release hotfix}
|
8
8
|
|
9
|
+
# params:
|
10
|
+
# release_type, alpha_branch, beta_branch, release_branch, hotfix_destination
|
9
11
|
def self.run(params)
|
10
12
|
require 'fastlane/plugin/android_versioning'
|
11
|
-
|
12
13
|
other_action.create_fastlane_session
|
13
14
|
|
14
|
-
|
15
|
-
is_beta =
|
16
|
-
|
15
|
+
release_type = params[:release_type] || UI.select("Select a release type:", VALID_RELEASE_TYPES)
|
16
|
+
is_beta = release_type.include?('beta')
|
17
|
+
is_release = release_type.include?('release')
|
18
|
+
is_hotfix = release_type.include?('hotfix')
|
19
|
+
|
17
20
|
ios_version = other_action.get_version_number(xcodeproj: params[:xcodeproj], target: File.basename(params[:xcodeproj], '.*'))
|
18
21
|
android_version = other_action.get_version_name(app_project_dir: params[:android_app_dir])
|
19
22
|
should_prompt_for_version_bump = params[:prompt_for_version_bump] === true || is_beta
|
20
23
|
|
21
24
|
if is_beta
|
22
|
-
|
23
|
-
|
24
|
-
target_branch = params[:beta_branch]
|
25
|
-
else
|
26
|
-
tag_prefix = 'releases'
|
27
|
-
base_branch = params[:beta_branch]
|
28
|
-
target_branch = params[:production_branch]
|
25
|
+
# TODO: ohter branches
|
26
|
+
verify_git_branch_state(beta_branch)
|
29
27
|
end
|
30
28
|
|
31
|
-
#
|
32
|
-
other_action.ensure_git_branch(branch: base_branch)
|
33
|
-
other_action.ensure_git_status_clean
|
34
|
-
sh "git branch --set-upstream-to=origin/#{base_branch} #{base_branch}"
|
35
|
-
other_action.git_pull
|
29
|
+
# TODO: flows
|
36
30
|
|
37
31
|
# Cut a fresh branch unless this is a hotfix
|
38
|
-
if !is_hotfix
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
32
|
+
# if !is_hotfix
|
33
|
+
# # delete an existing branch if we have one
|
34
|
+
# sh "git show-ref #{target_branch}" do |status|
|
35
|
+
# sh "git branch -D #{target_branch}" if status.success?
|
36
|
+
# end
|
43
37
|
|
44
|
-
|
45
|
-
end
|
38
|
+
# sh "git checkout -b #{target_branch}"
|
39
|
+
# end
|
46
40
|
|
47
41
|
# Tag / Bump version
|
48
42
|
if should_prompt_for_version_bump
|
@@ -61,13 +55,13 @@ module Fastlane
|
|
61
55
|
end
|
62
56
|
end
|
63
57
|
|
64
|
-
# Tag it
|
65
|
-
tag_name = "
|
58
|
+
# Tag it. TODO: release
|
59
|
+
tag_name = "release/ios-#{ios_version}-android-#{android_version}"
|
66
60
|
other_action.add_git_tag(tag: tag_name)
|
67
|
-
other_action.push_to_git_remote(
|
68
|
-
|
69
|
-
|
70
|
-
)
|
61
|
+
# other_action.push_to_git_remote(
|
62
|
+
# local_branch: target_branch,
|
63
|
+
# force: true
|
64
|
+
# )
|
71
65
|
|
72
66
|
merge_branch(branch: target_branch, target: base_branch)
|
73
67
|
return if is_beta
|
@@ -83,7 +77,7 @@ module Fastlane
|
|
83
77
|
target = options[:target]
|
84
78
|
|
85
79
|
sh "git checkout #{target}"
|
86
|
-
sh "git merge origin/#{branch} --no-ff -m 'Merge #{branch} -> #{target} [skip ci]' " do |status|
|
80
|
+
sh "git merge origin/#{branch} --no-ff -m 'chore(release): Merge #{branch} -> #{target} [skip ci]' " do |status|
|
87
81
|
unless status.success?
|
88
82
|
UI.error "Failed to merge #{branch} into #{target}"
|
89
83
|
end
|
@@ -116,6 +110,14 @@ module Fastlane
|
|
116
110
|
bump_type: version_bump
|
117
111
|
)
|
118
112
|
end
|
113
|
+
|
114
|
+
def self.verify_git_branch_state(branch)
|
115
|
+
# Ensure we're on the right branch and in a good state
|
116
|
+
# other_action.ensure_git_branch(branch)
|
117
|
+
other_action.ensure_git_status_clean
|
118
|
+
sh "git branch --set-upstream-to=origin/#{branch} #{branch}"
|
119
|
+
other_action.git_pull
|
120
|
+
end
|
119
121
|
|
120
122
|
def self.prompt_for_version
|
121
123
|
UI.select("Update Version?: ", ["none", "major", "minor", "patch"])
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'fastlane/action'
|
2
|
+
require 'fastlane/plugin/cryptex'
|
3
|
+
|
4
|
+
module Fastlane
|
5
|
+
module Actions
|
6
|
+
class ReadFastlaneSessionAction < Action
|
7
|
+
def self.run(params)
|
8
|
+
key = Helper::ReactNativeReleaseHelper::FASTLANE_SESSION_CRYPTEX_KEY
|
9
|
+
fastlane_session_git_url = ENV["CRYPTEX_GIT_URL"]
|
10
|
+
fastlane_session_password = ENV["CRYPTEX_PASSWORD"]
|
11
|
+
fastlane_session_cookie_path = Tempfile.new('')
|
12
|
+
|
13
|
+
UI.message "Reading fastlane session.."
|
14
|
+
|
15
|
+
other_action.cryptex(
|
16
|
+
type: "export",
|
17
|
+
out: fastlane_session_cookie_path.path,
|
18
|
+
key: key,
|
19
|
+
)
|
20
|
+
|
21
|
+
fastlane_session = (open fastlane_session_cookie_path.path).read
|
22
|
+
|
23
|
+
UI.message fastlane_session_cookie_path.path
|
24
|
+
UI.message fastlane_session
|
25
|
+
|
26
|
+
ENV["FASTLANE_SESSION"] = fastlane_session
|
27
|
+
|
28
|
+
UI.success "Read FASTLANE_SESSION from remote repository."
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.description
|
32
|
+
"Simplify 2FA authentication for App Store Connect"
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.authors
|
36
|
+
["cball", "isaiahgrey93"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.return_value
|
40
|
+
# If your method provides a return value, you can describe here what it does
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.details
|
44
|
+
"Fetches an encrypted cookie for authenticating with App Store connecting. Handles fetching and decrypting the cookie before setting to the local env."
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.is_supported?(platform)
|
48
|
+
# Adjust this if your plugin only works for a particular platform (iOS vs. Android, for example)
|
49
|
+
# See: https://docs.fastlane.tools/advanced/#control-configuration-by-lane-and-by-platform
|
50
|
+
#
|
51
|
+
[:ios, :android].include?(platform)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -5,11 +5,20 @@ module Fastlane
|
|
5
5
|
|
6
6
|
module Helper
|
7
7
|
class ReactNativeReleaseHelper
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
FASTLANE_CRYPTEX_KEY = 'fastlane_vars'
|
9
|
+
APP_CRYPTEX_KEY = 'app_vars'
|
10
|
+
APP_ENV_PATH = '.env'
|
11
|
+
VALID_NAMESPACES = ['alpha', 'beta', 'release', ''] # empty string denotes root namespace
|
12
|
+
ANDROID_KEYSTORE_CRYPTEX_KEY = 'ANDROID_KEYSTORE'
|
13
|
+
ANDROID_KEYSTORE_PATH = "../app/android.keystore"
|
14
|
+
GOOGLE_PLAY_CREDENTIALS_CRYPTEX_KEY = 'GOOGLE_PLAY_CREDS'
|
15
|
+
FASTLANE_SESSION_CRYPTEX_KEY = 'FASTLANE_SESSION'
|
16
|
+
|
17
|
+
# returns an app key for a specific namespace. Ex: beta_app_vars
|
18
|
+
def self.app_key_for(namespace)
|
19
|
+
return APP_CRYPTEX_KEY if namespace.strip.empty?
|
20
|
+
|
21
|
+
"#{namespace}_#{APP_CRYPTEX_KEY}"
|
13
22
|
end
|
14
23
|
end
|
15
24
|
end
|