snapshot of https://github.com/tldraw/tldraw.git (main, 2026-09-23; blobs > 131072B omitted)
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
Some checks failed
Deploy analytics worker / Deploy analytics worker to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
i18n upload strings / Upload latest strings (push) Failing after 1s
Deploy bemo / Deploy bemo to ${{ (github.ref == 'refs/heads/bemo-production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Failing after 1s
Deploy grafana resources / ${{ github.event_name == 'push' && 'Deploy grafana resources' || 'Validate grafana resources (dry run)' }} (push) Failing after 0s
End to end tests (dotcom) / Check for relevant changes (push) Failing after 0s
End to end tests (examples) / Check for relevant changes (push) Failing after 0s
End to end tests (mermaid readability) / Check for relevant changes (push) Failing after 1s
End to end tests (perf) / Check for relevant changes (push) Failing after 0s
Publish editor extensions / Publish editor extensions (push) Failing after 1s
Publish SDK packages / Remove the publish-packages label (push) Has been skipped
Checks / Tests & checks (push) Has been cancelled
Checks / Build all projects (push) Has been cancelled
Deploy templates / Deploy templates (push) Has been cancelled
End to end tests (dotcom) / End to end tests (dotcom) (push) Has been cancelled
End to end tests (mermaid readability) / End to end tests (mermaid readability) (push) Has been cancelled
End to end tests (perf) / End to end tests (perf) (push) Has been cancelled
Deploy .com / Deploy dotcom to ${{ (github.ref == 'refs/heads/production' && 'production') || (github.ref == 'refs/heads/main' && 'staging') || 'preview' }} (push) Has been cancelled
End to end tests (examples) / End to end tests (examples) (push) Has been cancelled
Publish SDK packages / Publish SDK packages (push) Has been cancelled
Publish SDK packages / Tell user released version (push) Has been cancelled
Publish SDK packages / Publishes code templates to separate repositories (push) Has been cancelled
Publish SDK packages / Deploys the template demos with the new SDK version (push) Has been cancelled
This commit is contained in:
217
internal/scripts/lib/deploy.ts
Normal file
217
internal/scripts/lib/deploy.ts
Normal file
@@ -0,0 +1,217 @@
|
||||
import { readFileSync, writeFileSync } from 'fs'
|
||||
import { join } from 'path'
|
||||
import * as github from '@actions/github'
|
||||
import { exec } from './exec'
|
||||
|
||||
export function getDeployInfo() {
|
||||
const githubPrNumber = process.env.GITHUB_REF?.match(/refs\/pull\/(\d+)\/merge/)?.[1]
|
||||
|
||||
let previewId = process.env.TLDRAW_PREVIEW_ID
|
||||
if (!previewId && process.env.TLDRAW_ENV === 'preview') {
|
||||
if (githubPrNumber) {
|
||||
previewId = `pr-${githubPrNumber}`
|
||||
} else {
|
||||
throw new Error(
|
||||
'If running preview deploys from outside of a PR action, TLDRAW_PREVIEW_ID env var must be set'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const sha: string | undefined =
|
||||
// if the event is 'pull_request', github.context.sha is an ephemeral merge commit
|
||||
// while the actual commit we want to create the deployment for is the 'head' of the PR.
|
||||
github.context.eventName === 'pull_request'
|
||||
? github.context.payload.pull_request?.head.sha
|
||||
: github.context.sha
|
||||
|
||||
if (!sha) {
|
||||
throw new Error('Could not determine the SHA of the commit to deploy')
|
||||
}
|
||||
|
||||
return {
|
||||
githubPrNumber,
|
||||
previewId,
|
||||
sha,
|
||||
}
|
||||
}
|
||||
|
||||
// Creates a github 'deployment', which creates a 'View Deployment' button in the PR timeline.
|
||||
export async function createGithubDeployment(
|
||||
env: { GH_TOKEN: string; TLDRAW_ENV: string },
|
||||
{
|
||||
app,
|
||||
deploymentUrl,
|
||||
inspectUrl,
|
||||
sha,
|
||||
}: { app: string; deploymentUrl: string; inspectUrl?: string; sha: string }
|
||||
) {
|
||||
const client = github.getOctokit(env.GH_TOKEN)
|
||||
|
||||
const deployment = await client.rest.repos.createDeployment({
|
||||
owner: 'tldraw',
|
||||
repo: 'tldraw',
|
||||
ref: sha,
|
||||
payload: { web_url: deploymentUrl },
|
||||
environment: `${app}-${env.TLDRAW_ENV}`,
|
||||
transient_environment: env.TLDRAW_ENV === 'preview',
|
||||
production_environment: env.TLDRAW_ENV === 'production',
|
||||
required_contexts: [],
|
||||
auto_merge: false,
|
||||
task: 'deploy',
|
||||
})
|
||||
|
||||
await client.rest.repos.createDeploymentStatus({
|
||||
owner: 'tldraw',
|
||||
repo: 'tldraw',
|
||||
deployment_id: (deployment.data as any).id,
|
||||
state: 'success',
|
||||
environment_url: deploymentUrl,
|
||||
log_url: inspectUrl,
|
||||
})
|
||||
}
|
||||
|
||||
/** Deploy a worker to wrangler, returning the deploy ID */
|
||||
export async function wranglerDeploy({
|
||||
location,
|
||||
dryRun,
|
||||
env,
|
||||
vars,
|
||||
sentry,
|
||||
}: {
|
||||
location: string
|
||||
dryRun: boolean
|
||||
env: string
|
||||
vars: Record<string, string>
|
||||
sentry?: {
|
||||
authToken: string
|
||||
project: string
|
||||
environment?: string
|
||||
}
|
||||
}) {
|
||||
const varsArray = []
|
||||
for (const [key, value] of Object.entries(vars)) {
|
||||
varsArray.push('--var', `${key}:${value}`)
|
||||
}
|
||||
|
||||
const out = await exec(
|
||||
'yarn',
|
||||
[
|
||||
'wrangler',
|
||||
'deploy',
|
||||
dryRun ? '--dry-run' : null,
|
||||
'--env',
|
||||
env,
|
||||
'--outdir',
|
||||
'.wrangler/dist',
|
||||
...varsArray,
|
||||
],
|
||||
{
|
||||
pwd: location,
|
||||
env: {
|
||||
NODE_ENV: 'production',
|
||||
// wrangler needs CI=1 set to prevent it from trying to do interactive prompts
|
||||
CI: '1',
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
if (dryRun) return
|
||||
|
||||
const versionMatch = out.match(/Current Version ID: (.+)/)
|
||||
if (!versionMatch) {
|
||||
throw new Error('Could not find the deploy ID in wrangler output')
|
||||
}
|
||||
|
||||
const workerNameMatch = out.match(/Uploaded ([^ ]+)/)
|
||||
|
||||
if (!workerNameMatch) {
|
||||
throw new Error('Could not find the worker name in wrangler output')
|
||||
}
|
||||
|
||||
if (sentry) {
|
||||
const release = `${sentry.environment ?? workerNameMatch[1]}.${versionMatch[1]}`
|
||||
|
||||
const sentryEnv = {
|
||||
SENTRY_AUTH_TOKEN: sentry.authToken,
|
||||
SENTRY_ORG: 'tldraw',
|
||||
SENTRY_PROJECT: sentry.project,
|
||||
}
|
||||
|
||||
// create a sentry release:
|
||||
await exec('yarn', ['run', '-T', 'sentry-cli', 'releases', 'new', release], {
|
||||
pwd: location,
|
||||
env: sentryEnv,
|
||||
})
|
||||
|
||||
// upload sourcemaps to the release:
|
||||
await exec(
|
||||
'yarn',
|
||||
[
|
||||
'run',
|
||||
'-T',
|
||||
'sentry-cli',
|
||||
'releases',
|
||||
'files',
|
||||
release,
|
||||
'upload-sourcemaps',
|
||||
'.wrangler/dist',
|
||||
],
|
||||
{
|
||||
pwd: location,
|
||||
env: sentryEnv,
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export interface ServiceBinding {
|
||||
binding: string
|
||||
service: string
|
||||
}
|
||||
|
||||
export async function setWranglerPreviewConfig(
|
||||
location: string,
|
||||
{
|
||||
name,
|
||||
routeHostname,
|
||||
serviceBinding,
|
||||
}: { name: string; routeHostname?: string; serviceBinding?: ServiceBinding },
|
||||
queueName?: string
|
||||
) {
|
||||
// A zone route instead of a custom domain: custom domains mint a dedicated
|
||||
// certificate pack per hostname, while routes are covered by the zone's
|
||||
// universal wildcard cert and the existing proxied *.tldraw.xyz DNS record.
|
||||
const zoneName = routeHostname?.split('.').slice(-2).join('.')
|
||||
const additionalProperties = `name = "${name}"
|
||||
${routeHostname ? `routes = [ { pattern = "${routeHostname}/*", zone_name = "${zoneName}" } ]` : ''}
|
||||
${serviceBinding ? `services = [ {binding = "${serviceBinding.binding}", service = "${serviceBinding.service}" } ]` : ''}`
|
||||
|
||||
const envPreviewSection = `\n[env.preview]\n${additionalProperties}\n`
|
||||
|
||||
const path = join(location, 'wrangler.toml')
|
||||
let data = readFileSync(path).toString()
|
||||
|
||||
// Replace the entire [env.preview] section including all its properties
|
||||
// Match from [env.preview] to the next section or end of file
|
||||
const previewSectionRegex = /\n\[env\.preview\]\n(?:[^[](?:[^\n]*\n)*)?/
|
||||
|
||||
if (previewSectionRegex.test(data)) {
|
||||
data = data.replace(previewSectionRegex, envPreviewSection)
|
||||
} else {
|
||||
data += envPreviewSection
|
||||
}
|
||||
|
||||
if (queueName) {
|
||||
const envPreviewQueuesSection = `\n[[env.preview.queues.producers]]
|
||||
queue = "${queueName}"
|
||||
binding = "QUEUE"
|
||||
|
||||
[[env.preview.queues.consumers]]
|
||||
queue = "${queueName}"
|
||||
max_retries =10
|
||||
`
|
||||
data += envPreviewQueuesSection
|
||||
}
|
||||
|
||||
writeFileSync(path, data)
|
||||
}
|
||||
Reference in New Issue
Block a user