fastlane-plugin-wpmreleasetoolkit 1.3.1 → 2.2.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 (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