[docs] Sync docs deploy with npm deploy (#3153)
This PR makes it so that our docs deployment process is tied to, and mirrors, the npm deployment process. From here on: - Commits to main get deployed to staging.tldraw.dev - Commits to a special protected branch called `docs-production` get deployed to www.tldraw.dev - Whenever we create a new npm 'latest' release we reset the HEAD of docs-production to point to the tagged commit for that release. - If we make a docs change that we want to appear on tldraw.dev ASAP without waiting for the next npm release, we'll have to follow the same process as for creating a patch release i.e merge a cherry-pick PR targeting the latest release branch e.g. `v2.0.x`. This will not cause another npm patch release unless the cherry-picked changes touch source files, e.g. updating TSDoc comments. ### Change Type - [x] `docs` — Changes to the documentation, examples, or templates. - [x] `tools` — Changes to infrastructure, CI, internal scripts, debugging tools, etc.
This commit is contained in:
parent
4d8dab843e
commit
44a3ea7363
6 changed files with 137 additions and 14 deletions
84
scripts/lib/didAnyPackageChange.ts
Normal file
84
scripts/lib/didAnyPackageChange.ts
Normal file
|
@ -0,0 +1,84 @@
|
|||
import { writeFileSync } from 'fs'
|
||||
import tar from 'tar'
|
||||
import tmp from 'tmp'
|
||||
import { exec } from './exec'
|
||||
import { PackageDetails, getAllPackageDetails } from './publishing'
|
||||
|
||||
async function hasPackageChanged(pkg: PackageDetails) {
|
||||
const dir = tmp.dirSync({ unsafeCleanup: true })
|
||||
const dirPath = dir.name
|
||||
try {
|
||||
const version = pkg.version
|
||||
|
||||
const unscopedName = pkg.name.replace('@tldraw/', '')
|
||||
const url = `https://registry.npmjs.org/${pkg.name}/-/${unscopedName}-${version}.tgz`
|
||||
const res = await fetch(url)
|
||||
if (res.status >= 400) {
|
||||
throw new Error(`Package not found at url ${url}: ${res.status}`)
|
||||
}
|
||||
const publishedTarballPath = `${dirPath}/published-package.tgz`
|
||||
writeFileSync(publishedTarballPath, Buffer.from(await res.arrayBuffer()))
|
||||
const publishedManifest = await getTarballManifest(publishedTarballPath)
|
||||
|
||||
const localTarballPath = `${dirPath}/local-package.tgz`
|
||||
await exec('yarn', ['pack', '--out', localTarballPath], { pwd: pkg.dir })
|
||||
|
||||
const localManifest = await getTarballManifest(localTarballPath)
|
||||
|
||||
return !manifestsAreEqual(publishedManifest, localManifest)
|
||||
} finally {
|
||||
dir.removeCallback()
|
||||
}
|
||||
}
|
||||
|
||||
function manifestsAreEqual(a: Record<string, Buffer>, b: Record<string, Buffer>) {
|
||||
const aKeys = Object.keys(a)
|
||||
const bKeys = Object.keys(b)
|
||||
if (aKeys.length !== bKeys.length) {
|
||||
return false
|
||||
}
|
||||
for (const key of aKeys) {
|
||||
if (!bKeys.includes(key)) {
|
||||
return false
|
||||
}
|
||||
if (!a[key].equals(b[key])) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
function getTarballManifest(tarballPath: string): Promise<Record<string, Buffer>> {
|
||||
const manifest: Record<string, Buffer> = {}
|
||||
return new Promise((resolve, reject) =>
|
||||
tar.list(
|
||||
{
|
||||
// @ts-expect-error bad typings
|
||||
file: tarballPath,
|
||||
onentry: (entry) => {
|
||||
entry.on('data', (data) => {
|
||||
// we could hash these to reduce memory but it's probably fine
|
||||
manifest[entry.path] = data
|
||||
})
|
||||
},
|
||||
},
|
||||
(err: any) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
resolve(manifest)
|
||||
}
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export async function didAnyPackageChange() {
|
||||
const details = getAllPackageDetails()
|
||||
for (const pkg of Object.values(details)) {
|
||||
if (await hasPackageChanged(pkg)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
|
@ -32,7 +32,7 @@
|
|||
"@aws-sdk/lib-storage": "^3.440.0",
|
||||
"@types/is-ci": "^3.0.0",
|
||||
"@types/node": "~20.11",
|
||||
"@types/tar": "^6.1.7",
|
||||
"@types/tar": "^6.1.11",
|
||||
"@typescript-eslint/utils": "^5.59.0",
|
||||
"ast-types": "^0.14.2",
|
||||
"cross-fetch": "^3.1.5",
|
||||
|
@ -56,8 +56,10 @@
|
|||
"dependencies": {
|
||||
"@octokit/rest": "^20.0.2",
|
||||
"@types/minimist": "^1.2.5",
|
||||
"@types/tmp": "^0.2.6",
|
||||
"ignore": "^5.2.4",
|
||||
"minimist": "^1.2.8",
|
||||
"tar": "^6.2.0"
|
||||
"tar": "^6.2.0",
|
||||
"tmp": "^0.2.3"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -125,6 +125,7 @@ async function main() {
|
|||
if (!isPrerelease) {
|
||||
const { major, minor } = parse(nextVersion)!
|
||||
await exec('git', ['push', 'origin', `${gitTag}:refs/heads/v${major}.${minor}.x`])
|
||||
await exec('git', ['push', 'origin', `${gitTag}:docs-production`, `--force`])
|
||||
}
|
||||
|
||||
// create a release on github
|
||||
|
|
|
@ -3,6 +3,7 @@ import fetch from 'cross-fetch'
|
|||
import glob from 'glob'
|
||||
import { assert } from 'node:console'
|
||||
import { appendFileSync } from 'node:fs'
|
||||
import { didAnyPackageChange } from './lib/didAnyPackageChange'
|
||||
import { exec } from './lib/exec'
|
||||
import { generateAutoRcFile } from './lib/labels'
|
||||
import { nicelog } from './lib/nicelog'
|
||||
|
@ -41,6 +42,17 @@ async function main() {
|
|||
return
|
||||
}
|
||||
|
||||
if (isLatestVersion) {
|
||||
await exec('git', ['push', 'origin', `HEAD:docs-production`, '--force'])
|
||||
}
|
||||
|
||||
// Skip releasing a new version if the package contents are identical.
|
||||
// This may happen when cherry-picking docs-only changes.
|
||||
if (!(await didAnyPackageChange())) {
|
||||
nicelog('No packages have changed, skipping release')
|
||||
return
|
||||
}
|
||||
|
||||
nicelog('Releasing version', nextVersion)
|
||||
|
||||
await setAllVersions(nextVersion)
|
||||
|
|
17
scripts/vercel/should-build-docs.sh
Executable file
17
scripts/vercel/should-build-docs.sh
Executable file
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env bash
|
||||
set -eux
|
||||
|
||||
if [[ "$VERCEL_ENV" == "production" ]] ; then
|
||||
echo "Always build on production";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
## main is not production anymore, but we still always want to build it
|
||||
if [[ "$VERCEL_GIT_COMMIT_REF" == "main" ]] ; then
|
||||
echo "Always build on main";
|
||||
exit 1;
|
||||
fi
|
||||
|
||||
## on PR builds, only rebuild if the docs directory changed
|
||||
git diff HEAD^ HEAD --quiet ./apps/docs
|
||||
|
31
yarn.lock
31
yarn.lock
|
@ -7351,7 +7351,8 @@ __metadata:
|
|||
"@types/is-ci": "npm:^3.0.0"
|
||||
"@types/minimist": "npm:^1.2.5"
|
||||
"@types/node": "npm:~20.11"
|
||||
"@types/tar": "npm:^6.1.7"
|
||||
"@types/tar": "npm:^6.1.11"
|
||||
"@types/tmp": "npm:^0.2.6"
|
||||
"@typescript-eslint/utils": "npm:^5.59.0"
|
||||
ast-types: "npm:^0.14.2"
|
||||
cross-fetch: "npm:^3.1.5"
|
||||
|
@ -7370,6 +7371,7 @@ __metadata:
|
|||
semver: "npm:^7.3.8"
|
||||
svgo: "npm:^3.0.2"
|
||||
tar: "npm:^6.2.0"
|
||||
tmp: "npm:^0.2.3"
|
||||
typescript: "npm:^5.3.3"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
|
@ -8212,13 +8214,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/tar@npm:^6.1.7":
|
||||
version: 6.1.10
|
||||
resolution: "@types/tar@npm:6.1.10"
|
||||
"@types/tar@npm:^6.1.11":
|
||||
version: 6.1.11
|
||||
resolution: "@types/tar@npm:6.1.11"
|
||||
dependencies:
|
||||
"@types/node": "npm:*"
|
||||
minipass: "npm:^4.0.0"
|
||||
checksum: da525415a9bac9e81a1498d0b684dd7fa34f69a8568b54ab19660e99d5e7dcdeb2527a40059e1cfc697fe4bbcc18cd03a50c96356d84ab865345c2c48a9d88f6
|
||||
checksum: 0d54b8acbd7d2fc43bd1097eef5058604a6b0e3a394cf485038303ca3ef39ecb42451c7dc5a2b9b18420e137ef5b2c76ec504e94c2f45010b2c8e8c3a49d9de7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
@ -8231,6 +8233,13 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/tmp@npm:^0.2.6":
|
||||
version: 0.2.6
|
||||
resolution: "@types/tmp@npm:0.2.6"
|
||||
checksum: e14a094c10569d3b56805552b21417860ef21060d969000d5d5b53604a78c2bdac216f064b03797d4b07a081e0141dd3ab22bc36923e75300eb1c023f7252cc7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/tough-cookie@npm:*":
|
||||
version: 4.0.5
|
||||
resolution: "@types/tough-cookie@npm:4.0.5"
|
||||
|
@ -21513,7 +21522,7 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"rimraf@npm:^3.0.0, rimraf@npm:^3.0.2":
|
||||
"rimraf@npm:^3.0.2":
|
||||
version: 3.0.2
|
||||
resolution: "rimraf@npm:3.0.2"
|
||||
dependencies:
|
||||
|
@ -23015,12 +23024,10 @@ __metadata:
|
|||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"tmp@npm:^0.2.1":
|
||||
version: 0.2.1
|
||||
resolution: "tmp@npm:0.2.1"
|
||||
dependencies:
|
||||
rimraf: "npm:^3.0.0"
|
||||
checksum: 445148d72df3ce99356bc89a7857a0c5c3b32958697a14e50952c6f7cf0a8016e746ababe9a74c1aa52f04c526661992f14659eba34d3c6701d49ba2f3cf781b
|
||||
"tmp@npm:^0.2.1, tmp@npm:^0.2.3":
|
||||
version: 0.2.3
|
||||
resolution: "tmp@npm:0.2.3"
|
||||
checksum: 7b13696787f159c9754793a83aa79a24f1522d47b87462ddb57c18ee93ff26c74cbb2b8d9138f571d2e0e765c728fb2739863a672b280528512c6d83d511c6fa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
|
Loading…
Reference in a new issue