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