( tag: string, deps: NotesFetcherDeps, )
| 285 | } |
| 286 | |
| 287 | async function defaultFetchReleaseNotesForTag( |
| 288 | tag: string, |
| 289 | deps: NotesFetcherDeps, |
| 290 | ): Promise<ReleaseNotes | null> { |
| 291 | const url = `https://api.github.com/repos/${deps.repositoryOwner}/${deps.repositoryName}/releases/tags/${tag}`; |
| 292 | const controller = new AbortController(); |
| 293 | const timeout = setTimeout(() => controller.abort(), 10_000); |
| 294 | |
| 295 | try { |
| 296 | let response: Response; |
| 297 | try { |
| 298 | response = await fetch(url, { |
| 299 | headers: { |
| 300 | Accept: 'application/vnd.github+json', |
| 301 | 'User-Agent': `xcodebuildmcp/${deps.currentVersion}`, |
| 302 | }, |
| 303 | signal: controller.signal, |
| 304 | }); |
| 305 | } catch { |
| 306 | return null; |
| 307 | } |
| 308 | |
| 309 | if (response.status === 404) { |
| 310 | return null; |
| 311 | } |
| 312 | |
| 313 | if (!response.ok) { |
| 314 | return null; |
| 315 | } |
| 316 | |
| 317 | const data = (await response.json()) as GitHubReleaseResponse; |
| 318 | |
| 319 | return { |
| 320 | body: data.body ?? '', |
| 321 | htmlUrl: |
| 322 | data.html_url ?? |
| 323 | `https://github.com/${deps.repositoryOwner}/${deps.repositoryName}/releases/tag/${tag}`, |
| 324 | name: data.name ?? undefined, |
| 325 | publishedAt: data.published_at ?? undefined, |
| 326 | }; |
| 327 | } finally { |
| 328 | clearTimeout(timeout); |
| 329 | } |
| 330 | } |
| 331 | |
| 332 | // --- Release notes rendering --- |
| 333 |
no outgoing calls
no test coverage detected