d25d482dc2
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
284 lines
9.9 KiB
TypeScript
284 lines
9.9 KiB
TypeScript
import type { TriggerOutput } from '@/triggers/types'
|
||
|
||
export const azureDevOpsTriggerOptions = [
|
||
{ label: 'Build Failed', id: 'azure_devops_build_failed' },
|
||
{ label: 'Work Item Created', id: 'azure_devops_work_item_created' },
|
||
{ label: 'All Service Hook Events', id: 'azure_devops_webhook' },
|
||
]
|
||
|
||
export const AZURE_DEVOPS_BUILD_FAILED_EVENT = 'build.complete'
|
||
export const AZURE_DEVOPS_WORK_ITEM_CREATED_EVENT = 'workitem.created'
|
||
|
||
function instructions(steps: string[]): string {
|
||
return steps.map((s, i) => `<div class="mb-3"><strong>${i + 1}.</strong> ${s}</div>`).join('')
|
||
}
|
||
|
||
export const buildFailedSetupInstructions = instructions([
|
||
'Open your Azure DevOps project and go to <strong>Project settings → Service hooks</strong>.',
|
||
'Click <strong>+ Create subscription</strong>, choose <strong>Web Hooks</strong>, then <strong>Next</strong>.',
|
||
'For <strong>Trigger on this type of event</strong>, select <strong>Build completed</strong>.',
|
||
'Under <strong>Filters</strong>, set <strong>Build result</strong> to <strong>Failed</strong> (optionally add Canceled / Partially succeeded).',
|
||
'Click <strong>Next</strong>, paste the <strong>Webhook URL</strong> above into the <strong>URL</strong> field.',
|
||
'Leave other fields as defaults. Click <strong>Test</strong> to verify, then <strong>Finish</strong>.',
|
||
])
|
||
|
||
export const workItemCreatedSetupInstructions = instructions([
|
||
'Open your Azure DevOps project and go to <strong>Project settings → Service hooks</strong>.',
|
||
'Click <strong>+ Create subscription</strong>, choose <strong>Web Hooks</strong>, then <strong>Next</strong>.',
|
||
'For <strong>Trigger on this type of event</strong>, select <strong>Work item created</strong>.',
|
||
'Click <strong>Next</strong>, paste the <strong>Webhook URL</strong> above into the <strong>URL</strong> field.',
|
||
'Leave other fields as defaults. Click <strong>Test</strong> to verify, then <strong>Finish</strong>.',
|
||
])
|
||
|
||
export const webhookSetupInstructions = instructions([
|
||
'Open your Azure DevOps project and go to <strong>Project settings → Service hooks</strong>.',
|
||
'Click <strong>+ Create subscription</strong>, choose <strong>Web Hooks</strong>, then <strong>Next</strong>.',
|
||
'Select whichever <strong>event types</strong> you want this URL to receive (build, work item, release, etc.).',
|
||
'Click <strong>Next</strong>, paste the <strong>Webhook URL</strong> above into the <strong>URL</strong> field.',
|
||
'Leave other fields as defaults. Click <strong>Test</strong> to verify, then <strong>Finish</strong>.',
|
||
'Sim does not filter deliveries for this trigger — configure event types in Azure DevOps.',
|
||
])
|
||
|
||
/**
|
||
* Returns whether an Azure DevOps service hook payload matches the configured trigger.
|
||
*/
|
||
export function isAzureDevOpsEventMatch(triggerId: string, body: Record<string, unknown>): boolean {
|
||
if (triggerId === 'azure_devops_webhook') {
|
||
return true
|
||
}
|
||
|
||
const eventType = body.eventType as string | undefined
|
||
|
||
if (triggerId === 'azure_devops_build_failed') {
|
||
if (eventType !== AZURE_DEVOPS_BUILD_FAILED_EVENT) {
|
||
return false
|
||
}
|
||
const resource = body.resource as Record<string, unknown> | undefined
|
||
const result = (resource?.result as string | undefined)?.toLowerCase()
|
||
return (
|
||
result === 'failed' ||
|
||
result === 'canceled' ||
|
||
result === 'cancelled' ||
|
||
result === 'stopped' ||
|
||
result === 'partiallysucceeded'
|
||
)
|
||
}
|
||
|
||
if (triggerId === 'azure_devops_work_item_created') {
|
||
return eventType === AZURE_DEVOPS_WORK_ITEM_CREATED_EVENT
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
export function buildBuildFailedOutputs(): Record<string, TriggerOutput> {
|
||
return {
|
||
buildId: {
|
||
type: 'number',
|
||
description: 'Build ID',
|
||
},
|
||
buildNumber: {
|
||
type: 'string',
|
||
description: 'Build number string (e.g. 20240101.1)',
|
||
},
|
||
result: {
|
||
type: 'string',
|
||
description: 'Build result: failed | canceled | partiallySucceeded',
|
||
},
|
||
pipelineId: {
|
||
type: 'number',
|
||
description: 'Pipeline definition ID',
|
||
},
|
||
pipelineName: {
|
||
type: 'string',
|
||
description: 'Pipeline definition name',
|
||
},
|
||
projectName: {
|
||
type: 'string',
|
||
description: 'Azure DevOps project name',
|
||
},
|
||
branch: {
|
||
type: 'string',
|
||
description: 'Source branch name (refs/heads/ prefix stripped)',
|
||
},
|
||
commitSha: {
|
||
type: 'string',
|
||
description: 'Source commit SHA',
|
||
},
|
||
triggeredBy: {
|
||
type: 'string',
|
||
description: 'Display name of the person who triggered the build',
|
||
},
|
||
triggeredByEmail: {
|
||
type: 'string',
|
||
description: 'Email/unique name of the person who triggered the build, or null if not set',
|
||
},
|
||
startTime: {
|
||
type: 'string',
|
||
description: 'Build start time (ISO 8601)',
|
||
},
|
||
finishTime: {
|
||
type: 'string',
|
||
description: 'Build finish time (ISO 8601)',
|
||
},
|
||
buildUrl: {
|
||
type: 'string',
|
||
description: 'API URL for the build resource',
|
||
},
|
||
}
|
||
}
|
||
|
||
export function buildWorkItemCreatedOutputs(): Record<string, TriggerOutput> {
|
||
return {
|
||
workItemId: {
|
||
type: 'number',
|
||
description: 'Work item ID',
|
||
},
|
||
workItemType: {
|
||
type: 'string',
|
||
description: 'Work item type for Basic process (e.g. Issue, Task, Epic)',
|
||
},
|
||
title: {
|
||
type: 'string',
|
||
description: 'Work item title',
|
||
},
|
||
state: {
|
||
type: 'string',
|
||
description: 'Work item state for Basic process (e.g. To Do, Doing, Done)',
|
||
},
|
||
createdBy: {
|
||
type: 'string',
|
||
description: 'Display name of the creator, or null if not set',
|
||
},
|
||
assignedTo: {
|
||
type: 'string',
|
||
description: 'Assignee display name, or null if unassigned',
|
||
},
|
||
priority: {
|
||
type: 'number',
|
||
description: 'Priority (1–4), or 0 if not set',
|
||
},
|
||
areaPath: {
|
||
type: 'string',
|
||
description: 'Area path',
|
||
},
|
||
iterationPath: {
|
||
type: 'string',
|
||
description: 'Iteration path',
|
||
},
|
||
description: {
|
||
type: 'string',
|
||
description: 'Work item description (HTML), or null if not set',
|
||
},
|
||
projectName: {
|
||
type: 'string',
|
||
description: 'Azure DevOps project name',
|
||
},
|
||
workItemUrl: {
|
||
type: 'string',
|
||
description: 'API URL for the work item resource',
|
||
},
|
||
}
|
||
}
|
||
|
||
export function buildWebhookOutputs(): Record<string, TriggerOutput> {
|
||
return {
|
||
eventType: {
|
||
type: 'string',
|
||
description: 'Service hook event type (e.g. build.complete, workitem.created)',
|
||
},
|
||
notificationId: {
|
||
type: 'number',
|
||
description: 'Notification ID',
|
||
},
|
||
subscriptionId: {
|
||
type: 'string',
|
||
description: 'Service hook subscription ID',
|
||
},
|
||
publisherId: {
|
||
type: 'string',
|
||
description: 'Publisher ID (e.g. tfs)',
|
||
},
|
||
createdDate: {
|
||
type: 'string',
|
||
description: 'Event creation time (ISO 8601)',
|
||
},
|
||
resource: {
|
||
type: 'json',
|
||
description: 'Event resource payload',
|
||
},
|
||
resourceContainers: {
|
||
type: 'json',
|
||
description: 'Resource container references (project, collection, etc.)',
|
||
},
|
||
message: {
|
||
type: 'json',
|
||
description: 'Short message object',
|
||
},
|
||
detailedMessage: {
|
||
type: 'json',
|
||
description: 'Detailed message object',
|
||
},
|
||
}
|
||
}
|
||
|
||
export function formatBuildCompleteInput(body: Record<string, unknown>): Record<string, unknown> {
|
||
const resource = (body.resource ?? {}) as Record<string, unknown>
|
||
const definition = (resource.definition ?? {}) as Record<string, unknown>
|
||
const project = (resource.project ?? {}) as Record<string, unknown>
|
||
const requestedFor = (resource.requestedFor ?? {}) as Record<string, unknown>
|
||
const sourceBranch = (resource.sourceBranch as string) ?? ''
|
||
|
||
return {
|
||
buildId: Number(resource.id ?? 0),
|
||
buildNumber: (resource.buildNumber as string) ?? '',
|
||
result: (resource.result as string) ?? '',
|
||
pipelineId: Number(definition.id ?? 0),
|
||
pipelineName: (definition.name as string) ?? '',
|
||
projectName: (project.name as string) ?? '',
|
||
branch: sourceBranch.replace(/^refs\/heads\//, ''),
|
||
commitSha: (resource.sourceVersion as string) ?? '',
|
||
triggeredBy: (requestedFor.displayName as string) ?? null,
|
||
triggeredByEmail: (requestedFor.uniqueName as string) ?? null,
|
||
startTime: (resource.startTime as string) ?? '',
|
||
finishTime: (resource.finishTime as string) ?? '',
|
||
buildUrl: (resource.url as string) ?? '',
|
||
}
|
||
}
|
||
|
||
export function formatWorkItemCreatedInput(body: Record<string, unknown>): Record<string, unknown> {
|
||
const resource = (body.resource ?? {}) as Record<string, unknown>
|
||
const fields = (resource.fields ?? {}) as Record<string, unknown>
|
||
|
||
return {
|
||
workItemId: Number(resource.id ?? 0),
|
||
workItemType: (fields['System.WorkItemType'] as string) ?? '',
|
||
title: (fields['System.Title'] as string) ?? '',
|
||
state: (fields['System.State'] as string) ?? '',
|
||
createdBy:
|
||
(fields['System.CreatedBy'] as { displayName?: string } | undefined)?.displayName ?? null,
|
||
assignedTo:
|
||
(fields['System.AssignedTo'] as { displayName?: string } | undefined)?.displayName ?? null,
|
||
priority: Number(fields['Microsoft.VSTS.Common.Priority'] ?? 0),
|
||
areaPath: (fields['System.AreaPath'] as string) ?? '',
|
||
iterationPath: (fields['System.IterationPath'] as string) ?? '',
|
||
description: (fields['System.Description'] as string) ?? null,
|
||
projectName: (fields['System.TeamProject'] as string) ?? '',
|
||
workItemUrl: (resource.url as string) ?? '',
|
||
}
|
||
}
|
||
|
||
export function formatWebhookEnvelopeInput(body: Record<string, unknown>): Record<string, unknown> {
|
||
return {
|
||
eventType: (body.eventType as string) ?? '',
|
||
notificationId: Number(body.notificationId ?? 0),
|
||
subscriptionId: (body.subscriptionId as string) ?? '',
|
||
publisherId: (body.publisherId as string) ?? '',
|
||
createdDate: (body.createdDate as string) ?? '',
|
||
resource: body.resource ?? null,
|
||
resourceContainers: body.resourceContainers ?? null,
|
||
message: body.message ?? null,
|
||
detailedMessage: body.detailedMessage ?? null,
|
||
}
|
||
}
|