Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -469,7 +469,7 @@ impl<'a> AuthenticatedApi<'a> {
}

/// Convenience method to call self.api.request.
fn request(&self, method: Method, url: &str) -> ApiResult<ApiRequest> {
pub fn request(&self, method: Method, url: &str) -> ApiResult<ApiRequest> {
self.api.request(method, url, None)
}

Expand Down Expand Up @@ -1899,6 +1899,15 @@ impl ApiRequest {
}
}

impl fmt::Display for ApiResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.body {
Some(ref body) => write!(f, "{}", String::from_utf8_lossy(body)),
None => Ok(()),
}
}
}

impl ApiResponse {
/// Returns the status code of the response
pub fn status(&self) -> u32 {
Expand Down
55 changes: 55 additions & 0 deletions src/commands/api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
use anyhow::Result;
use clap::{Arg, ArgAction, ArgMatches, Command, ValueHint};

use crate::api::{Api, Method};

pub fn make_command(command: Command) -> Command {
command
.about("Make a raw API request to the Sentry API.")
.arg(
Arg::new("endpoint")
.value_name("ENDPOINT")
.required(true)
.value_hint(ValueHint::Url)
.help(
"The API endpoint to request (e.g., 'organizations/' or '/projects/my-org/my-project/releases/').{n}\
The endpoint will be prefixed with '/api/0/' automatically.",
),
)
.arg(
Arg::new("method")
.short('m')
.long("method")
.value_name("METHOD")
.value_parser(["GET", "POST", "PUT", "DELETE"])
.default_value("GET")
.action(ArgAction::Set)
.help("The HTTP method to use for the request."),
)
}

pub fn execute(matches: &ArgMatches) -> Result<()> {
let endpoint = matches
.get_one::<String>("endpoint")
.expect("endpoint is required");
let method_str = matches
.get_one::<String>("method")
.expect("method has a default value");

let method = match method_str.as_str() {
"GET" => Method::Get,
"POST" => Method::Post,
"PUT" => Method::Put,
"DELETE" => Method::Delete,
_ => unreachable!("Invalid method value"),
};

let api = Api::current();
let authenticated_api = api.authenticated()?;
let resp = authenticated_api.request(method, endpoint)?.send()?;

// Print the response body as-is to stdout
println!("{resp}");

Ok(())
}
2 changes: 2 additions & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use crate::utils::system::{load_dotenv, print_error, set_panic_hook, QuietExit};
use crate::utils::update::run_sentrycli_update_nagger;
use crate::utils::value_parsers::auth_token_parser;

mod api;
mod bash_hook;
mod build;
mod dart_symbol_map;
Expand Down Expand Up @@ -51,6 +52,7 @@ mod upload_proguard;

macro_rules! each_subcommand {
($mac:ident) => {
$mac!(api);
$mac!(bash_hook);
$mac!(build);
$mac!(debug_files);
Expand Down
17 changes: 17 additions & 0 deletions tests/integration/_cases/api/api-get-with-leading-slash.trycmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
```
$ sentry-cli api /organizations/
? success
[
{
"id": "1",
"slug": "sentry",
"name": "Sentry",
"dateCreated": "2014-12-15T12:00:00.000Z",
"isEarlyAdopter": true,
"require2FA": false,
"requireEmailVerification": false,
"features": []
}
]

```
17 changes: 17 additions & 0 deletions tests/integration/_cases/api/api-get.trycmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
```
$ sentry-cli api organizations/
? success
[
{
"id": "1",
"slug": "sentry",
"name": "Sentry",
"dateCreated": "2014-12-15T12:00:00.000Z",
"isEarlyAdopter": true,
"require2FA": false,
"requireEmailVerification": false,
"features": []
}
]

```
24 changes: 24 additions & 0 deletions tests/integration/_cases/api/api-help.trycmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
```
$ sentry-cli api --help
? success
Make a raw API request to the Sentry API.

Usage: sentry-cli[EXE] api [OPTIONS] <ENDPOINT>

Arguments:
<ENDPOINT>
The API endpoint to request (e.g., 'organizations/' or
'/projects/my-org/my-project/releases/').
The endpoint will be prefixed with '/api/0/' automatically.

Options:
-m, --method <METHOD>
The HTTP method to use for the request.

[default: GET]
[possible values: GET, POST, PUT, DELETE]

-h, --help
Print help (see a summary with '-h')

```
14 changes: 14 additions & 0 deletions tests/integration/_cases/api/api-post.trycmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
```
$ sentry-cli api --method POST organizations/wat-org/releases/
? success
{
"version": "1.0.0",
"url": null,
"dateCreated": "2024-01-15T12:00:00.000Z",
"dateReleased": null,
"lastEvent": null,
"newGroups": 0,
"projects": []
}

```
1 change: 1 addition & 0 deletions tests/integration/_cases/help/help.trycmd
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Usage: sentry-cli[EXE] [OPTIONS] <COMMAND>

Commands:
completions Generate completions for the specified shell.
api Make a raw API request to the Sentry API.
debug-files Locate, analyze or upload debug information files. [aliases: dif]
deploys Manage deployments for Sentry releases.
events Manage events on Sentry.
Expand Down
12 changes: 12 additions & 0 deletions tests/integration/_responses/api/get-organizations.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"id": "1",
"slug": "sentry",
"name": "Sentry",
"dateCreated": "2014-12-15T12:00:00.000Z",
"isEarlyAdopter": true,
"require2FA": false,
"requireEmailVerification": false,
"features": []
}
]
9 changes: 9 additions & 0 deletions tests/integration/_responses/api/post-releases.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"version": "1.0.0",
"url": null,
"dateCreated": "2024-01-15T12:00:00.000Z",
"dateReleased": null,
"lastEvent": null,
"newGroups": 0,
"projects": []
}
Loading