Skip to content

Commit 98ca0e8

Browse files
committed
Fix discovery of draft releases during artifact upload
1 parent 04864e9 commit 98ca0e8

File tree

4 files changed

+60
-16
lines changed

4 files changed

+60
-16
lines changed

Justfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ release-create tag:
8585
exit 1
8686
;;
8787
"release not found")
88-
gh release create {{tag}} --draft --notes TBD --verify-tag
88+
gh release create {{tag}} --draft --title {{tag}} --notes TBD --verify-tag
8989
;;
9090
*)
9191
echo "error: unexpected gh cli output: $draft_exists"

src/github.rs

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use {
77
RELEASE_TRIPLES, bootstrap_llvm, build_wanted_filenames, produce_install_only,
88
produce_install_only_stripped,
99
},
10-
anyhow::{Result, anyhow},
10+
anyhow::{Context, Result, anyhow},
1111
bytes::Bytes,
1212
clap::ArgMatches,
1313
futures::StreamExt,
@@ -170,6 +170,43 @@ fn new_github_client(args: &ArgMatches) -> Result<(Octocrab, String)> {
170170
Ok((builder.build()?, token))
171171
}
172172

173+
async fn get_draft_release_by_tag(
174+
client: &Octocrab,
175+
organization: &str,
176+
repo: &str,
177+
tag: &str,
178+
) -> Result<Release> {
179+
let mut page = client
180+
.repos(organization, repo)
181+
.releases()
182+
.list()
183+
.send()
184+
.await?;
185+
186+
let release = loop {
187+
if let Some(release) = page
188+
.take_items()
189+
.into_iter()
190+
.find(|release| release.tag_name == tag)
191+
{
192+
break Some(release);
193+
}
194+
195+
page = match client.get_page::<Release>(&page.next).await? {
196+
Some(page) => page,
197+
None => break None,
198+
};
199+
};
200+
201+
let release = release.ok_or_else(|| anyhow!("release {tag} does not exist"))?;
202+
203+
if !release.draft {
204+
return Err(anyhow!("release {tag} exists but is not a draft"));
205+
}
206+
207+
Ok(release)
208+
}
209+
173210
pub async fn command_fetch_release_distributions(args: &ArgMatches) -> Result<()> {
174211
let dest_dir = args
175212
.get_one::<PathBuf>("dest")
@@ -486,12 +523,7 @@ pub async fn command_upload_release_distributions(args: &ArgMatches) -> Result<(
486523
}
487524

488525
let (client, token) = new_github_client(args)?;
489-
let repo_handler = client.repos(organization, repo);
490-
let releases = repo_handler.releases();
491-
let release = releases
492-
.get_by_tag(tag)
493-
.await
494-
.map_err(|_| anyhow!("release {tag} does not exist; create it via GitHub web UI"))?;
526+
let release = get_draft_release_by_tag(&client, organization, repo, tag).await?;
495527

496528
let retry_policy = ExponentialBackoff::builder().build_with_max_retries(5);
497529
let raw_client = Client::new();
@@ -538,10 +570,9 @@ pub async fn command_upload_release_distributions(args: &ArgMatches) -> Result<(
538570

539571
// Check that content wasn't munged as part of uploading. This once happened
540572
// and created a busted release. Never again.
541-
let release = releases
542-
.get_by_tag(tag)
573+
let release = get_draft_release_by_tag(&client, organization, repo, tag)
543574
.await
544-
.map_err(|_| anyhow!("could not find release; this should not happen!"))?;
575+
.with_context(|| format!("could not find draft release {tag}; this should not happen"))?;
545576
let shasums_asset = release
546577
.assets
547578
.into_iter()

src/github_api_tester.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,8 @@ class Release:
138138
release_id: int
139139
tag_name: str
140140
assets: list = dataclasses.field(default_factory=list)
141+
draft: bool = True
142+
prerelease: bool = False
141143
# fault0 and fault1 are called before and after receiving the first
142144
# chunk of a PUT request, respectively. Each is called once per
143145
# release - the first upload that hits it will disarm it.
@@ -157,14 +159,15 @@ def render(self) -> dict:
157159
"node_id": "fakenode",
158160
"tag_name": self.tag_name,
159161
"target_commitish": "main",
160-
"draft": False,
161-
"prerelease": True,
162+
"draft": self.draft,
163+
"prerelease": self.prerelease,
162164
"assets": [i.render() for i in self.assets],
163165
}
164166

165167

166168
releases = [
167169
Release(1, "basic"),
170+
Release(2, "draft"),
168171
Release(11, "early-drop", fault0=drop_connection),
169172
Release(12, "late-drop", fault1=drop_connection),
170173
Release(4011, "early-401", fault0=lambda: quart.abort(401)),
@@ -195,7 +198,17 @@ def get_release(*, tag=None, release=None) -> Release:
195198

196199
@app.route("/repos/<org>/<repo>/releases/tags/<tag>")
197200
async def get_release_by_tag(org, repo, tag):
198-
return get_release(tag=tag).render()
201+
release = get_release(tag=tag)
202+
if release.draft:
203+
quart.abort(
204+
404, response=quart.jsonify({"message": "Not Found", "status": "404"})
205+
)
206+
return release.render()
207+
208+
209+
@app.route("/repos/<org>/<repo>/releases")
210+
async def list_releases(org, repo):
211+
return quart.jsonify([release.render() for release in releases])
199212

200213

201214
@app.route("/repos/<org>/<repo>/releases/<int:release>")
@@ -311,7 +324,7 @@ async def upload_release_distributions(*args):
311324

312325

313326
# TODO: test all of [r.tag_name for r in releases]
314-
TAGS_TO_TEST = ["basic", "early-drop", "late-drop", "early-403", "late-403"]
327+
TAGS_TO_TEST = ["basic", "draft", "early-drop", "late-drop", "early-403", "late-403"]
315328

316329

317330
@pytest.mark.parametrize("tag", TAGS_TO_TEST)

src/macho.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use {
66
crate::validation::ValidationContext,
7-
anyhow::{anyhow, Context, Result},
7+
anyhow::{Context, Result, anyhow},
88
apple_sdk::{AppleSdk, SdkSearch, SdkSearchLocation, SdkSorting, SdkVersion, SimpleSdk},
99
semver::Version,
1010
std::{

0 commit comments

Comments
 (0)