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
@@ -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
- VALID_TARGETS = %w{beta production}
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
- target = UI.select "Select a release type:", VALID_TARGETS
15
- is_beta = target.include?('beta')
16
- is_hotfix = params[:hotfix] === true
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
- tag_prefix = 'betas'
23
- base_branch = params[:alpha_branch]
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
- # Ensure we're on the right branch and in a good state
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
- # delete an existing branch if we have one
40
- sh "git show-ref #{target_branch}" do |status|
41
- sh "git branch -D #{target_branch}" if status.success?
42
- end
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
- sh "git checkout -b #{target_branch}"
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 = "#{tag_prefix}/ios-#{ios_version}-android-#{android_version}"
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
- local_branch: target_branch,
69
- force: true
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
- # class methods that you define here become available in your action
9
- # as `Helper::ReactNativeReleaseHelper.your_method`
10
- #
11
- def self.show_message
12
- UI.message("Hello from the react_native_release plugin helper!")
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