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

This commit is contained in:
upstream-mirror
2026-09-23 16:12:52 +05:00
commit a774ac673a
4541 changed files with 770499 additions and 0 deletions

View File

@@ -0,0 +1,143 @@
import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from 'fs'
import path from 'path'
import { parse } from 'semver'
import { exec } from './lib/exec'
import { makeEnv } from './lib/makeEnv'
import { nicelog } from './lib/nicelog'
// VSCE_PAT needs to be set. It is used by the vsce publish command.
// OVSX_PAT needs to be set for Open VSX publishing (handled by publish script).
const env = makeEnv(['VSCE_PAT', 'OVSX_PAT', 'TLDRAW_ENV'])
const EXTENSION_DIR = 'apps/vscode/extension'
const DISTRIBUTION_DIR = 'apps/vscode/extension/release'
const MAX_VERSION_CONFLICT_ATTEMPTS = 5
const VERSION_CONFLICT_RETRY_DELAY_MS = 30_000
function isVersionConflictError(err: unknown): boolean {
const message = err instanceof Error ? err.message : ''
const stderr = typeof (err as any)?.stderr === 'string' ? (err as any).stderr : ''
return message.includes('already exists') || stderr.includes('already exists')
}
async function fetchMarketplaceVersion(): Promise<string> {
await exec('yarn', ['get-info'], { pwd: EXTENSION_DIR })
const extensionInfoJsonPath = path.join(EXTENSION_DIR, 'extension.json')
if (!existsSync(extensionInfoJsonPath)) {
throw new Error('Published extension info not found.')
}
const extensionInfoJson = JSON.parse(readFileSync(extensionInfoJsonPath, 'utf8'))
const version = extensionInfoJson.versions[0].version
if (!version) {
throw new Error('Could not get the version of the published extension.')
}
return version
}
async function bumpVersion(fromVersion?: string): Promise<string> {
const currentVersion = fromVersion ?? (await fetchMarketplaceVersion())
const semVer = parse(currentVersion)
if (!semVer) {
throw new Error(`Could not parse the published version: ${currentVersion}`)
}
const release = env.TLDRAW_ENV === 'production' ? 'minor' : 'patch'
const nextVersion = semVer.inc(release).version
nicelog(`Bumping extension version from ${currentVersion} to ${nextVersion}`)
const packageJsonPath = path.join(EXTENSION_DIR, 'package.json')
if (!existsSync(packageJsonPath)) {
throw new Error("Could not find the extension's package.json file.")
}
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
packageJson.version = nextVersion
writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, '\t') + '\n')
return nextVersion
}
async function copyExtensionToReleaseFolder(version: string) {
if (!existsSync(DISTRIBUTION_DIR)) {
mkdirSync(DISTRIBUTION_DIR, { recursive: true })
}
const tempDir = path.join(EXTENSION_DIR, 'temp')
if (!existsSync(tempDir)) {
throw new Error(
'Extension temp directory not found. Make sure packaging completed successfully.'
)
}
const files = readdirSync(tempDir)
const vsixFile = files.find((file: string) => file.endsWith('.vsix'))
if (!vsixFile) {
throw new Error('No .vsix file found in temp directory.')
}
const sourcePath = path.join(tempDir, vsixFile)
const targetPath = path.join(DISTRIBUTION_DIR, 'tldraw-vscode.vsix')
nicelog(`Copying extension from ${sourcePath} to ${targetPath}`)
copyFileSync(sourcePath, targetPath)
nicelog('Setting git user identity...')
await exec('git', ['config', 'user.name', 'huppy-bot[bot]'])
await exec('git', ['config', 'user.email', '128400622+huppy-bot[bot]@users.noreply.github.com'])
nicelog('Committing extension to git...')
await exec('git', ['add', '-f', targetPath])
await exec('git', ['commit', '-m', `Add VSCode extension v${version} [skip ci]`])
nicelog('Pushing changes to remote repository...')
await exec('git', ['push'])
}
async function main() {
if (env.TLDRAW_ENV !== 'production' && env.TLDRAW_ENV !== 'staging') {
throw new Error('Workflow triggered from a branch other than main or production.')
}
await exec('yarn', ['lazy', 'run', 'build', '--filter=packages/*'])
// When two pushes to main happen in quick succession, the concurrency group serializes
// the runs but `vsce show` can lag a fresh publish by 10+ minutes, so both runs compute
// the same next version. The "already exists" rejection is authoritative, so on conflict
// bump past the rejected version locally instead of re-fetching the stale listing.
let conflictedVersion: string | undefined
for (let attempt = 1; attempt <= MAX_VERSION_CONFLICT_ATTEMPTS; attempt++) {
const version = await bumpVersion(conflictedVersion)
try {
switch (env.TLDRAW_ENV) {
case 'production':
await exec('yarn', ['package'], { pwd: EXTENSION_DIR })
await exec('yarn', ['publish'], { pwd: EXTENSION_DIR })
await copyExtensionToReleaseFolder(version)
return
case 'staging':
await exec('yarn', ['package', '--pre-release'], { pwd: EXTENSION_DIR })
await exec('yarn', ['publish', '--pre-release'], { pwd: EXTENSION_DIR })
return
}
} catch (err) {
// Exit code 75 from the publish script means an earlier upload may have succeeded.
if ((err as { code?: number })?.code === 75) {
throw new Error(
`Publishing version ${version} stopped because an earlier Marketplace upload may have succeeded. Open VSX has not been attempted. Check Marketplace and complete this release at the same version; do not rerun the workflow blindly, as it computes a new version.`,
{ cause: err }
)
}
if (isVersionConflictError(err) && attempt < MAX_VERSION_CONFLICT_ATTEMPTS) {
conflictedVersion = version
nicelog(
`Version ${version} already exists (attempt ${attempt}/${MAX_VERSION_CONFLICT_ATTEMPTS}), bumping past it and retrying in ${VERSION_CONFLICT_RETRY_DELAY_MS / 1000}s...`
)
await new Promise((resolve) => setTimeout(resolve, VERSION_CONFLICT_RETRY_DELAY_MS))
continue
}
throw err
}
}
}
main().catch(async (err) => {
console.error(err)
process.exit(1)
})