fastlane-plugin-wpmreleasetoolkit 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +339 -0
- data/README.md +38 -0
- data/bin/drawText +19 -0
- data/ext/drawText/extconf.rb +36 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit.rb +16 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/README.md +20 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/an_localize_libs_action.rb +53 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/an_update_metadata_source_action.rb +171 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/an_validate_lib_strings_action.rb +63 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_betabuild_prechecks.rb +103 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_build_prechecks.rb +83 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_build_preflight.rb +54 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_bump_version_beta.rb +69 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_bump_version_final_release.rb +58 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_bump_version_hotfix.rb +77 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_bump_version_release.rb +89 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_codefreeze_prechecks.rb +79 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_completecodefreeze_prechecks.rb +68 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_create_xml_release_notes.rb +63 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_current_branch_is_hotfix.rb +44 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_download_file_by_version.rb +79 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_download_translations_action.rb +115 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_finalize_prechecks.rb +71 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_get_alpha_version.rb +44 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_get_app_version.rb +44 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_get_release_version.rb +44 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_hotifx_prechecks.rb +78 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_merge_translators_strings.rb +106 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_tag_build.rb +51 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_update_metadata.rb +52 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/android/android_update_release_notes.rb +56 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/circleci_trigger_job_action.rb +63 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/close_milestone_action.rb +56 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/create_new_milestone_action.rb +59 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/create_release_action.rb +91 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/extract_release_notes_for_version_action.rb +89 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/get_prs_list_action.rb +64 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/gp_downloadmetadata_action.rb +90 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/gp_update_metadata_source.rb +170 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/promo_screenshots_action.rb +247 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/removebranchprotection_action.rb +57 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/setbranchprotection_action.rb +56 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/common/setfrozentag_action.rb +81 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/configure/configure_add_files_to_copy_action.rb +96 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/configure/configure_apply_action.rb +139 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/configure/configure_download_action.rb +57 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/configure/configure_setup_action.rb +86 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/configure/configure_update_action.rb +139 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/configure/configure_validate_action.rb +134 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/add_development_certificates_to_provisioning_profiles.rb +77 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/add_devices_to_provisioning_profiles.rb +79 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_betabuild_prechecks.rb +92 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_build_prechecks.rb +74 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_build_preflight.rb +78 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_bump_version_beta.rb +68 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_bump_version_hotfix.rb +87 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_bump_version_release.rb +114 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_check_beta_deps.rb +62 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_clear_intermediate_tags.rb +60 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_codefreeze_prechecks.rb +70 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_completecodefreeze_prechecks.rb +63 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_current_branch_is_hotfix.rb +40 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_final_tag.rb +52 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_finalize_prechecks.rb +64 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_get_app_version.rb +47 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_get_build_version.rb +60 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_get_store_app_sizes.rb +121 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_hotifx_prechecks.rb +78 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_lint_localizations.rb +167 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_localize_project.rb +44 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_merge_translators_strings.rb +93 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_tag_build.rb +44 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_update_metadata.rb +40 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_update_metadata_source.rb +81 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_update_release_notes.rb +56 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/actions/ios/ios_validate_ci_build.rb +46 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/an_metadata_update_helper.rb +152 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/android/android_git_helper.rb +44 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/android/android_localize_helper.rb +359 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/android/android_version_helper.rb +475 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/ci_helper.rb +91 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/configure_helper.rb +282 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/encryption_helper.rb +51 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/filesystem_helper.rb +93 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/git_helper.rb +224 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb +135 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_adc_app_sizes_helper.rb +74 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_git_helper.rb +80 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_l10n_helper.rb +208 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/ios/ios_version_helper.rb +348 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/metadata_download_helper.rb +107 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/metadata_update_helper.rb +182 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/promo_screenshots_helper.rb +399 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/helper/release_notes_helper.rb +21 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/models/configuration.rb +40 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/models/file_reference.rb +86 -0
- data/lib/fastlane/plugin/wpmreleasetoolkit/version.rb +5 -0
- metadata +449 -0
@@ -0,0 +1,224 @@
|
|
1
|
+
require 'git'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Helper
|
5
|
+
# Helper methods to execute git-related operations
|
6
|
+
#
|
7
|
+
module GitHelper
|
8
|
+
# Checks if the given path, or current directory if no path is given, is
|
9
|
+
# inside a Git repository
|
10
|
+
#
|
11
|
+
# @param [String] path An optional path where to check if a Git repo
|
12
|
+
# exists.
|
13
|
+
#
|
14
|
+
# @return [Bool] True if the current directory is the root of a git repo
|
15
|
+
# (i.e. a local working copy) or a subdirectory of one.
|
16
|
+
#
|
17
|
+
def self.is_git_repo?(path: Dir.pwd)
|
18
|
+
# If the path doesn't exist, find its first ancestor.
|
19
|
+
path = first_existing_ancestor_of(path: path)
|
20
|
+
# Get the path's directory, so we can look in it for the Git folder
|
21
|
+
dir = path.directory? ? path : path.dirname
|
22
|
+
|
23
|
+
# Recursively look for the Git folder until it's found or we read the
|
24
|
+
# the file system root
|
25
|
+
dir = dir.parent until Dir.entries(dir).include?('.git') || dir.root?
|
26
|
+
|
27
|
+
# If we reached the root, we haven't found a repo. (Technically, there
|
28
|
+
# could be a repo in the root of the system, but that's a usecase that
|
29
|
+
# we don't need to support at this time)
|
30
|
+
return dir.root? == false
|
31
|
+
end
|
32
|
+
|
33
|
+
# Travels back the hierarchy of the given path until it finds an existing
|
34
|
+
# ancestor, or it reaches the root of the file system.
|
35
|
+
#
|
36
|
+
# @param [String] path The path to inspect
|
37
|
+
#
|
38
|
+
# @return [Pathname] The first existing ancestor, or `path` itself if it
|
39
|
+
# exists
|
40
|
+
#
|
41
|
+
def self.first_existing_ancestor_of(path:)
|
42
|
+
p = Pathname(path).expand_path
|
43
|
+
p = p.parent until p.exist? || p.root?
|
44
|
+
return p
|
45
|
+
end
|
46
|
+
|
47
|
+
# Check if the current directory has git-lfs enabled
|
48
|
+
#
|
49
|
+
# @return [Bool] True if the current directory is a git working copy and has git-lfs enabled.
|
50
|
+
#
|
51
|
+
def self.has_git_lfs?
|
52
|
+
return false unless is_git_repo?
|
53
|
+
|
54
|
+
`git config --get-regex lfs`.length > 0
|
55
|
+
end
|
56
|
+
|
57
|
+
# Switch to the given branch and pull its latest commits.
|
58
|
+
#
|
59
|
+
# @param [String,Hash] branch Name of the branch to pull.
|
60
|
+
# If you provide a Hash with a single key=>value pair, it will build the branch name as `"#{key}/#{value}"`,
|
61
|
+
# i.e. `checkout_and_pull(release: version)` is equivalent to `checkout_and_pull("release/#{version}")`.
|
62
|
+
#
|
63
|
+
# @return [Bool] True if it succeeded switching and pulling, false if there was an error during the switch or pull.
|
64
|
+
#
|
65
|
+
def self.checkout_and_pull(branch)
|
66
|
+
branch = branch.first.join('/') if branch.is_a?(Hash)
|
67
|
+
Action.sh('git', 'checkout', branch)
|
68
|
+
Action.sh('git', 'pull')
|
69
|
+
return true
|
70
|
+
rescue
|
71
|
+
return false
|
72
|
+
end
|
73
|
+
|
74
|
+
# Update every submodule in the current git repository
|
75
|
+
#
|
76
|
+
def self.update_submodules
|
77
|
+
Action.sh('git', 'submodule', 'update', '--init', '--recursive')
|
78
|
+
end
|
79
|
+
|
80
|
+
# Create a new branch named `branch_name`, cutting it from branch/commit/tag `from`, and push it
|
81
|
+
#
|
82
|
+
# If the branch with that name already exists, it will instead switch to it and pull new commits.
|
83
|
+
#
|
84
|
+
# @param [String] branch_name The full name of the new branch to create, e.g "release/1.2"
|
85
|
+
# @param [String?] from The branch or tag from which to cut the branch from.
|
86
|
+
# If `nil`, will cut the new branch from the current commit. Otherwise, will checkout that commit/branch/tag before cutting the branch.
|
87
|
+
# @param [Bool] push If true, will also push the branch to `origin`, tracking the upstream branch with the local one.
|
88
|
+
#
|
89
|
+
def self.create_branch(branch_name, from: nil, push: true)
|
90
|
+
if branch_exists?(branch_name)
|
91
|
+
UI.message("Branch #{branch_name} already exists. Skipping creation.")
|
92
|
+
Action.sh('git', 'checkout', branch_name)
|
93
|
+
Action.sh('git', 'pull', 'origin', branch_name)
|
94
|
+
else
|
95
|
+
Action.sh('git', 'checkout', from) unless from.nil?
|
96
|
+
Action.sh('git', 'checkout', '-b', branch_name)
|
97
|
+
Action.sh('git', 'push', '-u', 'origin', branch_name) if push
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
# `git add` the specified files (if any provided) then commit them using the provided message.
|
102
|
+
# Optionally, push the commit to the remote too.
|
103
|
+
#
|
104
|
+
# @param [String] message The commit message to use
|
105
|
+
# @param [String|Array<String>] files A file or array of files to git-add before creating the commit.
|
106
|
+
# use `nil` or `[]` if you already added the files in a separate step and don't wan't this method to add any new file before commit.
|
107
|
+
# Also accepts the special symbol `:all` to add all the files (`git commit -a -m …`).
|
108
|
+
# @param [Bool] push If true, will `git push` to `origin` after the commit has been created. Defaults to `false`.
|
109
|
+
#
|
110
|
+
# @return [Bool] True if commit and push were successful, false if there was an issue during commit & push (most likely being "nothing to commit").
|
111
|
+
#
|
112
|
+
def self.commit(message:, files: nil, push: false)
|
113
|
+
files = [files] if files.is_a?(String)
|
114
|
+
args = []
|
115
|
+
if files == :all
|
116
|
+
args = ['-a']
|
117
|
+
elsif !files.nil? && !files.empty?
|
118
|
+
Action.sh('git', 'add', *files)
|
119
|
+
end
|
120
|
+
begin
|
121
|
+
Action.sh('git', 'commit', *args, '-m', message)
|
122
|
+
Action.sh('git', 'push', 'origin', 'HEAD') if push
|
123
|
+
return true
|
124
|
+
rescue
|
125
|
+
return false
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# Get the SHA of a given git ref. Typically useful to get the SHA of the current HEAD commit.
|
130
|
+
#
|
131
|
+
# @param [String] ref The git ref (commit, branch name, 'HEAD', …) to resolve as a SHA
|
132
|
+
# @return [String] The commit SHA of the ref
|
133
|
+
#
|
134
|
+
def self.get_commit_sha(ref: 'HEAD')
|
135
|
+
Git.open(Dir.pwd).revparse(ref)
|
136
|
+
end
|
137
|
+
|
138
|
+
# Creates a tag for the given version, and optionally push it to the remote.
|
139
|
+
#
|
140
|
+
# @param [String] version The name of the tag to push, e.g. "1.2"
|
141
|
+
# @param [Bool] push If true (the default), the tag will also be pushed to `origin`
|
142
|
+
#
|
143
|
+
def self.create_tag(version, push: true)
|
144
|
+
Action.sh('git', 'tag', version)
|
145
|
+
Action.sh('git', 'push', 'origin', version) if push
|
146
|
+
end
|
147
|
+
|
148
|
+
# Returns the list of tags that are pointing to the current commit (HEAD)
|
149
|
+
#
|
150
|
+
# @return [Array<String>] List of tags associated with the HEAD commit
|
151
|
+
#
|
152
|
+
def self.list_tags_on_current_commit
|
153
|
+
Action.sh('git', 'tag', '--points-at', 'HEAD').split("\n")
|
154
|
+
end
|
155
|
+
|
156
|
+
# List all the tags in the local working copy, optionally filtering the list using a pattern
|
157
|
+
#
|
158
|
+
# @param [String] matching The pattern of the tag(s) to match and filter on; use "*" for wildcards.
|
159
|
+
# For example, `"1.2.*"` will match every tag starting with `"1.2."`. Defaults to '*' which lists all tags.
|
160
|
+
#
|
161
|
+
# @return [Array<String>] The list of local tags matching the pattern
|
162
|
+
#
|
163
|
+
def self.list_local_tags(matching: '*')
|
164
|
+
Action.sh('git', 'tag', '--list', matching).split("\n")
|
165
|
+
end
|
166
|
+
|
167
|
+
# Delete the mentioned local tags in the local working copy, and optionally delete them on the remote too.
|
168
|
+
#
|
169
|
+
# @param [Array<String>] tags_to_delete The list of tags to delete
|
170
|
+
# @param [Bool] delete_on_remote If true, will also delete the tag from the remote. Otherwise, it will only be deleted locally.
|
171
|
+
#
|
172
|
+
def self.delete_tags(tags_to_delete, delete_on_remote: false)
|
173
|
+
g = Git.open(Dir.pwd)
|
174
|
+
local_tag_names = g.tags.map(&:name)
|
175
|
+
|
176
|
+
Array(tags_to_delete).each do |tag|
|
177
|
+
g.delete_tag(tag) if local_tag_names.include?(tag)
|
178
|
+
g.push('origin', ":refs/tags/#{tag}") if delete_on_remote
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Fetch all the tags from the remote.
|
183
|
+
#
|
184
|
+
def self.fetch_all_tags
|
185
|
+
Action.sh('git', 'fetch', '--tags')
|
186
|
+
end
|
187
|
+
|
188
|
+
# Checks if a branch exists locally.
|
189
|
+
#
|
190
|
+
# @param [String] branch_name The name of the branch to check for
|
191
|
+
#
|
192
|
+
# @return [Bool] True if the branch exists in the local working copy, false otherwise.
|
193
|
+
#
|
194
|
+
def self.branch_exists?(branch_name)
|
195
|
+
!Action.sh('git', 'branch', '--list', branch_name).empty?
|
196
|
+
end
|
197
|
+
|
198
|
+
# Ensure that we are on the expected branch, and abort if not.
|
199
|
+
#
|
200
|
+
# @param [String] branch_name The name of the branch we expect to be on
|
201
|
+
#
|
202
|
+
# @raise [UserError] Raises a user_error! and interrupts the lane if we are not on the expected branch.
|
203
|
+
#
|
204
|
+
def self.ensure_on_branch!(branch_name)
|
205
|
+
current_branch_name = Action.sh('git', 'symbolic-ref', '-q', 'HEAD')
|
206
|
+
UI.user_error!("This command works only on #{branch_name} branch") unless current_branch_name.include?(branch_name)
|
207
|
+
end
|
208
|
+
|
209
|
+
# Checks whether a given path is ignored by Git, relying on Git's
|
210
|
+
# `check-ignore` under the hood.
|
211
|
+
#
|
212
|
+
# @param [String] path The path to check against `.gitignore`
|
213
|
+
#
|
214
|
+
# @return [Bool] True if the given path is ignored or outside a Git repository, false otherwise.
|
215
|
+
def self.is_ignored?(path:)
|
216
|
+
return true unless is_git_repo?(path: path)
|
217
|
+
|
218
|
+
Actions.sh('git', 'check-ignore', path) do |status, _, _|
|
219
|
+
status.success?
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'fastlane_core/ui/ui'
|
2
|
+
require 'octokit'
|
3
|
+
require 'open-uri'
|
4
|
+
|
5
|
+
module Fastlane
|
6
|
+
UI = FastlaneCore::UI unless Fastlane.const_defined?('UI')
|
7
|
+
|
8
|
+
module Helper
|
9
|
+
class GithubHelper
|
10
|
+
def self.github_client
|
11
|
+
client = Octokit::Client.new(access_token: ENV['GHHELPER_ACCESS'])
|
12
|
+
|
13
|
+
# Fetch the current user
|
14
|
+
user = client.user
|
15
|
+
UI.message("Logged in as: #{user.name}")
|
16
|
+
|
17
|
+
# Auto-paginate to ensure we're not missing data
|
18
|
+
client.auto_paginate = true
|
19
|
+
|
20
|
+
client
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.get_milestone(repository, release)
|
24
|
+
miles = github_client().list_milestones(repository)
|
25
|
+
mile = nil
|
26
|
+
|
27
|
+
miles&.each do |mm|
|
28
|
+
mile = mm if mm[:title].start_with?(release)
|
29
|
+
end
|
30
|
+
|
31
|
+
return mile
|
32
|
+
end
|
33
|
+
|
34
|
+
# Fetch all the PRs for a given milestone
|
35
|
+
#
|
36
|
+
# @param [String] repository The repository name, including the organization (e.g. `wordpress-mobile/wordpress-ios`)
|
37
|
+
# @param [String] milestone The name of the milestone we want to fetch the list of PRs for (e.g.: `16.9`)
|
38
|
+
# @return [<Sawyer::Resource>] A list of the PRs for the given milestone, sorted by number
|
39
|
+
#
|
40
|
+
def self.get_prs_for_milestone(repository, milestone)
|
41
|
+
github_client.search_issues(%(type:pr milestone:"#{milestone}" repo:#{repository}))[:items].sort_by(&:number)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.get_last_milestone(repository)
|
45
|
+
options = {}
|
46
|
+
options[:state] = 'open'
|
47
|
+
|
48
|
+
milestones = github_client().list_milestones(repository, options)
|
49
|
+
return nil if milestones.nil?
|
50
|
+
|
51
|
+
last_stone = nil
|
52
|
+
milestones.each do |mile|
|
53
|
+
if last_stone.nil?
|
54
|
+
last_stone = mile unless mile[:title].split(' ')[0].split('.').length < 2
|
55
|
+
else
|
56
|
+
begin
|
57
|
+
if mile[:title].split(' ')[0].split('.')[0] > last_stone[:title].split(' ')[0].split('.')[0]
|
58
|
+
last_stone = mile
|
59
|
+
elsif mile[:title].split(' ')[0].split('.')[1] > last_stone[:title].split(' ')[0].split('.')[1]
|
60
|
+
last_stone = mile
|
61
|
+
end
|
62
|
+
rescue StandardError
|
63
|
+
puts 'Found invalid milestone'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
last_stone
|
69
|
+
end
|
70
|
+
|
71
|
+
def self.create_milestone(repository, newmilestone_number, newmilestone_duedate, need_submission)
|
72
|
+
submission_date = need_submission ? newmilestone_duedate.to_datetime.next_day(11) : newmilestone_duedate.to_datetime.next_day(14)
|
73
|
+
release_date = newmilestone_duedate.to_datetime.next_day(14)
|
74
|
+
comment = "Code freeze: #{newmilestone_duedate.to_datetime.strftime('%B %d, %Y')} App Store submission: #{submission_date.strftime('%B %d, %Y')} Release: #{release_date.strftime('%B %d, %Y')}"
|
75
|
+
|
76
|
+
options = {}
|
77
|
+
options[:due_on] = newmilestone_duedate
|
78
|
+
options[:description] = comment
|
79
|
+
github_client().create_milestone(repository, newmilestone_number, options)
|
80
|
+
end
|
81
|
+
|
82
|
+
# Creates a Release on GitHub as a Draft
|
83
|
+
#
|
84
|
+
# @param [String] repository The repository to create the GitHub release on. Typically a repo slug (<org>/<repo>).
|
85
|
+
# @param [String] version The version for which to create this release. Will be used both as the name of the tag and the name of the release.
|
86
|
+
# @param [String?] target The commit SHA or branch name that this release will point to when it's published and creates the tag.
|
87
|
+
# If nil (the default), will use the repo's current HEAD commit at the time this method is called.
|
88
|
+
# Unused if the tag already exists.
|
89
|
+
# @param [String] description The text to use as the release's body / description (typically the release notes)
|
90
|
+
# @param [Array<String>] assets List of file paths to attach as assets to the release
|
91
|
+
# @param [TrueClass|FalseClass] prerelease Indicates if this should be created as a pre-release (i.e. for alpha/beta)
|
92
|
+
#
|
93
|
+
def self.create_release(repository:, version:, target: nil, description:, assets:, prerelease:)
|
94
|
+
release = github_client().create_release(
|
95
|
+
repository,
|
96
|
+
version, # tag name
|
97
|
+
name: version, # release name
|
98
|
+
target_commitish: target || Git.open(Dir.pwd).log.first.sha,
|
99
|
+
draft: true,
|
100
|
+
prerelease: prerelease,
|
101
|
+
body: description
|
102
|
+
)
|
103
|
+
assets.each do |file_path|
|
104
|
+
github_client().upload_asset(release[:url], file_path, content_type: 'application/octet-stream')
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Downloads a file from the given GitHub tag
|
109
|
+
#
|
110
|
+
# @param [String] repository The repository name (including the organization)
|
111
|
+
# @param [String] tag The name of the tag we're downloading from
|
112
|
+
# @param [String] file_path The path, inside the project folder, of the file to download
|
113
|
+
# @param [String] download_folder The folder which the file should be downloaded into
|
114
|
+
# @return [String] The path of the downloaded file, or nil if something went wrong
|
115
|
+
#
|
116
|
+
def self.download_file_from_tag(repository:, tag:, file_path:, download_folder:)
|
117
|
+
repository = repository.delete_prefix('/').chomp('/')
|
118
|
+
file_path = file_path.delete_prefix('/').chomp('/')
|
119
|
+
file_name = File.basename(file_path)
|
120
|
+
download_path = File.join(download_folder, file_name)
|
121
|
+
|
122
|
+
begin
|
123
|
+
uri = URI.parse("https://raw.githubusercontent.com/#{repository}/#{tag}/#{file_path}")
|
124
|
+
uri.open do |remote_file|
|
125
|
+
File.write(download_path, remote_file.read)
|
126
|
+
end
|
127
|
+
rescue OpenURI::HTTPError
|
128
|
+
return nil
|
129
|
+
end
|
130
|
+
|
131
|
+
download_path
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'spaceship'
|
2
|
+
|
3
|
+
module Fastlane
|
4
|
+
module Helper
|
5
|
+
module Ios
|
6
|
+
module ADCAppSizesHelper
|
7
|
+
DEFAULT_DEVICES = ['Universal', 'iPhone 8', 'iPhone X']
|
8
|
+
|
9
|
+
# Fetch the App Sizes stats from ADC
|
10
|
+
#
|
11
|
+
# @return [Array<Hash>] app build details, one entry per app version found
|
12
|
+
# Each entry is a hash with keys `cfBundleVersion` and `sizesInBytes`.
|
13
|
+
# Value for key `sizeInBytes` is itself a Hash with one entry per device name (including special name "Universal")
|
14
|
+
# whose value is a Hash with keys `compressed` and `uncompressed`
|
15
|
+
#
|
16
|
+
def self.get_adc_sizes(adc_user:, adc_team: 'Automattic, Inc.', bundle_id:, only_version: nil, limit: 10)
|
17
|
+
UI.message 'Connecting to ADC...'
|
18
|
+
Spaceship::ConnectAPI.login(adc_user, team_name: adc_team)
|
19
|
+
app = Spaceship::ConnectAPI::App.find(bundle_id)
|
20
|
+
|
21
|
+
UI.message 'Fetching the list of versions...'
|
22
|
+
versions = app.app_store_versions.select { |v| v.version_string == only_version && !v.build.nil? }
|
23
|
+
versions = app.get_app_store_versions.reject { |v| v.build.nil? } if versions.empty?
|
24
|
+
UI.message "Found #{versions.count} versions." + (limit == 0 ? '' : " Limiting to last #{limit}")
|
25
|
+
versions = versions.first(limit) unless limit == 0
|
26
|
+
|
27
|
+
UI.message 'Fetching App Sizes...'
|
28
|
+
|
29
|
+
builds_details = versions.each_with_index.map do |v, idx|
|
30
|
+
print "Fetching info for: #{v.version_string.rjust(8)} (#{v.build.version.rjust(11)}) [#{idx.to_s.rjust(3)}/#{versions.count}]\r"
|
31
|
+
Spaceship::Tunes.client.build_details(app_id: app.id, train: v.version_string, build_number: v.build.version, platform: 'ios') rescue nil
|
32
|
+
end.compact.reverse
|
33
|
+
print(' ' * 55 + "\n")
|
34
|
+
|
35
|
+
builds_details
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.sz(bytes)
|
39
|
+
(bytes.to_f / (1024 * 1024)).round(1)
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.sz_mb(bytes)
|
43
|
+
sz(bytes).to_s.rjust(5) + ' MB'
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.format_csv(app_sizes, devices: nil)
|
47
|
+
devices = DEFAULT_DEVICES if devices.nil? || devices.empty?
|
48
|
+
csv = "Version\t" + devices.join("\t") + "\n"
|
49
|
+
app_sizes.each do |details|
|
50
|
+
build_number = details['cfBundleVersion']
|
51
|
+
sizes = details['sizesInBytes'].select { |name, _| devices.include?(name) }
|
52
|
+
csv += "#{build_number}\t" + devices.map { |d| sz(sizes[d]['compressed']) }.join("\t") + "\n"
|
53
|
+
end
|
54
|
+
csv
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.format_markdown(app_sizes, devices: nil)
|
58
|
+
devices = DEFAULT_DEVICES if devices.nil? || devices.empty?
|
59
|
+
app_sizes.map do |details|
|
60
|
+
build_number = details['cfBundleVersion']
|
61
|
+
sizes = details['sizesInBytes'].select { |name, _| devices.include?(name) }
|
62
|
+
col_size = devices.map(&:length).max
|
63
|
+
table = "| #{build_number.ljust(col_size)} | Download | Install |\n"
|
64
|
+
table += "|:#{'-' * col_size}-|---------:|---------:|\n"
|
65
|
+
sizes.each do |(device_name, size_info)|
|
66
|
+
table += "| #{device_name.ljust(col_size)} | #{sz_mb(size_info['compressed'])} | #{sz_mb(size_info['uncompressed'])} |\n"
|
67
|
+
end
|
68
|
+
table
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Fastlane
|
2
|
+
module Helper
|
3
|
+
module Ios
|
4
|
+
# Helper methods to execute git-related operations that are specific to iOS projects
|
5
|
+
#
|
6
|
+
module GitHelper
|
7
|
+
# Commit and push the files that are modified when we bump version numbers on an iOS project
|
8
|
+
#
|
9
|
+
# This typically commits and pushes:
|
10
|
+
# - The files in `./config/*` – especially `Version.*.xcconfig` files
|
11
|
+
# - The `fastlane/Deliverfile` file (which contains the `app_version` line)
|
12
|
+
# - The `<ProjectRoot>/<ProjectName>/Resources/AppStoreStrings.pot` file, containing a key for that version's release notes
|
13
|
+
#
|
14
|
+
# @env PROJECT_ROOT_FOLDER The path to the git root of the project
|
15
|
+
# @env PROJECT_NAME The name of the directory containing the project code (especially containing the Resources/ subfolder)
|
16
|
+
#
|
17
|
+
# @param [Bool] include_deliverfile If true (the default), includes the `fastlane/Deliverfile` in files being commited
|
18
|
+
# @param [Bool] include_metadata If true (the default), includes the `fastlane/download_metadata.swift` file and the `.pot` file (which typically contains an entry or release notes for the new version)
|
19
|
+
#
|
20
|
+
def self.commit_version_bump(include_deliverfile: true, include_metadata: true)
|
21
|
+
files_list = [File.join(ENV['PROJECT_ROOT_FOLDER'], 'config', '.')]
|
22
|
+
files_list.append File.join('fastlane', 'Deliverfile') if include_deliverfile
|
23
|
+
if include_metadata
|
24
|
+
files_list.append File.join('fastlane', 'download_metadata.swift')
|
25
|
+
files_list.append File.join(ENV['PROJECT_ROOT_FOLDER'], ENV['PROJECT_NAME'], 'Resources', ENV['APP_STORE_STRINGS_FILE_NAME'])
|
26
|
+
end
|
27
|
+
|
28
|
+
Fastlane::Helper::GitHelper.commit(message: 'Bump version number', files: files_list, push: true)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Calls the `Scripts/localize.py` script in the project root folder and push the `*.strings` files
|
32
|
+
#
|
33
|
+
# That script updates the `.strings` files with translations from GlotPress.
|
34
|
+
#
|
35
|
+
# @env PROJECT_ROOT_FOLDER The path to the git root of the project
|
36
|
+
# @env PROJECT_NAME The name of the directory containing the project code (especially containing the `build.gradle` file)
|
37
|
+
#
|
38
|
+
# @todo Migrate the scripts, currently in each host repo and called by this method, to be helpers and actions
|
39
|
+
# in the release-toolkit instead, and move this code away from `ios_git_helper`.
|
40
|
+
#
|
41
|
+
def self.localize_project
|
42
|
+
Action.sh("cd #{get_from_env!(key: 'PROJECT_ROOT_FOLDER')} && ./Scripts/localize.py")
|
43
|
+
|
44
|
+
Fastlane::Helper::GitHelper.commit(message: 'Update strings for localization', files: strings_files, push: true) || UI.message('No new strings, skipping commit')
|
45
|
+
end
|
46
|
+
|
47
|
+
# Call the `Scripts/update-translations.rb` then the `fastlane/download_metadata` Scripts from the host project folder
|
48
|
+
#
|
49
|
+
# @env PROJECT_ROOT_FOLDER The path to the git root of the project
|
50
|
+
# @env PROJECT_NAME The name of the directory containing the project code (especially containing the `build.gradle` file)
|
51
|
+
#
|
52
|
+
# @todo Migrate the scripts, currently in each host repo and called by this method, to be helpers and actions
|
53
|
+
# in the release-toolkit instead, and move this code away from `ios_git_helper`.
|
54
|
+
#
|
55
|
+
def self.update_metadata
|
56
|
+
Action.sh("cd #{get_from_env!(key: 'PROJECT_ROOT_FOLDER')} && ./Scripts/update-translations.rb")
|
57
|
+
|
58
|
+
Fastlane::Helper::GitHelper.commit(message: 'Update translations', files: strings_files, push: false)
|
59
|
+
|
60
|
+
Action.sh('cd fastlane && ./download_metadata.swift')
|
61
|
+
|
62
|
+
Fastlane::Helper::GitHelper.commit(message: 'Update metadata translations', files: './fastlane/metadata/', push: true)
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.strings_files
|
66
|
+
project_root = get_from_env!(key: 'PROJECT_ROOT_FOLDER')
|
67
|
+
project_name = get_from_env!(key: 'PROJECT_NAME')
|
68
|
+
|
69
|
+
Dir.glob(File.join(project_root, project_name, '**', '*.strings'))
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.get_from_env!(key:)
|
73
|
+
ENV.fetch(key) do
|
74
|
+
UI.user_error! "Could not find value for \"#{key}\" in environment."
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|