Class: Fastlane::Helper::GithubHelper
- Inherits:
-
Object
- Object
- Fastlane::Helper::GithubHelper
- Defined in:
- lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb
Instance Attribute Summary collapse
-
#client ⇒ Object
readonly
Returns the value of attribute client.
Class Method Summary collapse
-
.branch_protection_api_response_to_normalized_hash(response) ⇒ Hash
Convert a response from the ‘/branch-protection` API endpoint into a Hash suitable to be returned and/or reused to pass to a subsequent `/branch-protection` API request.
-
.github_token_config_item ⇒ FastlaneCore::ConfigItem
Creates a GithubToken Fastlane ConfigItem.
Instance Method Summary collapse
-
#comment_on_pr(project_slug:, pr_number:, body:, reuse_identifier: SecureRandom.uuid) ⇒ Object
Creates (or updates an existing) GitHub PR Comment.
-
#create_milestone(repository:, title:, due_date:, days_until_submission:, days_until_release:) ⇒ Object
Creates a new milestone.
-
#create_release(repository:, version:, description:, assets:, prerelease:, is_draft:, target: nil) ⇒ Object
Creates a Release on GitHub as a Draft.
-
#download_file_from_tag(repository:, tag:, file_path:, download_folder:) ⇒ String
Downloads a file from the given GitHub tag.
-
#generate_release_notes(repository:, tag_name:, previous_tag:, target_commitish: nil, config_file_path: nil) ⇒ String
Use the GitHub API to generate release notes based on the list of PRs between current tag and previous tag.
-
#get_branch_protection(repository:, branch:, **options) ⇒ Object
Get the list of branch protection settings for a given branch of a repository.
- #get_last_milestone(repository) ⇒ Object
- #get_milestone(repository, release) ⇒ Object
-
#get_prs_for_milestone(repository, milestone) ⇒ <Sawyer::Resource>
Fetch all the PRs for a given milestone.
-
#get_release_url(repository:, tag_name:) ⇒ String
Returns the URL of the GitHub release pointing at a given tag.
-
#initialize(github_token:) ⇒ GithubHelper
constructor
Helper for GitHub Actions.
-
#remove_branch_protection(repository:, branch:) ⇒ Object
Remove the protection of a single branch from a repository.
-
#set_branch_protection(repository:, branch:, **options) ⇒ Object
Protects a single branch from a repository.
-
#update_milestone(repository:, number:, **options) ⇒ Milestone
Update a milestone for a repository.
Constructor Details
#initialize(github_token:) ⇒ GithubHelper
Helper for GitHub Actions
17 18 19 20 21 22 23 24 25 26 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 17 def initialize(github_token:) @client = Octokit::Client.new(access_token: github_token) # Fetch the current user user = @client.user UI.("Logged in as: #{user.name}") # Auto-paginate to ensure we're not missing data @client.auto_paginate = true end |
Instance Attribute Details
#client ⇒ Object (readonly)
Returns the value of attribute client.
11 12 13 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 11 def client @client end |
Class Method Details
.branch_protection_api_response_to_normalized_hash(response) ⇒ Hash
Convert a response from the ‘/branch-protection` API endpoint into a Hash suitable to be returned and/or reused to pass to a subsequent `/branch-protection` API request
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 282 def self.branch_protection_api_response_to_normalized_hash(response) return {} if response.nil? normalize_values = lambda do |hash| hash.each do |k, v| # Boolean values appear as { "enabled" => true/false } in the Response, while they must appear as true/false in Request hash[k] = v[:enabled] if v.is_a?(Hash) && v.key?(:enabled) # References to :users, :teams and :apps are expanded as Objects in the Response, while they must just be the login or slug in Request hash[k] = v.map { |item| item[:login] } if k == :users && v.is_a?(Array) hash[k] = v.map { |item| item[:slug] } if %i[teams apps].include?(k) && v.is_a?(Array) # Response contains lots of `*url` keys that are useless in practice and makes the returned hash harder to parse visually hash.delete(k) if k.to_s == 'url' || k.to_s.end_with?('_url') # Recurse into Hashes and Array of Hashes normalize_values.call(v) if v.is_a?(Hash) v.each { |item| normalize_values.call(item) if item.is_a?(Hash) } if v.is_a?(Array) end end hash = response.to_hash normalize_values.call(hash) # Response contains both (legacy) `:contexts` key and new `:checks` key, but only one of the two should be passed in Request hash[:required_status_checks].delete(:contexts) unless hash.dig(:required_status_checks, :checks).nil? hash end |
.github_token_config_item ⇒ FastlaneCore::ConfigItem
Creates a GithubToken Fastlane ConfigItem
314 315 316 317 318 319 320 321 322 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 314 def self.github_token_config_item FastlaneCore::ConfigItem.new( key: :github_token, env_name: 'GITHUB_TOKEN', description: 'The GitHub OAuth access token', optional: false, type: String ) end |
Instance Method Details
#comment_on_pr(project_slug:, pr_number:, body:, reuse_identifier: SecureRandom.uuid) ⇒ Object
Creates (or updates an existing) GitHub PR Comment
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 206 def comment_on_pr(project_slug:, pr_number:, body:, reuse_identifier: SecureRandom.uuid) comments = client.issue_comments(project_slug, pr_number) reuse_marker = "<!-- REUSE_ID: #{reuse_identifier} -->" existing_comment = comments.find do |comment| # Only match comments posted by the owner of the GitHub Token, and with the given reuse ID comment.user.id == client.user.id and comment.body.include?(reuse_marker) end comment_body = reuse_marker + body if existing_comment.nil? client.add_comment(project_slug, pr_number, comment_body) else client.update_comment(project_slug, existing_comment.id, comment_body) end reuse_identifier end |
#create_milestone(repository:, title:, due_date:, days_until_submission:, days_until_release:) ⇒ Object
Creates a new milestone
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 82 def create_milestone(repository:, title:, due_date:, days_until_submission:, days_until_release:) UI.user_error!('days_until_release must be greater than zero.') unless days_until_release.positive? UI.user_error!('days_until_submission must be greater than zero.') unless days_until_submission.positive? UI.user_error!('days_until_release must be greater or equal to days_until_submission.') unless days_until_release >= days_until_submission submission_date = due_date.to_datetime.next_day(days_until_submission) release_date = due_date.to_datetime.next_day(days_until_release) comment = <<~MILESTONE_DESCRIPTION Code freeze: #{due_date.to_datetime.strftime('%B %d, %Y')} App Store submission: #{submission_date.strftime('%B %d, %Y')} Release: #{release_date.strftime('%B %d, %Y')} MILESTONE_DESCRIPTION = {} # == Workaround for GitHub API bug == # # It seems that whatever date we send to the API, GitHub will 'floor' it to the date that seems to be at # 00:00 PST/PDT and then discard the time component of the date we sent. # This means that, when we cross the November DST change date, where the due date of the previous milestone # was e.g. `2022-10-31T07:00:00Z` and `.next_day(14)` returns `2022-11-14T07:00:00Z` and we send that value # for the `due_on` field via the API, GitHub ends up creating a milestone with a due of `2022-11-13T08:00:00Z` # instead, introducing an off-by-one error on that due date. # # This is a bug in the GitHub API, not in our date computation logic. # To solve this, we trick it by forcing the time component of the ISO date we send to be `12:00:00Z`. [:due_on] = due_date.strftime('%Y-%m-%dT12:00:00Z') [:description] = comment client.create_milestone(repository, title, ) end |
#create_release(repository:, version:, description:, assets:, prerelease:, is_draft:, target: nil) ⇒ Object
Creates a Release on GitHub as a Draft
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 124 def create_release(repository:, version:, description:, assets:, prerelease:, is_draft:, target: nil) release = client.create_release( repository, version, # tag name name: version, # release name target_commitish: target || Git.open(Dir.pwd).log.first.sha, prerelease: prerelease, draft: is_draft, body: description ) assets.each do |file_path| client.upload_asset(release[:url], file_path, content_type: 'application/octet-stream') end release[:html_url] end |
#download_file_from_tag(repository:, tag:, file_path:, download_folder:) ⇒ String
Downloads a file from the given GitHub tag
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 185 def download_file_from_tag(repository:, tag:, file_path:, download_folder:) repository = repository.delete_prefix('/').chomp('/') file_path = file_path.delete_prefix('/').chomp('/') file_name = File.basename(file_path) download_path = File.join(download_folder, file_name) download_url = client.contents(repository, path: file_path, ref: tag).download_url begin uri = URI.parse(download_url) uri.open do |remote_file| File.write(download_path, remote_file.read) end rescue OpenURI::HTTPError return nil end download_path end |
#generate_release_notes(repository:, tag_name:, previous_tag:, target_commitish: nil, config_file_path: nil) ⇒ String
This API uses the ‘.github/release.yml` config file to classify the PRs by category in the generated list according to PR labels.
Use the GitHub API to generate release notes based on the list of PRs between current tag and previous tag.
152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 152 def generate_release_notes(repository:, tag_name:, previous_tag:, target_commitish: nil, config_file_path: nil) repo_path = Octokit::Repository.path(repository) api_url = "#{repo_path}/releases/generate-notes" res = client.post( api_url, tag_name: tag_name, target_commitish: target_commitish, # Only used if no git tag named `tag_name` exists yet previous_tag_name: previous_tag, config_file_path: config_file_path ) res.body end |
#get_branch_protection(repository:, branch:, **options) ⇒ Object
Get the list of branch protection settings for a given branch of a repository
259 260 261 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 259 def get_branch_protection(repository:, branch:, **) client.branch_protection(repository, branch) end |
#get_last_milestone(repository) ⇒ Object
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 49 def get_last_milestone(repository) = {} [:state] = 'open' milestones = client.list_milestones(repository, ) return nil if milestones.nil? last_stone = nil milestones.each do |mile| mile_vcomps = mile[:title].split[0].split('.') if last_stone.nil? last_stone = mile unless mile_vcomps.length < 2 else begin last_vcomps = last_stone[:title].split[0].split('.') last_stone = mile if Integer(mile_vcomps[0]) > Integer(last_vcomps[0]) || Integer(mile_vcomps[1]) > Integer(last_vcomps[1]) rescue StandardError puts 'Found invalid milestone' end end end last_stone end |
#get_milestone(repository, release) ⇒ Object
28 29 30 31 32 33 34 35 36 37 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 28 def get_milestone(repository, release) miles = client.list_milestones(repository) mile = nil miles&.each do |mm| mile = mm if mm[:title].start_with?(release) end return mile end |
#get_prs_for_milestone(repository, milestone) ⇒ <Sawyer::Resource>
Fetch all the PRs for a given milestone
45 46 47 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 45 def get_prs_for_milestone(repository, milestone) client.search_issues(%(type:pr milestone:"#{milestone}" repo:#{repository}))[:items].sort_by(&:number) end |
#get_release_url(repository:, tag_name:) ⇒ String
Returns the URL of the GitHub release pointing at a given tag
171 172 173 174 175 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 171 def get_release_url(repository:, tag_name:) client.release_for_tag(repository, tag_name).html_url rescue Octokit::NotFound nil end |
#remove_branch_protection(repository:, branch:) ⇒ Object
Remove the protection of a single branch from a repository
249 250 251 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 249 def remove_branch_protection(repository:, branch:) client.unprotect_branch(repository, branch) end |
#set_branch_protection(repository:, branch:, **options) ⇒ Object
Protects a single branch from a repository
270 271 272 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 270 def set_branch_protection(repository:, branch:, **) client.protect_branch(repository, branch, ) end |
#update_milestone(repository:, number:, **options) ⇒ Milestone
Update a milestone for a repository
239 240 241 |
# File 'lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb', line 239 def update_milestone(repository:, number:, **) client.update_milestone(repository, number, ) end |