fastlane-plugin-flint 0.1.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.
@@ -0,0 +1,211 @@
1
+ require 'fastlane_core/command_executor'
2
+
3
+ require_relative 'change_password'
4
+ require_relative 'encrypt'
5
+
6
+ module Fastlane
7
+ module Flint
8
+ class GitHelper
9
+ FLINT_VERSION_FILE_NAME = "flint_version.txt"
10
+
11
+ def self.clone(git_url,
12
+ shallow_clone,
13
+ manual_password: nil,
14
+ skip_docs: false,
15
+ branch: "master",
16
+ git_full_name: nil,
17
+ git_user_email: nil,
18
+ clone_branch_directly: false,
19
+ encrypt: nil)
20
+ # Note: if you modify the parameters above, don't forget to also update the method call in
21
+ # - flint_action.rb
22
+ # - nuke.rb
23
+ # - change_password.rb
24
+ # - commands_generator.rb
25
+ #
26
+ return @dir if @dir
27
+
28
+ @dir = Dir.mktmpdir
29
+
30
+ command = "git clone '#{git_url}' '#{@dir}'"
31
+ if shallow_clone
32
+ command << " --depth 1 --no-single-branch"
33
+ elsif clone_branch_directly
34
+ command += " -b #{branch.shellescape} --single-branch"
35
+ end
36
+
37
+ UI.message("Cloning remote git repo...")
38
+
39
+ if branch && !clone_branch_directly
40
+ UI.message("If cloning the repo takes too long, you can use the `clone_branch_directly` option in flint.")
41
+ end
42
+
43
+ begin
44
+ # GIT_TERMINAL_PROMPT will fail the `git clone` command if user credentials are missing
45
+ FastlaneCore::CommandExecutor.execute(command: "GIT_TERMINAL_PROMPT=0 #{command}",
46
+ print_all: FastlaneCore::Globals.verbose?,
47
+ print_command: FastlaneCore::Globals.verbose?)
48
+ rescue
49
+ UI.error("Error cloning keystores repo, please make sure you have read access to the repository you want to use")
50
+ if branch && clone_branch_directly
51
+ UI.error("You passed '#{branch}' as branch in combination with the `clone_branch_directly` flag. Please remove `clone_branch_directly` flag on the first run for _flint_ to create the branch.")
52
+ end
53
+ UI.error("Run the following command manually to make sure you're properly authenticated:")
54
+ UI.command(command)
55
+ UI.user_error!("Error cloning keystores git repo, please make sure you have access to the repository - see instructions above")
56
+ end
57
+
58
+ add_user_config(git_full_name, git_user_email)
59
+
60
+ UI.user_error!("Error cloning repo, make sure you have access to it '#{git_url}'") unless File.directory?(@dir)
61
+
62
+ checkout_branch(branch) unless branch == "master"
63
+
64
+ if !Helper.test? && GitHelper.flint_version(@dir).nil? && manual_password.nil? && File.exist?(File.join(@dir, "README.md"))
65
+ UI.important("Migrating to new flint...")
66
+ ChangePassword.update(params: { git_url: git_url,
67
+ git_branch: branch,
68
+ shallow_clone: shallow_clone },
69
+ from: "",
70
+ to: encrypt.password(git_url))
71
+ return self.clone(git_url, shallow_clone)
72
+ end
73
+
74
+ encrypt.decrypt_repo(path: @dir, git_url: git_url, manual_password: manual_password)
75
+
76
+ return @dir
77
+ end
78
+
79
+ def self.generate_commit_message(params)
80
+ # 'Automatic commit via fastlane'
81
+ [
82
+ "[fastlane]",
83
+ "Updated",
84
+ params[:type].to_s,
85
+ "and platform android"
86
+ ].join(" ")
87
+ end
88
+
89
+ def self.flint_version(workspace)
90
+ path = File.join(workspace, FLINT_VERSION_FILE_NAME)
91
+ if File.exist?(path)
92
+ Gem::Version.new(File.read(path))
93
+ end
94
+ end
95
+
96
+ def self.commit_changes(path, message, git_url, branch = "master", files_to_commmit = nil, encrypt = nil)
97
+ files_to_commmit ||= []
98
+ Dir.chdir(path) do
99
+ return if `git status`.include?("nothing to commit")
100
+
101
+ encrypt.encrypt_repo(path: path, git_url: git_url)
102
+ commands = []
103
+
104
+ if files_to_commmit.count > 0 # e.g. for nuke this is treated differently
105
+ if !File.exist?(FLINT_VERSION_FILE_NAME) || File.read(FLINT_VERSION_FILE_NAME) != Fastlane::VERSION.to_s
106
+ files_to_commmit << FLINT_VERSION_FILE_NAME
107
+ File.write(FLINT_VERSION_FILE_NAME, Fastlane::VERSION) # stored unencrypted
108
+ end
109
+
110
+ template = File.read("#{Flint::ROOT}/assets/READMETemplate.md")
111
+ readme_path = "README.md"
112
+ if !File.exist?(readme_path) || File.read(readme_path) != template
113
+ files_to_commmit << readme_path
114
+ File.write(readme_path, template)
115
+ end
116
+
117
+ # `git add` each file we want to commit
118
+ # - Fixes https://github.com/fastlane/fastlane/issues/8917
119
+ # - Fixes https://github.com/fastlane/fastlane/issues/8793
120
+ # - Replaces, closes and fixes https://github.com/fastlane/fastlane/pull/8919
121
+ commands += files_to_commmit.map do |current_file|
122
+ "git add #{current_file.shellescape}"
123
+ end
124
+ else
125
+ # No specific list given, e.g. this happens on `fastlane flint nuke`
126
+ # We just want to run `git add -A` to commit everything
127
+ commands << "git add -A"
128
+ end
129
+ commands << "git commit -m #{message.shellescape}"
130
+ commands << "GIT_TERMINAL_PROMPT=0 git push origin #{branch.shellescape}"
131
+
132
+ UI.message("Pushing changes to remote git repo...")
133
+
134
+ commands.each do |command|
135
+ FastlaneCore::CommandExecutor.execute(command: command,
136
+ print_all: FastlaneCore::Globals.verbose?,
137
+ print_command: FastlaneCore::Globals.verbose?)
138
+ end
139
+ end
140
+ FileUtils.rm_rf(path)
141
+ @dir = nil
142
+ rescue => ex
143
+ UI.error("Couldn't commit or push changes back to git...")
144
+ UI.error(ex)
145
+ end
146
+
147
+ def self.clear_changes
148
+ return unless @dir
149
+
150
+ FileUtils.rm_rf(@dir)
151
+ @dir = nil
152
+ end
153
+
154
+ # Create and checkout an specific branch in the git repo
155
+ def self.checkout_branch(branch)
156
+ return unless @dir
157
+
158
+ commands = []
159
+ if branch_exists?(branch)
160
+ # Checkout the branch if it already exists
161
+ commands << "git checkout #{branch.shellescape}"
162
+ else
163
+ # If a new branch is being created, we create it as an 'orphan' to not inherit changes from the master branch.
164
+ commands << "git checkout --orphan #{branch.shellescape}"
165
+ # We also need to reset the working directory to not transfer any uncommitted changes to the new branch.
166
+ commands << "git reset --hard"
167
+ end
168
+
169
+ UI.message("Checking out branch #{branch}...")
170
+
171
+ Dir.chdir(@dir) do
172
+ commands.each do |command|
173
+ FastlaneCore::CommandExecutor.execute(command: command,
174
+ print_all: FastlaneCore::Globals.verbose?,
175
+ print_command: FastlaneCore::Globals.verbose?)
176
+ end
177
+ end
178
+ end
179
+
180
+ # Checks if a specific branch exists in the git repo
181
+ def self.branch_exists?(branch)
182
+ return unless @dir
183
+
184
+ result = Dir.chdir(@dir) do
185
+ FastlaneCore::CommandExecutor.execute(command: "git --no-pager branch --list origin/#{branch.shellescape} --no-color -r",
186
+ print_all: FastlaneCore::Globals.verbose?,
187
+ print_command: FastlaneCore::Globals.verbose?)
188
+ end
189
+ return !result.empty?
190
+ end
191
+
192
+ def self.add_user_config(user_name, user_email)
193
+ # Add git config if needed
194
+ commands = []
195
+ commands << "git config user.name \"#{user_name}\"" unless user_name.nil?
196
+ commands << "git config user.email \"#{user_email}\"" unless user_email.nil?
197
+
198
+ return if commands.empty?
199
+
200
+ UI.message("Add git user config to local git repo...")
201
+ Dir.chdir(@dir) do
202
+ commands.each do |command|
203
+ FastlaneCore::CommandExecutor.execute(command: command,
204
+ print_all: FastlaneCore::Globals.verbose?,
205
+ print_command: FastlaneCore::Globals.verbose?)
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,119 @@
1
+ require 'terminal-table'
2
+
3
+ require 'fastlane_core/print_table'
4
+
5
+ require_relative 'git_helper'
6
+ require_relative 'encrypt'
7
+
8
+ module Fastlane
9
+ module Flint
10
+ class Nuke
11
+ attr_accessor :params
12
+ attr_accessor :type
13
+
14
+ attr_accessor :files
15
+
16
+ def run(params, type: nil)
17
+ self.params = params
18
+ self.type = type
19
+
20
+ params[:workspace] = GitHelper.clone(params[:git_url],
21
+ params[:shallow_clone],
22
+ skip_docs: params[:skip_docs],
23
+ branch: params[:git_branch],
24
+ git_full_name: params[:git_full_name],
25
+ git_user_email: params[:git_user_email],
26
+ clone_branch_directly: params[:clone_branch_directly],
27
+ encrypt: Encrypt.new)
28
+
29
+ had_app_identifier = self.params.fetch(:app_identifier, ask: false)
30
+ self.params[:app_identifier] = '' # we don't really need a value here
31
+ FastlaneCore::PrintTable.print_values(config: params,
32
+ hide_keys: [:app_identifier, :workspace],
33
+ title: "Summary for flint nuke #{Fastlane::VERSION}")
34
+
35
+ prepare_list
36
+ print_tables
37
+
38
+ if params[:readonly]
39
+ UI.user_error!("`fastlane flint nuke` doesn't delete anything when running with --readonly enabled")
40
+ end
41
+
42
+ if (self.files).count > 0
43
+ unless params[:skip_confirmation]
44
+ if type == "release"
45
+ UI.confirm(
46
+ "DANGER: By nuking release keys you might not " +
47
+ "be able to update your app in the play store. Are you sure?"
48
+ )
49
+ end
50
+ UI.error("---")
51
+ UI.error("Are you sure you want to completely delete and revoke all the")
52
+ UI.error("keystores listed above? (y/n)")
53
+ UI.error("---")
54
+ end
55
+ if params[:skip_confirmation] || UI.confirm("Do you really want to nuke everything listed above?")
56
+ nuke_it_now!
57
+ UI.success("Successfully cleaned up ♻️")
58
+ else
59
+ UI.success("Cancelled nuking #thanks 🏠 👨 ‍👩 ‍👧")
60
+ end
61
+ else
62
+ UI.success("No relevant keystores found, nothing to nuke here :)")
63
+ end
64
+ end
65
+
66
+ # Collect all the keystores
67
+ def prepare_list
68
+ UI.message("Fetching keystores...")
69
+ cert_type = Flint.cert_type_sym(type)
70
+
71
+ certs = Dir[File.join(params[:workspace], "**", "*-#{cert_type.to_s}.keystore")]
72
+
73
+ self.files = certs
74
+ end
75
+
76
+ # Print tables to ask the user
77
+ def print_tables
78
+ puts("")
79
+ if self.files.count > 0
80
+ rows = self.files.collect do |f|
81
+ components = f.split(File::SEPARATOR)[-3..-1]
82
+ file_type = components[0..1].reverse.join(" ")[0..-2]
83
+
84
+ [file_type, components[2]]
85
+ end
86
+ puts(Terminal::Table.new({
87
+ title: "Files that are going to be deleted".green,
88
+ headings: ["Type", "File Name"],
89
+ rows: rows
90
+ }))
91
+ puts("")
92
+ end
93
+ end
94
+
95
+ def nuke_it_now!
96
+ if self.files.count > 0
97
+ delete_files!
98
+ end
99
+
100
+ # Now we need to commit and push all this too
101
+ message = ["[fastlane]", "Nuked", "files", "for", type.to_s].join(" ")
102
+ GitHelper.commit_changes(params[:workspace], message, self.params[:git_url], params[:git_branch], nil, Encrypt.new)
103
+ end
104
+
105
+ private
106
+
107
+ def delete_files!
108
+ UI.header("Deleting #{self.files.count} files from the git repo...")
109
+
110
+ self.files.each do |file|
111
+ UI.message("Deleting file '#{File.basename(file)}'...")
112
+
113
+ File.delete(file)
114
+ UI.success("Successfully deleted file")
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,31 @@
1
+ require 'terminal-table'
2
+
3
+ require 'fastlane_core/print_table'
4
+
5
+ require_relative 'utils'
6
+
7
+ module Fastlane
8
+ module Flint
9
+ class TablePrinter
10
+ def self.print_summary(app_identifier: nil, type: nil, platform: :android, keystore_name: nil)
11
+ rows = []
12
+
13
+ type = type.to_sym
14
+
15
+ rows << ["App Identifier", "", app_identifier]
16
+ rows << ["Type", "", type]
17
+ rows << ["Platform", "", platform.to_s]
18
+ rows << ["Keystore", "", keystore_name]
19
+
20
+ params = {}
21
+ params[:rows] = FastlaneCore::PrintTable.transform_output(rows)
22
+ params[:title] = "Installed Keystores".green
23
+ params[:headings] = ['Parameter', 'Environment Variable', 'Value']
24
+
25
+ puts("")
26
+ puts(Terminal::Table.new(params))
27
+ puts("")
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,49 @@
1
+ require 'digest'
2
+ require 'fileutils'
3
+ require 'openssl'
4
+
5
+
6
+ module Fastlane
7
+ module Flint
8
+ class Utils
9
+ def self.import(item_path, target_path, keystore_name, alias_name, password)
10
+ FileUtils.cp(item_path, target_path)
11
+ end
12
+
13
+ def self.activate(keystore_name, alias_name, password, keystore_properties_path)
14
+ template = File.read("#{Flint::ROOT}/assets/KeystorePropertiesTemplate")
15
+ template.gsub!("[[STORE_FILE]]", keystore_name)
16
+ template.gsub!("[[KEY_ALIAS]]", alias_name)
17
+ template.gsub!("[[PASSWORD]]", password)
18
+ File.write(keystore_properties_path, template)
19
+
20
+ # We could test that the required lines are added to build.gradle
21
+ end
22
+
23
+ def self.installed?(item_path, target_path)
24
+ if File.exist?(target_path)
25
+ installed_digest = Digest::MD5.hexdigest File.read target_path
26
+ item_digest = Digest::MD5.hexdigest File.read item_path
27
+
28
+ return installed_digest == item_digest
29
+ end
30
+
31
+ return false
32
+ end
33
+
34
+ def self.get_keystore_info(item_path, password)
35
+ cmd =
36
+ begin
37
+ output = IO.popen("keytool -list -v -keystore '#{item_path}' -storepass '#{password}'")
38
+ lines = output.readlines
39
+ output.close
40
+ raise lines.join unless $?.exitstatus == 0
41
+ rescue => ex
42
+ raise ex
43
+ end
44
+
45
+ return lines
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,5 @@
1
+ module Fastlane
2
+ module Flint
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,189 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: fastlane-plugin-flint
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jyrno Ader
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-12-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: pry
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec_junit_formatter
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '='
88
+ - !ruby/object:Gem::Version
89
+ version: 0.49.1
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - '='
95
+ - !ruby/object:Gem::Version
96
+ version: 0.49.1
97
+ - !ruby/object:Gem::Dependency
98
+ name: rubocop-require_tools
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: fastlane
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 2.109.1
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: 2.109.1
139
+ description:
140
+ email: jyrno42@gmail.com
141
+ executables: []
142
+ extensions: []
143
+ extra_rdoc_files: []
144
+ files:
145
+ - LICENSE
146
+ - README.md
147
+ - lib/assets/FlintfileTemplate
148
+ - lib/assets/KeystorePropertiesTemplate
149
+ - lib/assets/READMETemplate.md
150
+ - lib/fastlane/plugin/flint.rb
151
+ - lib/fastlane/plugin/flint/actions/flint_action.rb
152
+ - lib/fastlane/plugin/flint/actions/flint_change_password.rb
153
+ - lib/fastlane/plugin/flint/actions/flint_nuke.rb
154
+ - lib/fastlane/plugin/flint/actions/flint_setup.rb
155
+ - lib/fastlane/plugin/flint/helper/change_password.rb
156
+ - lib/fastlane/plugin/flint/helper/commands_generator.rb
157
+ - lib/fastlane/plugin/flint/helper/encrypt.rb
158
+ - lib/fastlane/plugin/flint/helper/flint_helper.rb
159
+ - lib/fastlane/plugin/flint/helper/generator.rb
160
+ - lib/fastlane/plugin/flint/helper/git_helper.rb
161
+ - lib/fastlane/plugin/flint/helper/nuke.rb
162
+ - lib/fastlane/plugin/flint/helper/table_printer.rb
163
+ - lib/fastlane/plugin/flint/helper/utils.rb
164
+ - lib/fastlane/plugin/flint/version.rb
165
+ homepage: https://github.com/jyrno42/fastlane-plugin-flint
166
+ licenses:
167
+ - MIT
168
+ metadata: {}
169
+ post_install_message:
170
+ rdoc_options: []
171
+ require_paths:
172
+ - lib
173
+ required_ruby_version: !ruby/object:Gem::Requirement
174
+ requirements:
175
+ - - ">="
176
+ - !ruby/object:Gem::Version
177
+ version: '0'
178
+ required_rubygems_version: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - ">="
181
+ - !ruby/object:Gem::Version
182
+ version: '0'
183
+ requirements: []
184
+ rubyforge_project:
185
+ rubygems_version: 2.7.6
186
+ signing_key:
187
+ specification_version: 4
188
+ summary: Easily sync your keystores across your team using git
189
+ test_files: []