fastlane-plugin-wpmreleasetoolkit 1.3.1 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_betabuild_prechecks.rb +11 -17
  3. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_build_prechecks.rb +5 -10
  4. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_bump_version_beta.rb +9 -16
  5. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_bump_version_final_release.rb +8 -15
  6. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_bump_version_hotfix.rb +13 -22
  7. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_bump_version_release.rb +11 -18
  8. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_codefreeze_prechecks.rb +4 -10
  9. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_completecodefreeze_prechecks.rb +2 -8
  10. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_current_branch_is_hotfix.rb +1 -7
  11. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_download_file_by_version.rb +1 -1
  12. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_finalize_prechecks.rb +2 -6
  13. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_get_alpha_version.rb +1 -7
  14. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_get_app_version.rb +1 -7
  15. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_get_release_version.rb +1 -7
  16. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_hotifx_prechecks.rb +4 -4
  17. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_tag_build.rb +2 -8
  18. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/check_translation_progress.rb +1 -1
  19. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/comment_on_pr.rb +89 -0
  20. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/create_release_action.rb +3 -1
  21. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_bump_version_hotfix.rb +30 -15
  22. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_generate_strings_file_from_code.rb +115 -0
  23. data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_localize_project.rb +5 -6
  24. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/an_metadata_update_helper.rb +1 -1
  25. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/android/android_git_helper.rb +1 -1
  26. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/android/android_version_helper.rb +33 -68
  27. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/filesystem_helper.rb +3 -1
  28. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb +48 -8
  29. data/lib/fastlane/plugin/wpmreleasetoolkit/helper/interactive_prompt_reminder.rb +93 -0
  30. data/lib/fastlane/plugin/wpmreleasetoolkit/version.rb +1 -1
  31. metadata +27 -4
@@ -0,0 +1,89 @@
1
+ require 'fastlane/action'
2
+
3
+ module Fastlane
4
+ module Actions
5
+ module SharedValues
6
+ PR_COMMENT_REUSE_IDENTIFIER = :PR_COMMENT_REUSE_IDENTIFIER
7
+ end
8
+
9
+ class CommentOnPrAction < Action
10
+ def self.run(params)
11
+ require_relative '../../helper/github_helper'
12
+
13
+ reuse_identifier = Fastlane::Helper::GithubHelper.comment_on_pr(
14
+ project_slug: params[:project],
15
+ pr_number: params[:pr_number],
16
+ body: params[:body],
17
+ reuse_identifier: params[:reuse_identifier]
18
+ )
19
+
20
+ Actions.lane_context[SharedValues::PR_COMMENT_REUSE_IDENTIFIER] = reuse_identifier
21
+
22
+ reuse_identifier
23
+ end
24
+
25
+ def self.description
26
+ 'Post a comment on a given PR number (optionally updating an existing one)'
27
+ end
28
+
29
+ def self.authors
30
+ ['Automattic']
31
+ end
32
+
33
+ def self.details
34
+ <<~DETAILS
35
+ If used just once, this method makes it nice and easy to post a quick comment to a GitHub PR.
36
+
37
+ Subsequent runs will allow you to update an existing comment as many times as you need to
38
+ (e.g. across multiple CI runs), by using a `:reuse_identifier` to identify the comment to update.
39
+ DETAILS
40
+ end
41
+
42
+ def self.available_options
43
+ [
44
+ FastlaneCore::ConfigItem.new(
45
+ key: :access_token,
46
+ env_name: 'GITHUB_TOKEN',
47
+ description: 'The GitHub token to use for posting the comment',
48
+ type: String
49
+ ),
50
+ FastlaneCore::ConfigItem.new(
51
+ key: :reuse_identifier,
52
+ description: 'If provided, the reuse identifier can identify an existing comment to overwrite',
53
+ type: String,
54
+ default_value: nil
55
+ ),
56
+ FastlaneCore::ConfigItem.new(
57
+ key: :project,
58
+ description: 'The project slug (ex: `wordpress-mobile/wordpress-ios`)',
59
+ type: String
60
+ ),
61
+ FastlaneCore::ConfigItem.new(
62
+ key: :pr_number,
63
+ description: 'The PR number',
64
+ type: Integer
65
+ ),
66
+ FastlaneCore::ConfigItem.new(
67
+ key: :body,
68
+ description: 'The content of the comment',
69
+ type: String
70
+ ),
71
+ ]
72
+ end
73
+
74
+ def self.output
75
+ [
76
+ ['PR_COMMENT_REUSE_IDENTIFIER', 'The `reuse_identifier` for the most recently posted comment'],
77
+ ]
78
+ end
79
+
80
+ def self.return_value
81
+ 'The `reuse_identifier` for the posted comment (useful for updating it later, if needed)'
82
+ end
83
+
84
+ def self.is_supported?(platform)
85
+ true
86
+ end
87
+ end
88
+ end
89
+ end
@@ -10,7 +10,9 @@ module Fastlane
10
10
  repository = params[:repository]
11
11
  version = params[:version]
12
12
  assets = params[:release_assets]
13
- release_notes = params[:release_notes_file_path].nil? ? '' : IO.read(params[:release_notes_file_path])
13
+ release_notes = params[:release_notes_file_path].nil? ? '' : File.read(params[:release_notes_file_path])
14
+ # Replace full URLS to PRs/Issues with shorthand, because GitHub does not render them properly otherwise.
15
+ release_notes.gsub!(%r{https://github.com/([^/]*/[^/]*)/(pulls?|issues?)/([0-9]*)}, '\1#\3')
14
16
  prerelease = params[:prerelease]
15
17
 
16
18
  UI.message("Creating draft release #{version} in #{repository}.")
@@ -9,14 +9,18 @@ module Fastlane
9
9
  create_config(params[:previous_version], params[:version])
10
10
  show_config()
11
11
 
12
- UI.message 'Updating Fastlane deliver file...'
13
- Fastlane::Helper::Ios::VersionHelper.update_fastlane_deliver(@new_short_version)
14
- UI.message 'Done!'
12
+ update_deliverfile = params[:skip_deliver] == false
13
+ if update_deliverfile
14
+ UI.message 'Updating Fastlane deliver file...'
15
+ Fastlane::Helper::Ios::VersionHelper.update_fastlane_deliver(@new_short_version)
16
+ UI.message 'Done!'
17
+ end
18
+
15
19
  UI.message 'Updating XcConfig...'
16
20
  Fastlane::Helper::Ios::VersionHelper.update_xc_configs(@new_version, @new_short_version, @new_version_internal)
17
21
  UI.message 'Done!'
18
22
 
19
- Fastlane::Helper::Ios::GitHelper.commit_version_bump(include_deliverfile: true, include_metadata: false)
23
+ Fastlane::Helper::Ios::GitHelper.commit_version_bump(include_deliverfile: update_deliverfile, include_metadata: false)
20
24
 
21
25
  UI.message 'Done.'
22
26
  end
@@ -34,18 +38,29 @@ module Fastlane
34
38
  end
35
39
 
36
40
  def self.available_options
37
- # Define all options your action supports.
38
-
39
- # Below a few examples
40
41
  [
41
- FastlaneCore::ConfigItem.new(key: :version,
42
- env_name: 'FL_IOS_BUMP_VERSION_HOTFIX_VERSION',
43
- description: 'The version of the hotfix',
44
- is_string: true),
45
- FastlaneCore::ConfigItem.new(key: :previous_version,
46
- env_name: 'FL_IOS_BUMP_VERSION_HOTFIX_PREVIOUS_VERSION',
47
- description: 'The version to branch from',
48
- is_string: true), # the default value if the user didn't provide one
42
+ FastlaneCore::ConfigItem.new(
43
+ key: :version,
44
+ env_name: 'FL_IOS_BUMP_VERSION_HOTFIX_VERSION',
45
+ description: 'The version of the hotfix',
46
+ is_string: true
47
+ ),
48
+ FastlaneCore::ConfigItem.new(
49
+ key: :previous_version,
50
+ env_name: 'FL_IOS_BUMP_VERSION_HOTFIX_PREVIOUS_VERSION',
51
+ description: 'The version to branch from',
52
+ is_string: true
53
+ ),
54
+ FastlaneCore::ConfigItem.new(
55
+ key: :skip_deliver,
56
+ env_name: 'FL_IOS_BUMP_VERSION_HOTFIX_SKIP_DELIVER',
57
+ description: 'Skips Deliverfile key update',
58
+ is_string: false, # Boolean parameter
59
+ optional: true,
60
+ # Don't skip the Deliverfile by default. At the time of writing, 2 out of 3 consumers
61
+ # still have a Deliverfile.
62
+ default_value: false
63
+ ),
49
64
  ]
50
65
  end
51
66
 
@@ -0,0 +1,115 @@
1
+ module Fastlane
2
+ module Actions
3
+ class IosGenerateStringsFileFromCodeAction < Action
4
+ def self.run(params)
5
+ files = files_matching(paths: params[:paths], exclude: params[:exclude])
6
+ flags = [('-q' if params[:quiet]), ('-SwiftUI' if params[:swiftui])].compact
7
+ flags += Array(params[:routines]).flat_map { |routine| ['-s', routine] }
8
+ cmd = ['genstrings', '-o', params[:output_dir], *flags, *files]
9
+ out = Actions.sh_control_output(*cmd, print_command: FastlaneCore::Globals.verbose?, print_command_output: true)
10
+ out = out.scrub.strip.split("\n")
11
+ errors = out.select { |line| line.include?('genstrings: error: ') }
12
+ UI.user_error!(errors.join("\n")) unless !params[:fail_on_error] || errors.empty?
13
+ out
14
+ end
15
+
16
+ # Adds the proper `**/*.{m,swift}` to the list of paths
17
+ def self.glob_pattern(path)
18
+ if path.end_with?('**') || path.end_with?('**/')
19
+ File.join(path, '*.{m,swift}')
20
+ elsif File.directory?(path) || path.end_with?('/')
21
+ File.join(path, '**', '*.{m,swift}')
22
+ else
23
+ path
24
+ end
25
+ end
26
+
27
+ def self.files_matching(paths:, exclude:)
28
+ globbed_paths = paths.map { |p| glob_pattern(p) }
29
+ Dir.glob(globbed_paths).reject do |file|
30
+ exclude&.any? { |ex| File.fnmatch?(ex, file) }
31
+ end
32
+ end
33
+
34
+ #####################################################
35
+ # @!group Documentation
36
+ #####################################################
37
+
38
+ def self.description
39
+ 'Generate the .strings files from your Objective-C and Swift code'
40
+ end
41
+
42
+ def self.details
43
+ <<~DETAILS
44
+ Uses `genstrings` to generate the `.strings` files from your Objective-C and Swift code.
45
+ (especially `Localizable.strings` but it could generate more if the code uses custom tables).
46
+
47
+ You can provide a list of paths to scan but also paths to exclude. Both supports glob patterns.
48
+ You can also optionally provide a list of custom "routines" (aka macros or functions) that
49
+ `genstrings` should parse in addition to the usual `NSLocalizedString`. (see `-s` option of `genstrings`).
50
+
51
+ Tip: support for custom routines is useful if some of your targets define a helper function e.g.
52
+ `PodLocalizedString` to wrap calls to `Bundle.localizedString(forKey: key, value: value, table: nil)`,
53
+ just like the build-in `NSLocalizedString` does, but providing a custom bundle to look up the strings from.
54
+ DETAILS
55
+ end
56
+
57
+ def self.available_options
58
+ [
59
+ FastlaneCore::ConfigItem.new(key: :paths,
60
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_PATHS',
61
+ description: 'Array of paths to scan for `.m` and `.swift` files. The entries can also contain glob patterns',
62
+ type: Array,
63
+ default_value: ['.']),
64
+ FastlaneCore::ConfigItem.new(key: :exclude,
65
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_EXCLUDE',
66
+ description: 'Array of paths or glob patterns to exclude from scanning',
67
+ type: Array,
68
+ default_value: []),
69
+ FastlaneCore::ConfigItem.new(key: :routines,
70
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_ROUTINES',
71
+ description: 'Base name of the alternate methods to be parsed in addition to the standard `NSLocalizedString()` one. See the `-s` option in `man genstrings`',
72
+ type: Array,
73
+ default_value: []),
74
+ FastlaneCore::ConfigItem.new(key: :quiet,
75
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_QUIET',
76
+ description: 'In quiet mode, `genstrings` will log warnings about duplicate values, but not about duplicate comments',
77
+ is_string: false, # Boolean
78
+ default_value: true),
79
+ FastlaneCore::ConfigItem.new(key: :swiftui,
80
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_SWIFTUI',
81
+ description: "Should we include SwiftUI's `Text()` when parsing code with `genstrings`",
82
+ is_string: false, # Boolean
83
+ default_value: false),
84
+ FastlaneCore::ConfigItem.new(key: :output_dir,
85
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_OUTPUT_DIR',
86
+ description: 'The path to the directory where the generated `.strings` files should be created',
87
+ type: String),
88
+ FastlaneCore::ConfigItem.new(key: :fail_on_error,
89
+ env_name: 'FL_IOS_GENERATE_STRINGS_FILE_FROM_CODE_FAIL_ON_ERROR',
90
+ description: 'If true, will fail with user_error! if `genstrings` printed any error while parsing',
91
+ is_string: false, # Boolean
92
+ default_value: true),
93
+ ]
94
+ end
95
+
96
+ def self.return_type
97
+ # Describes what type of data is expected to be returned
98
+ # see RETURN_TYPES in https://github.com/fastlane/fastlane/blob/master/fastlane/lib/fastlane/action.rb
99
+ :array_of_strings
100
+ end
101
+
102
+ def self.return_value
103
+ 'List of warning lines generated by genstrings on stdout'
104
+ end
105
+
106
+ def self.authors
107
+ ['Automattic']
108
+ end
109
+
110
+ def self.is_supported?(platform)
111
+ [:ios, :mac].include?(platform)
112
+ end
113
+ end
114
+ end
115
+ end
@@ -20,16 +20,15 @@ module Fastlane
20
20
  end
21
21
 
22
22
  def self.details
23
- 'Gathers the string to localise'
24
- end
25
-
26
- def self.available_options
23
+ 'Gathers the string to localise. Deprecated in favor of the new `ios_generate_strings_file_from_code`'
27
24
  end
28
25
 
29
- def self.output
26
+ def self.category
27
+ :deprecated
30
28
  end
31
29
 
32
- def self.return_value
30
+ def self.deprecated_notes
31
+ 'This action is deprecated in favor of `ios_generate_strings_file_from_code`'
33
32
  end
34
33
 
35
34
  def self.authors
@@ -50,7 +50,7 @@ module Fastlane
50
50
 
51
51
  if line_count <= 1
52
52
  # Single line output
53
- fw.puts("msgid \"#{File.open(@content_file_path, 'r').read}\"")
53
+ fw.puts("msgid \"#{File.open(@content_file_path, 'r').read.rstrip}\"")
54
54
  else
55
55
  # Multiple line output
56
56
  fw.puts('msgid ""')
@@ -13,7 +13,7 @@ module Fastlane
13
13
  #
14
14
  def self.commit_version_bump
15
15
  require_relative './android_version_helper'
16
- if Fastlane::Helper::Android::VersionHelper.properties_file_exists
16
+ if File.exist?(Fastlane::Helper::Android::VersionHelper.version_properties_file)
17
17
  Fastlane::Helper::GitHelper.commit(
18
18
  message: 'Bump version number',
19
19
  files: File.join(ENV['PROJECT_ROOT_FOLDER'], 'version.properties'),
@@ -26,14 +26,12 @@ module Fastlane
26
26
  # "1.2" # Assuming build.gradle contains versionName "1.2.0"
27
27
  # "1.2.3" # Assuming build.gradle contains versionName "1.2.3"
28
28
  #
29
- # @param [String] app The name of the app to be used for beta and alpha version update
30
- #
31
29
  # @return [String] The public-facing version number, extracted from the `versionName` of the `build.gradle` file.
32
30
  # - If this version is a hotfix (more than 2 parts and 3rd part is non-zero), returns the "X.Y.Z" formatted string
33
31
  # - Otherwise (not a hotfix / 3rd part of version is 0), returns "X.Y" formatted version number
34
32
  #
35
- def self.get_public_version(app)
36
- version = get_release_version(product_name: app)
33
+ def self.get_public_version
34
+ version = get_release_version
37
35
  vp = get_version_parts(version[VERSION_NAME])
38
36
  return "#{vp[MAJOR_NUMBER]}.#{vp[MINOR_NUMBER]}" unless is_hotfix?(version)
39
37
 
@@ -42,12 +40,10 @@ module Fastlane
42
40
 
43
41
  # Extract the version name and code from the release version of the app from `version.properties file`
44
42
  #
45
- # @param [String] product_name The name of the app to be used for beta and alpha version update
46
- #
47
43
  # @return [Hash] A hash with 2 keys "name" and "code" containing the extracted version name and code, respectively
48
44
  #
49
- def self.get_release_version(product_name:)
50
- return get_version_from_properties(product_name: product_name) if properties_file_exists
45
+ def self.get_release_version
46
+ return get_version_from_properties() if File.exist?(version_properties_file)
51
47
 
52
48
  section = ENV['HAS_ALPHA_VERSION'].nil? ? 'defaultConfig' : 'vanilla {'
53
49
  gradle_path = self.gradle_path
@@ -56,66 +52,36 @@ module Fastlane
56
52
  return { VERSION_NAME => name, VERSION_CODE => code }
57
53
  end
58
54
 
59
- def self.properties_file_exists
60
- properties_file_path = File.join(ENV['PROJECT_ROOT_FOLDER'] || '.', 'version.properties')
61
-
62
- return File.exist?(properties_file_path)
55
+ def self.version_properties_file
56
+ File.join(ENV['PROJECT_ROOT_FOLDER'] || '.', 'version.properties')
63
57
  end
64
58
 
65
59
  # Extract the version name and code from the `version.properties` file in the project root
66
60
  #
67
- # @param [String] product_name The name of the app to extract the version from e.g. wordpress, simplenote
68
61
  # @param [Boolean] is_alpha true if the alpha version should be returned, false otherwise
69
62
  #
70
63
  # @return [Hash] A hash with 2 keys "name" and "code" containing the extracted version name and code, respectively
71
64
  #
72
- def self.get_version_from_properties(product_name:, is_alpha: false)
73
- alpha_variant = is_alpha ? alpha_flavor_name : nil
74
- version_name_key = [product_name, alpha_variant, 'versionName'].compact.join('.')
75
- version_code_key = [product_name, alpha_variant, 'versionCode'].compact.join('.')
65
+ def self.get_version_from_properties(is_alpha: false)
66
+ return nil unless File.exist?(version_properties_file)
76
67
 
77
- properties_file_path = File.join(ENV['PROJECT_ROOT_FOLDER'] || '.', 'version.properties')
68
+ version_name_key = is_alpha ? 'alpha.versionName' : 'versionName'
69
+ version_code_key = is_alpha ? 'alpha.versionCode' : 'versionCode'
78
70
 
79
- return nil unless File.exist?(properties_file_path)
80
-
81
- File.open(properties_file_path, 'r') do |f|
82
- text = f.read
83
- name = text.match(/#{version_name_key}=(\S*)/m)&.captures&.first
84
- code = text.match(/#{version_code_key}=(\S*)/m)&.captures&.first
71
+ text = File.read(version_properties_file)
72
+ name = text.match(/#{version_name_key}=(\S*)/m)&.captures&.first
73
+ code = text.match(/#{version_code_key}=(\S*)/m)&.captures&.first
85
74
 
86
- f.close
87
-
88
- return nil if name.nil? || code.nil?
89
-
90
- return { VERSION_NAME => name, VERSION_CODE => code.to_i }
91
- end
92
- end
93
-
94
- # Returns the name of the flavor used for alpha builds
95
- #
96
- # @env HAS_ALPHA_VERSION Should contain the name of the flavor used for alpha
97
- #
98
- # @return [String] The flavor name as provided by the env var, defaulting to `zalpha` if the env var
99
- # is not set or is set to '1' ('boolean' value used in legacy call sites)
100
- def self.alpha_flavor_name
101
- # TODO: Have each fastlane action which depends on this take the alpha flavor name as ConfigItem/parameter
102
- # explicitly instead (and get rid of the HAS_ALPHA_VERSION global / env var after that)
103
-
104
- # For now we pass the alpha flavor name by reusing the HAS_ALPHA_VERSION env var.
105
- return ENV['HAS_ALPHA_VERSION'] if ENV['HAS_ALPHA_VERSION'] && ENV['HAS_ALPHA_VERSION'] != '1'
106
-
107
- 'zalpha' # Default value if HAS_ALPHA_VERSION is not set or hasn't been updated at call site to the flavor name instead of '1'
75
+ return name.nil? || code.nil? ? nil : { VERSION_NAME => name, VERSION_CODE => code.to_i }
108
76
  end
109
77
 
110
78
  # Extract the version name and code from the `version.properties` file in the project root
111
79
  #
112
- # @param [String] app The name of the app to be used for beta and alpha version update
113
- #
114
80
  # @return [Hash] A hash with 2 keys `"name"` and `"code"` containing the extracted version name and code, respectively,
115
81
  # or `nil` if `$HAS_ALPHA_VERSION` is not defined.
116
82
  #
117
- def self.get_alpha_version(app)
118
- return get_version_from_properties(product_name: app, is_alpha: true) if properties_file_exists
83
+ def self.get_alpha_version
84
+ return get_version_from_properties(is_alpha: true) if File.exist?(version_properties_file)
119
85
 
120
86
  return nil if ENV['HAS_ALPHA_VERSION'].nil?
121
87
 
@@ -312,12 +278,11 @@ module Fastlane
312
278
 
313
279
  # Prints the current and next release version names to stdout, then returns the next release version
314
280
  #
315
- # @param [String] app The name of the app to be used for beta and alpha version update
316
281
  # @return [String] The next release version name to use after bumping the currently used release version.
317
282
  #
318
- def self.bump_version_release(app)
283
+ def self.bump_version_release
319
284
  # Bump release
320
- current_version = get_release_version(product_name: app)
285
+ current_version = self.get_release_version
321
286
  UI.message("Current version: #{current_version[VERSION_NAME]}")
322
287
  new_version = calc_next_release_base_version(current_version)
323
288
  UI.message("New version: #{new_version[VERSION_NAME]}")
@@ -328,24 +293,24 @@ module Fastlane
328
293
 
329
294
  # Update the `version.properties` file with new `versionName` and `versionCode` values
330
295
  #
331
- # @param [String] app The name of the app to be used for beta and alpha version update
332
296
  # @param [Hash] new_version_beta The version hash for the beta, containing values for keys "name" and "code"
333
297
  # @param [Hash] new_version_alpha The version hash for the alpha , containing values for keys "name" and "code"
334
298
  #
335
- def self.update_versions(app, new_version_beta, new_version_alpha)
336
- if properties_file_exists
337
- new_version_name_beta_key = "#{app}.versionName"
338
- new_version_code_beta_key = "#{app}.versionCode"
339
- Action.sh('./gradlew', 'updateVersionProperties', "-Pkey=#{new_version_name_beta_key}", "-Pvalue=#{new_version_beta[VERSION_NAME]}")
340
- Action.sh('./gradlew', 'updateVersionProperties', "-Pkey=#{new_version_code_beta_key}", "-Pvalue=#{new_version_beta[VERSION_CODE]}")
341
-
342
- unless new_version_alpha.nil?
343
- new_version_name_alpha_key = "#{app}.#{alpha_flavor_name}.versionName"
344
- new_version_code_alpha_key = "#{app}.#{alpha_flavor_name}.versionCode"
345
-
346
- Action.sh('./gradlew', 'updateVersionProperties', "-Pkey=#{new_version_name_alpha_key}", "-Pvalue=#{new_version_alpha[VERSION_NAME]}") unless new_version_alpha.nil?
347
- Action.sh('./gradlew', 'updateVersionProperties', "-Pkey=#{new_version_code_alpha_key}", "-Pvalue=#{new_version_alpha[VERSION_CODE]}") unless new_version_alpha.nil?
299
+ def self.update_versions(new_version_beta, new_version_alpha)
300
+ if File.exist?(version_properties_file)
301
+ replacements = {
302
+ versionName: (new_version_beta || {})[VERSION_NAME],
303
+ versionCode: (new_version_beta || {})[VERSION_CODE],
304
+ 'alpha.versionName': (new_version_alpha || {})[VERSION_NAME],
305
+ 'alpha.versionCode': (new_version_alpha || {})[VERSION_CODE]
306
+ }
307
+ content = File.read(version_properties_file)
308
+ content.gsub!(/^(.*) ?=.*$/) do |line|
309
+ key = Regexp.last_match(1).to_sym
310
+ value = replacements[key]
311
+ value.nil? ? line : "#{key}=#{value}"
348
312
  end
313
+ File.write(version_properties_file, content)
349
314
  else
350
315
  self.update_version(new_version_beta, ENV['HAS_ALPHA_VERSION'].nil? ? 'defaultConfig' : 'vanilla {')
351
316
  self.update_version(new_version_alpha, 'defaultConfig') unless new_version_alpha.nil?
@@ -434,7 +399,7 @@ module Fastlane
434
399
  #
435
400
  # @return [Bool] true if the string is representing an integer value, false if not
436
401
  #
437
- def self.is_int? string
402
+ def self.is_int?(string)
438
403
  true if Integer(string) rescue false
439
404
  end
440
405
 
@@ -36,7 +36,9 @@ module Fastlane
36
36
  while continue
37
37
  child_filenames = dir.children.map! { |x| File.basename(x) }
38
38
 
39
- if child_filenames.include? 'fastlane-plugin-wpmreleasetoolkit.gemspec'
39
+ # The first case is for development – where the `.gemspec` is present in the project root
40
+ # The second case is for production – where there's no `.gemspec`, but the root dir of the plugin is named `fastlane-plugin-wpmreleasetoolkit-{version}`.
41
+ if child_filenames.include?('fastlane-plugin-wpmreleasetoolkit.gemspec') || File.basename(dir).start_with?('fastlane-plugin-wpmreleasetoolkit-')
40
42
  continue = false
41
43
  else
42
44
  dir = dir.parent
@@ -1,23 +1,37 @@
1
1
  require 'fastlane_core/ui/ui'
2
2
  require 'octokit'
3
3
  require 'open-uri'
4
+ require 'securerandom'
4
5
 
5
6
  module Fastlane
6
7
  UI = FastlaneCore::UI unless Fastlane.const_defined?('UI')
7
8
 
8
9
  module Helper
9
10
  class GithubHelper
11
+ def self.github_token!
12
+ token = [
13
+ 'GHHELPER_ACCESS', # For historical reasons / backward compatibility
14
+ 'GITHUB_TOKEN', # Used by the `gh` CLI tool
15
+ ].map { |key| ENV[key] }
16
+ .compact
17
+ .first
18
+
19
+ token || UI.user_error!('Please provide a GitHub authentication token via the `GITHUB_TOKEN` environment variable')
20
+ end
21
+
10
22
  def self.github_client
11
- client = Octokit::Client.new(access_token: ENV['GHHELPER_ACCESS'])
23
+ @@client ||= begin
24
+ client = Octokit::Client.new(access_token: github_token!)
12
25
 
13
- # Fetch the current user
14
- user = client.user
15
- UI.message("Logged in as: #{user.name}")
26
+ # Fetch the current user
27
+ user = client.user
28
+ UI.message("Logged in as: #{user.name}")
16
29
 
17
- # Auto-paginate to ensure we're not missing data
18
- client.auto_paginate = true
30
+ # Auto-paginate to ensure we're not missing data
31
+ client.auto_paginate = true
19
32
 
20
- client
33
+ client
34
+ end
21
35
  end
22
36
 
23
37
  def self.get_milestone(repository, release)
@@ -117,8 +131,11 @@ module Fastlane
117
131
  file_name = File.basename(file_path)
118
132
  download_path = File.join(download_folder, file_name)
119
133
 
134
+ download_url = github_client.contents(repository,
135
+ path: file_path,
136
+ ref: tag).download_url
120
137
  begin
121
- uri = URI.parse("https://raw.githubusercontent.com/#{repository}/#{tag}/#{file_path}")
138
+ uri = URI.parse(download_url)
122
139
  uri.open do |remote_file|
123
140
  File.write(download_path, remote_file.read)
124
141
  end
@@ -128,6 +145,29 @@ module Fastlane
128
145
 
129
146
  download_path
130
147
  end
148
+
149
+ # Creates (or updates an existing) GitHub PR Comment
150
+ def self.comment_on_pr(project_slug:, pr_number:, body:, reuse_identifier: SecureRandom.uuid)
151
+ client = github_client
152
+ comments = client.issue_comments(project_slug, pr_number)
153
+
154
+ reuse_marker = "<!-- REUSE_ID: #{reuse_identifier} -->"
155
+
156
+ existing_comment = comments.find do |comment|
157
+ # Only match comments posted by the owner of the GitHub Token, and with the given reuse ID
158
+ comment.user.id == client.user.id and comment.body.include?(reuse_marker)
159
+ end
160
+
161
+ comment_body = reuse_marker + body
162
+
163
+ if existing_comment.nil?
164
+ client.add_comment(project_slug, pr_number, comment_body)
165
+ else
166
+ client.update_comment(project_slug, existing_comment.id, comment_body)
167
+ end
168
+
169
+ reuse_identifier
170
+ end
131
171
  end
132
172
  end
133
173
  end