Skip to content

Commit ff45453

Browse files
chore(api): Stop calling project-release endpoints (#2991)
### Description We should instead use the organization-release endpoints. The project-release endpoints have been kept around for backwards compatibility with ancient self-hosted versions, which we are dropping support for. ### Issues - Resolves #2840 - Resolves [CLI-186](https://linear.app/getsentry/issue/CLI-186/remove-calls-to-projectsreleases-endpoints)
1 parent 15dccc3 commit ff45453

File tree

9 files changed

+85
-181
lines changed

9 files changed

+85
-181
lines changed

src/api/mod.rs

Lines changed: 39 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use chrono::Duration;
2727
use chrono::{DateTime, FixedOffset, Utc};
2828
use clap::ArgMatches;
2929
use flate2::write::GzEncoder;
30-
use if_chain::if_chain;
3130
use lazy_static::lazy_static;
3231
use log::{debug, info, warn};
3332
use parking_lot::Mutex;
@@ -460,21 +459,9 @@ impl AuthenticatedApi<'_> {
460459

461460
/// Creates a new release.
462461
pub fn new_release(&self, org: &str, release: &NewRelease) -> ApiResult<ReleaseInfo> {
463-
// for single project releases use the legacy endpoint that is project bound.
464-
// This means we can support both old and new servers.
465-
if release.projects.len() == 1 {
466-
let path = format!(
467-
"/projects/{}/{}/releases/",
468-
PathArg(org),
469-
PathArg(&release.projects[0])
470-
);
471-
self.post(&path, release)?
472-
.convert_rnf(ApiErrorKind::ProjectNotFound)
473-
} else {
474-
let path = format!("/organizations/{}/releases/", PathArg(org));
475-
self.post(&path, release)?
476-
.convert_rnf(ApiErrorKind::OrganizationNotFound)
477-
}
462+
let path = format!("/organizations/{}/releases/", PathArg(org));
463+
self.post(&path, release)?
464+
.convert_rnf(ApiErrorKind::OrganizationNotFound)
478465
}
479466

480467
/// Updates a release.
@@ -484,29 +471,20 @@ impl AuthenticatedApi<'_> {
484471
version: &str,
485472
release: &UpdatedRelease,
486473
) -> ApiResult<ReleaseInfo> {
487-
if_chain! {
488-
if let Some(ref projects) = release.projects;
489-
if projects.len() == 1;
490-
then {
491-
let path = format!("/projects/{}/{}/releases/{}/",
492-
PathArg(org),
493-
PathArg(&projects[0]),
494-
PathArg(version)
495-
);
496-
self.put(&path, release)?.convert_rnf(ApiErrorKind::ReleaseNotFound)
497-
} else {
498-
if release.version.is_some() {
499-
let path = format!("/organizations/{}/releases/",
500-
PathArg(org));
501-
return self.post(&path, release)?.convert_rnf(ApiErrorKind::ReleaseNotFound)
502-
}
503-
504-
let path = format!("/organizations/{}/releases/{}/",
505-
PathArg(org),
506-
PathArg(version));
507-
self.put(&path, release)?.convert_rnf(ApiErrorKind::ReleaseNotFound)
508-
}
474+
if release.version.is_some() {
475+
let path = format!("/organizations/{}/releases/", PathArg(org));
476+
return self
477+
.post(&path, release)?
478+
.convert_rnf(ApiErrorKind::ReleaseNotFound);
509479
}
480+
481+
let path = format!(
482+
"/organizations/{}/releases/{}/",
483+
PathArg(org),
484+
PathArg(version)
485+
);
486+
self.put(&path, release)?
487+
.convert_rnf(ApiErrorKind::ReleaseNotFound)
510488
}
511489

512490
/// Sets release commits
@@ -530,28 +508,14 @@ impl AuthenticatedApi<'_> {
530508
}
531509

532510
/// Deletes an already existing release. Returns `true` if it was deleted
533-
/// or `false` if not. The project is needed to support the old deletion
534-
/// API.
535-
pub fn delete_release(
536-
&self,
537-
org: &str,
538-
project: Option<&str>,
539-
version: &str,
540-
) -> ApiResult<bool> {
541-
let resp = if let Some(project) = project {
542-
self.delete(&format!(
543-
"/projects/{}/{}/releases/{}/",
544-
PathArg(org),
545-
PathArg(project),
546-
PathArg(version)
547-
))?
548-
} else {
549-
self.delete(&format!(
550-
"/organizations/{}/releases/{}/",
551-
PathArg(org),
552-
PathArg(version)
553-
))?
554-
};
511+
/// or `false` if not.
512+
pub fn delete_release(&self, org: &str, version: &str) -> ApiResult<bool> {
513+
let resp = self.delete(&format!(
514+
"/organizations/{}/releases/{}/",
515+
PathArg(org),
516+
PathArg(version)
517+
))?;
518+
555519
if resp.status() == 404 {
556520
Ok(false)
557521
} else {
@@ -561,26 +525,12 @@ impl AuthenticatedApi<'_> {
561525

562526
/// Looks up a release and returns it. If it does not exist `None`
563527
/// will be returned.
564-
pub fn get_release(
565-
&self,
566-
org: &str,
567-
project: Option<&str>,
568-
version: &str,
569-
) -> ApiResult<Option<ReleaseInfo>> {
570-
let path = if let Some(project) = project {
571-
format!(
572-
"/projects/{}/{}/releases/{}/",
573-
PathArg(org),
574-
PathArg(project),
575-
PathArg(version)
576-
)
577-
} else {
578-
format!(
579-
"/organizations/{}/releases/{}/",
580-
PathArg(org),
581-
PathArg(version)
582-
)
583-
};
528+
pub fn get_release(&self, org: &str, version: &str) -> ApiResult<Option<ReleaseInfo>> {
529+
let path = format!(
530+
"/organizations/{}/releases/{}/",
531+
PathArg(org),
532+
PathArg(version)
533+
);
584534
let resp = self.get(&path)?;
585535
if resp.status() == 404 {
586536
Ok(None)
@@ -591,40 +541,24 @@ impl AuthenticatedApi<'_> {
591541

592542
/// Returns a list of releases for a given project. This is currently a
593543
/// capped list by what the server deems an acceptable default limit.
594-
pub fn list_releases(&self, org: &str, project: Option<&str>) -> ApiResult<Vec<ReleaseInfo>> {
595-
if let Some(project) = project {
596-
let path = format!("/projects/{}/{}/releases/", PathArg(org), PathArg(project));
597-
self.get(&path)?
598-
.convert_rnf::<Vec<ReleaseInfo>>(ApiErrorKind::ProjectNotFound)
599-
} else {
600-
let path = format!("/organizations/{}/releases/", PathArg(org));
601-
self.get(&path)?
602-
.convert_rnf::<Vec<ReleaseInfo>>(ApiErrorKind::OrganizationNotFound)
603-
}
544+
pub fn list_releases(&self, org: &str) -> ApiResult<Vec<ReleaseInfo>> {
545+
let path = format!("/organizations/{}/releases/", PathArg(org));
546+
self.get(&path)?
547+
.convert_rnf::<Vec<ReleaseInfo>>(ApiErrorKind::OrganizationNotFound)
604548
}
605549

606550
/// Looks up a release commits and returns it. If it does not exist `None`
607551
/// will be returned.
608552
pub fn get_release_commits(
609553
&self,
610554
org: &str,
611-
project: Option<&str>,
612555
version: &str,
613556
) -> ApiResult<Option<Vec<ReleaseCommit>>> {
614-
let path = if let Some(project) = project {
615-
format!(
616-
"/projects/{}/{}/releases/{}/commits/",
617-
PathArg(org),
618-
PathArg(project),
619-
PathArg(version)
620-
)
621-
} else {
622-
format!(
623-
"/organizations/{}/releases/{}/commits/",
624-
PathArg(org),
625-
PathArg(version)
626-
)
627-
};
557+
let path = format!(
558+
"/organizations/{}/releases/{}/commits/",
559+
PathArg(org),
560+
PathArg(version)
561+
);
628562
let resp = self.get(&path)?;
629563
if resp.status() == 404 {
630564
Ok(None)

src/commands/releases/delete.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,11 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
1717
let api = Api::current();
1818
#[expect(clippy::unwrap_used, reason = "legacy code")]
1919
let version = matches.get_one::<String>("version").unwrap();
20-
let project = config.get_project(matches).ok();
2120

22-
if api.authenticated()?.delete_release(
23-
&config.get_org(matches)?,
24-
project.as_deref(),
25-
version,
26-
)? {
21+
if api
22+
.authenticated()?
23+
.delete_release(&config.get_org(matches)?, version)?
24+
{
2725
println!("Deleted release {version}!");
2826
} else {
2927
println!("Did nothing. Release with this version ({version}) does not exist.");

src/commands/releases/info.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
3636
let version = matches.get_one::<String>("version").unwrap();
3737
let config = Config::current();
3838
let org = config.get_org(matches)?;
39-
let project = config.get_project(matches).ok();
40-
let release = authenticated_api.get_release(&org, project.as_deref(), version)?;
39+
let release = authenticated_api.get_release(&org, version)?;
4140

4241
if is_quiet_mode() {
4342
if release.is_none() {
@@ -85,9 +84,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
8584
}
8685

8786
if matches.get_flag("show_commits") {
88-
if let Ok(Some(commits)) =
89-
authenticated_api.get_release_commits(&org, project.as_deref(), version)
90-
{
87+
if let Ok(Some(commits)) = authenticated_api.get_release_commits(&org, version) {
9188
if !commits.is_empty() {
9289
data_row.add(
9390
commits

src/commands/releases/list.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,10 +43,9 @@ pub fn make_command(command: Command) -> Command {
4343
pub fn execute(matches: &ArgMatches) -> Result<()> {
4444
let config = Config::current();
4545
let api = Api::current();
46-
let project = config.get_project(matches).ok();
4746
let releases = api
4847
.authenticated()?
49-
.list_releases(&config.get_org(matches)?, project.as_deref())?;
48+
.list_releases(&config.get_org(matches)?)?;
5049

5150
if matches.get_flag("raw") {
5251
let versions = releases

tests/integration/releases/delete.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn successfully_deletes() {
66
.mock_endpoint(
77
MockEndpointBuilder::new(
88
"DELETE",
9-
"/api/0/projects/wat-org/wat-project/releases/wat-release/",
9+
"/api/0/organizations/wat-org/releases/wat-release/",
1010
)
1111
.with_status(204),
1212
)
@@ -20,7 +20,7 @@ fn allows_for_release_to_start_with_hyphen() {
2020
.mock_endpoint(
2121
MockEndpointBuilder::new(
2222
"DELETE",
23-
"/api/0/projects/wat-org/wat-project/releases/-hyphenated-release/",
23+
"/api/0/organizations/wat-org/releases/-hyphenated-release/",
2424
)
2525
.with_status(204),
2626
)
@@ -32,11 +32,8 @@ fn allows_for_release_to_start_with_hyphen() {
3232
fn informs_about_nonexisting_releases() {
3333
TestManager::new()
3434
.mock_endpoint(
35-
MockEndpointBuilder::new(
36-
"DELETE",
37-
"/api/0/projects/wat-org/wat-project/releases/whoops/",
38-
)
39-
.with_status(404),
35+
MockEndpointBuilder::new("DELETE", "/api/0/organizations/wat-org/releases/whoops/")
36+
.with_status(404),
4037
)
4138
.register_trycmd_test("releases/releases-delete-nonexisting.trycmd")
4239
.with_default_token();
@@ -48,7 +45,7 @@ fn doesnt_allow_to_delete_active_releases() {
4845
.mock_endpoint(
4946
MockEndpointBuilder::new(
5047
"DELETE",
51-
"/api/0/projects/wat-org/wat-project/releases/wat-release/",
48+
"/api/0/organizations/wat-org/releases/wat-release/",
5249
)
5350
.with_status(400)
5451
.with_response_file("releases/delete-active-release.json"),

tests/integration/releases/finalize.rs

Lines changed: 9 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@ use serde_json::json;
66
fn successfully_creates_a_release() {
77
TestManager::new()
88
.mock_endpoint(
9-
MockEndpointBuilder::new(
10-
"PUT",
11-
"/api/0/projects/wat-org/wat-project/releases/wat-release/",
12-
)
13-
.with_response_file("releases/get-release.json"),
9+
MockEndpointBuilder::new("PUT", "/api/0/organizations/wat-org/releases/wat-release/")
10+
.with_response_file("releases/get-release.json"),
1411
)
1512
.register_trycmd_test("releases/releases-finalize.trycmd")
1613
.with_default_token();
@@ -22,7 +19,7 @@ fn allows_for_release_to_start_with_hyphen() {
2219
.mock_endpoint(
2320
MockEndpointBuilder::new(
2421
"PUT",
25-
"/api/0/projects/wat-org/wat-project/releases/-hyphenated-release/",
22+
"/api/0/organizations/wat-org/releases/-hyphenated-release/",
2623
)
2724
.with_response_file("releases/get-release.json"),
2825
)
@@ -34,15 +31,12 @@ fn allows_for_release_to_start_with_hyphen() {
3431
fn release_with_custom_dates() {
3532
TestManager::new()
3633
.mock_endpoint(
37-
MockEndpointBuilder::new(
38-
"PUT",
39-
"/api/0/projects/wat-org/wat-project/releases/wat-release/",
40-
)
41-
.with_response_file("releases/get-release.json")
42-
.with_matcher(Matcher::PartialJson(json!({
43-
"projects": ["wat-project"],
44-
"dateReleased": "2015-05-15T00:00:00Z"
45-
}))),
34+
MockEndpointBuilder::new("PUT", "/api/0/organizations/wat-org/releases/wat-release/")
35+
.with_response_file("releases/get-release.json")
36+
.with_matcher(Matcher::PartialJson(json!({
37+
"projects": ["wat-project"],
38+
"dateReleased": "2015-05-15T00:00:00Z"
39+
}))),
4640
)
4741
.register_trycmd_test("releases/releases-finalize-dates.trycmd")
4842
.with_default_token();

0 commit comments

Comments
 (0)