Skip to content
Merged
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
31 changes: 31 additions & 0 deletions sentry-api-client/Public/Get-SentryEventAttachments.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
function Get-SentryEventAttachments {
<#
.SYNOPSIS
Retrieves attachments for a specific event from Sentry.

.DESCRIPTION
Fetches attachment metadata (name, size, type, content type) for a specific Sentry event.
Does not download attachment content. Automatically removes hyphens from GUID-formatted event IDs.

.PARAMETER EventId
The unique identifier of the event whose attachments to retrieve.

.EXAMPLE
Get-SentryEventAttachments -EventId "abc123def456"
# Returns an array of attachment objects for the event
#>
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$EventId
)

# Remove hyphens from GUID-formatted event IDs
$EventId = $EventId -replace '-', ''

$Uri = Get-SentryProjectUrl -Resource "events/$EventId/attachments/"

# The API returns a top-level JSON array. ConvertFrom-Json -AsHashtable unwraps
# single-element arrays into a hashtable, so wrap in @() to ensure array output.
return , @(Invoke-SentryApiRequest -Uri $Uri -Method 'GET')
}
12 changes: 12 additions & 0 deletions sentry-api-client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ Connect-SentryApi -ApiToken "your-api-token" -Organization "your-org" -Project "
# Get specific event
Get-SentryEvent -EventId "123456"

# Get event attachments
Get-SentryEventAttachments -EventId "123456"

# Find events by tag
Get-SentryEventsByTag -TagName 'environment' -TagValue 'production'

Expand Down Expand Up @@ -74,6 +77,15 @@ Clears the current Sentry API connection and configuration.

Retrieves a specific event from Sentry by its ID.

### Get-SentryEventAttachments

Retrieves attachment metadata (name, size, type, content type) for a specific event. Does not download attachment content. Returns an array of attachment metadata objects.

```powershell
# Get attachments for an event
Get-SentryEventAttachments -EventId "123456"
```

### Get-SentryEventsByTag

Retrieves events filtered by a specific tag name and value.
Expand Down
1 change: 1 addition & 0 deletions sentry-api-client/SentryApiClient.psd1
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
'Find-SentryEventByTag',
'Get-SentryCLI',
'Get-SentryEvent',
'Get-SentryEventAttachments',
'Get-SentryEventsByTag',
'Get-SentryLogs',
'Get-SentryLogsByAttribute',
Expand Down
80 changes: 80 additions & 0 deletions sentry-api-client/Tests/SentryApiClient.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Describe 'SentryApiClient Module' {
'Connect-SentryApi',
'Disconnect-SentryApi',
'Get-SentryEvent',
'Get-SentryEventAttachments',
'Find-SentryEventByTag',
'Get-SentryEventsByTag',
'Invoke-SentryCLI',
Expand Down Expand Up @@ -91,6 +92,31 @@ Describe 'SentryApiClient Module' {
# Invoke-WebRequest returns an object with a Content property containing JSON
# Order matters - most specific patterns first
switch -Regex ($Uri) {
'/events/\w+/attachments/' {
$responseData = @(
@{
id = '111'
event_id = '12345678901234567890123456789012'
type = 'event.attachment'
name = 'hello.txt'
mimetype = 'text/plain'
size = 14
headers = @{ 'Content-Type' = 'text/plain' }
sha1 = 'abc123'
},
@{
id = '222'
event_id = '12345678901234567890123456789012'
type = 'event.attachment'
name = 'config.txt'
mimetype = 'application/octet-stream'
size = 42
headers = @{ 'Content-Type' = 'application/octet-stream' }
sha1 = 'def456'
}
)
return @{ Content = ($responseData | ConvertTo-Json -Depth 10) }
}
'/issues/[^/]+/events/' {
# Handle issues/{id}/events/ endpoint - most specific first
$responseData = @(
Expand Down Expand Up @@ -271,6 +297,60 @@ Describe 'SentryApiClient Module' {
Assert-MockCalled -ModuleName SentryApiClient Invoke-WebRequest -Times 3
}
}

Context 'Get-SentryEventAttachments' {
It 'Should retrieve attachments for an event' {
$eventId = '12345678901234567890123456789012'
$result = Get-SentryEventAttachments -EventId $eventId

$result | Should -Not -BeNullOrEmpty
$result | Should -HaveCount 2
$result[0].name | Should -Be 'hello.txt'
$result[1].name | Should -Be 'config.txt'
}

It 'Should remove hyphens from GUID-formatted event ID' {
$guidEventId = '12345678-9012-3456-7890-123456789012'

Get-SentryEventAttachments -EventId $guidEventId

Assert-MockCalled -ModuleName SentryApiClient Invoke-WebRequest -ParameterFilter {
$Uri -like '*events/12345678901234567890123456789012/attachments/*'
}
}

It 'Should construct correct API URL' {
$eventId = '12345678901234567890123456789012'

Get-SentryEventAttachments -EventId $eventId

Assert-MockCalled -ModuleName SentryApiClient Invoke-WebRequest -ParameterFilter {
$Uri -match 'https://sentry.io/api/0/projects/test-org/test-project/events/\w+/attachments/'
}
}

It 'Should return array even with single attachment' {
Mock -ModuleName SentryApiClient Invoke-WebRequest {
$responseData = @(
@{
id = '333'
event_id = 'single'
type = 'event.attachment'
name = 'only.txt'
size = 5
headers = @{ 'Content-Type' = 'text/plain' }
}
)
return @{ Content = ($responseData | ConvertTo-Json -Depth 10) }
}

$result = Get-SentryEventAttachments -EventId 'single'

$result -is [Array] | Should -BeTrue
$result | Should -HaveCount 1
$result[0].name | Should -Be 'only.txt'
}
}
}

Context 'Error Handling' {
Expand Down
61 changes: 60 additions & 1 deletion utils/Integration.TestUtils.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -455,5 +455,64 @@ function Get-SentryTestTransaction {
throw "Transaction with trace $TraceId not found in Sentry within $TimeoutSeconds seconds: $lastError"
}

function Get-SentryTestEventAttachments {
[CmdletBinding()]
param(
[Parameter(Mandatory = $true)]
[string]$EventId,

[Parameter()]
[int]$ExpectedCount = 1,

[Parameter()]
[int]$TimeoutSeconds = 120
)

Write-Host "Fetching Sentry event attachments for event: $EventId" -ForegroundColor Yellow
$progressActivity = "Waiting for attachments on event $EventId"

$startTime = Get-Date
$endTime = $startTime.AddSeconds($TimeoutSeconds)
$lastError = $null
$elapsedSeconds = 0

try {
do {
$attachments = @()
$elapsedSeconds = [int]((Get-Date) - $startTime).TotalSeconds
$percentComplete = [math]::Min(100, ($elapsedSeconds / $TimeoutSeconds) * 100)

Write-Progress -Activity $progressActivity -Status "Elapsed: $elapsedSeconds/$TimeoutSeconds seconds" -PercentComplete $percentComplete

try {
$response = Get-SentryEventAttachments -EventId $EventId
if ($response.Count -ge $ExpectedCount) {
$attachments = $response
}
} catch {
$lastError = $_.Exception.Message
Write-Debug "Attachments for event $EventId not found yet: $lastError"
}

if ($attachments.Count -ge $ExpectedCount) {
Write-Host "Found $($attachments.Count) attachment(s) for event $EventId" -ForegroundColor Green

$attachmentsJson = $attachments | ConvertTo-Json -Depth 10
$attachmentsJson | Out-File -FilePath (Get-OutputFilePath "attachments-$EventId.json")

return , @($attachments)
}

Start-Sleep -Milliseconds 500
$currentTime = Get-Date
} while ($currentTime -lt $endTime)
} finally {
Write-Progress -Activity $progressActivity -Completed
}

$foundCount = if ($attachments) { $attachments.Count } else { 0 }
throw "Expected at least $ExpectedCount attachment(s) for event $EventId but found $foundCount within $TimeoutSeconds seconds. Last error: $lastError"
}

# Export module functions
Export-ModuleMember -Function Invoke-CMakeConfigure, Invoke-CMakeBuild, Set-OutputDir, Get-OutputFilePath, Get-EventIds, Get-SentryTestEvent, Get-SentryTestLog, Get-SentryTestMetric, Get-SentryTestTransaction, Get-PackageAumid
Export-ModuleMember -Function Invoke-CMakeConfigure, Invoke-CMakeBuild, Set-OutputDir, Get-OutputFilePath, Get-EventIds, Get-SentryTestEvent, Get-SentryTestEventAttachments, Get-SentryTestLog, Get-SentryTestMetric, Get-SentryTestTransaction, Get-PackageAumid