From 362a6c05113c3afa470059e2e73367a3bc0894aa Mon Sep 17 00:00:00 2001 From: Ian Maia Date: Wed, 8 Jul 2026 16:35:02 +0200 Subject: [PATCH 1/3] Fix GitHub release asset lookup --- CHANGELOG.md | 1 + .../wpmreleasetoolkit/helper/github_helper.rb | 18 ++++++++++- spec/github_helper_spec.rb | 31 +++++++++++++++++++ 3 files changed, 49 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 261e42fc4..ea1aacbfc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ _None_ - `StringsFileValidationHelper.find_duplicated_keys` now parses unquoted keys/values and inter-token comments, matching the grammar `plutil` accepts, instead of raising `Invalid character`. This lets `ios_lint_localizations`' `check_duplicate_keys` work on `InfoPlist.strings`-style files. [#741] - `ios_lint_localizations`' `check_duplicate_keys` now warns and skips, rather than crashing, on a file that parses as a property list but isn't a tokenizable flat `.strings`. [#741] - `L10nHelper.merge_strings` now prefixes keys via a comment-aware tokenizer, so unquoted keys, unquoted values, and keys behind an inter-token comment are prefixed in the output consistently with the reported keys. [#741] +- `upload_github_release_assets`: make release lookup more resilient by falling back to GitHub's direct release-by-tag lookup when the releases list does not include the requested release. ### Internal Changes diff --git a/lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb b/lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb index 798ee0123..dc072b3b1 100644 --- a/lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb +++ b/lib/fastlane/plugin/wpmreleasetoolkit/helper/github_helper.rb @@ -200,7 +200,7 @@ def create_release(repository:, version:, description:, assets:, prerelease:, is # @raise [Fastlane::UI::Error] UI.user_error! if the release does not exist. # def get_release(repository:, version:) - release = client.releases(repository).find { |candidate| candidate.tag_name == version } + release = find_release(repository: repository, version: version) return release unless release.nil? UI.user_error!("Could not find GitHub Release for tag #{version} in #{repository}") @@ -244,6 +244,22 @@ def upload_release_assets(repository:, version:, assets:, replace_existing: true release.html_url end + def find_release(repository:, version:) + release = client.releases(repository).find { |candidate| candidate.tag_name == version } + return release unless release.nil? + + release_for_tag(repository: repository, version: version) + end + + def release_for_tag(repository:, version:) + client.release_for_tag(repository, version) + rescue Octokit::NotFound + nil + end + + private :find_release + private :release_for_tag + # Use the GitHub API to generate release notes based on the list of PRs between current tag and previous tag. # @note This API uses the `.github/release.yml` config file to classify the PRs by category in the generated list according to PR labels. # diff --git a/spec/github_helper_spec.rb b/spec/github_helper_spec.rb index ddd823304..bbd393527 100644 --- a/spec/github_helper_spec.rb +++ b/spec/github_helper_spec.rb @@ -640,12 +640,14 @@ def create_release(is_draft:, assets: [], name: nil) before do allow(Octokit::Client).to receive(:new).and_return(client) + allow(client).to receive(:release_for_tag).with(test_repo, test_version).and_return(release) allow(client).to receive(:releases).with(test_repo).and_return([release]) allow(client).to receive(:release_assets).with(release_url).and_return(existing_assets) allow(client).to receive_messages(upload_asset: uploaded_asset, delete_release_asset: true) end it 'fails clearly if the release does not exist' do + allow(client).to receive(:release_for_tag).with(test_repo, test_version).and_raise(Octokit::NotFound) allow(client).to receive(:releases).with(test_repo).and_return([]) with_tmp_file(named: 'test-app.zip') do |file_path| @@ -702,6 +704,7 @@ def create_release(is_draft:, assets: [], name: nil) draft_release = sawyer_resource_stub(url: release_url, html_url: release_html_url, tag_name: test_version, draft: true) other_release = sawyer_resource_stub(url: 'https://api.github.com/repos/repo-test/project-test/releases/456', html_url: 'https://github.com/repo-test/project-test/releases/tag/0.9.0', tag_name: '0.9.0') + allow(client).to receive(:release_for_tag).with(test_repo, test_version).and_raise(Octokit::NotFound) allow(client).to receive(:releases).with(test_repo).and_return([other_release, draft_release]) allow(client).to receive(:release_assets).with(release_url).and_return([]) @@ -714,6 +717,34 @@ def create_release(is_draft:, assets: [], name: nil) end end + it 'uses the release list without calling the direct release-by-tag lookup' do + draft_release = sawyer_resource_stub(url: 'draft-api-url', html_url: 'draft-html-url', tag_name: test_version, draft: true) + + allow(client).to receive(:releases).with(test_repo).and_return([draft_release]) + expect(client).not_to receive(:release_for_tag) + allow(client).to receive(:release_assets).with(draft_release.url).and_return([]) + + with_tmp_file(named: 'test-app.zip') do |file_path| + expect(client).to receive(:upload_asset).with(draft_release.url, file_path, { content_type: 'application/octet-stream' }) + + result = upload_release_assets(assets: [file_path]) + + expect(result).to eq(draft_release.html_url) + end + end + + it 'falls back to the direct release-by-tag lookup when the release list misses' do + with_tmp_file(named: 'test-app.zip') do |file_path| + allow(client).to receive(:releases).with(test_repo).and_return([]) + allow(client).to receive(:release_for_tag).with(test_repo, test_version).and_return(release) + expect(client).to receive(:upload_asset).with(release_url, file_path, { content_type: 'application/octet-stream' }) + + result = upload_release_assets(assets: [file_path]) + + expect(result).to eq(release_html_url) + end + end + it 'uploads one asset to the existing release' do with_tmp_file(named: 'test-app.zip') do |file_path| expect(client).to receive(:upload_asset).with(release_url, file_path, { content_type: 'application/octet-stream' }) From 8ecb66b90718b313b760a28417c59c2daf1b17a9 Mon Sep 17 00:00:00 2001 From: Ian Maia Date: Wed, 8 Jul 2026 16:41:14 +0200 Subject: [PATCH 2/3] Add CHANGELOG PR number --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea1aacbfc..fa2ed8d72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ _None_ - `StringsFileValidationHelper.find_duplicated_keys` now parses unquoted keys/values and inter-token comments, matching the grammar `plutil` accepts, instead of raising `Invalid character`. This lets `ios_lint_localizations`' `check_duplicate_keys` work on `InfoPlist.strings`-style files. [#741] - `ios_lint_localizations`' `check_duplicate_keys` now warns and skips, rather than crashing, on a file that parses as a property list but isn't a tokenizable flat `.strings`. [#741] - `L10nHelper.merge_strings` now prefixes keys via a comment-aware tokenizer, so unquoted keys, unquoted values, and keys behind an inter-token comment are prefixed in the output consistently with the reported keys. [#741] -- `upload_github_release_assets`: make release lookup more resilient by falling back to GitHub's direct release-by-tag lookup when the releases list does not include the requested release. +- `upload_github_release_assets`: make release lookup more resilient by falling back to GitHub's direct release-by-tag lookup when the releases list does not include the requested release. [#753] ### Internal Changes From fe482ca6875f590da45bea58dd1d2af747141236 Mon Sep 17 00:00:00 2001 From: "Ian G. Maia" Date: Mon, 13 Jul 2026 16:10:41 +0200 Subject: [PATCH 3/3] Update spec title Co-authored-by: Gio Lodi --- spec/github_helper_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/github_helper_spec.rb b/spec/github_helper_spec.rb index bbd393527..31c6fdf47 100644 --- a/spec/github_helper_spec.rb +++ b/spec/github_helper_spec.rb @@ -717,7 +717,7 @@ def create_release(is_draft:, assets: [], name: nil) end end - it 'uses the release list without calling the direct release-by-tag lookup' do + it 'uses the release list if available' do draft_release = sawyer_resource_stub(url: 'draft-api-url', html_url: 'draft-html-url', tag_name: test_version, draft: true) allow(client).to receive(:releases).with(test_repo).and_return([draft_release])