Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
*.res linguist-language=ReScript
*.resi linguist-language=ReScript

/public/playground-bundles/** binary linguist-vendored
/apps/docs/public/playground-bundles/** binary linguist-vendored
10 changes: 7 additions & 3 deletions .github/scripts/deployment-environment.sh
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
#!/usr/bin/env bash
set -euo pipefail

# Export the canonical production URL or the branch-specific Pages preview URL
# for later GitHub Actions steps.
if [[ "$RAW_BRANCH" == "master" ]]; then
# Pages selects production by branch. Manual previews of master must use a
# preview alias, while a manual production deploy must explicitly target master.
if [[ "${GITHUB_EVENT_NAME:-}" == "push" && "$RAW_BRANCH" == "master" ]] ||
[[ "${GITHUB_EVENT_NAME:-}" == "workflow_dispatch" && "${DEPLOY_ENVIRONMENT:-}" == "production" ]]; then
{
echo "SAFE_BRANCH=master"
echo "DOCS_DEPLOYMENT_ENVIRONMENT=production"
echo "VITE_DEPLOYMENT_URL="
echo "DOCS_DEPLOYMENT_URL=https://rescript-lang.org"
} >> "$GITHUB_ENV"
Expand All @@ -19,6 +22,7 @@ else
SAFE_BRANCH="${BRANCH_PREFIX}-${BRANCH_DIGEST}"
{
echo "SAFE_BRANCH=$SAFE_BRANCH"
echo "DOCS_DEPLOYMENT_ENVIRONMENT=preview"
echo "VITE_DEPLOYMENT_URL=https://${SAFE_BRANCH}.rescript-lang.pages.dev"
echo "DOCS_DEPLOYMENT_URL=https://${SAFE_BRANCH}.rescript-lang.pages.dev"
} >> "$GITHUB_ENV"
Expand Down
6 changes: 4 additions & 2 deletions .github/scripts/lighthouse-environment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ REPOSITORY_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)

if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
RAW_TARGET_BRANCH=$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}" --jq '.base.ref')
TARGET_ENVIRONMENT=""
else
RAW_TARGET_BRANCH="$RAW_BRANCH"
TARGET_ENVIRONMENT="${DOCS_DEPLOYMENT_ENVIRONMENT:-}"
fi

ARTIFACT_NAME=$(node "$REPOSITORY_ROOT/apps/docs/scripts/lighthouse-report.mjs" artifact-name "$RAW_BRANCH")
TARGET_ARTIFACT_NAME=$(node "$REPOSITORY_ROOT/apps/docs/scripts/lighthouse-report.mjs" artifact-name "$RAW_TARGET_BRANCH")
ARTIFACT_NAME=$(node "$REPOSITORY_ROOT/apps/docs/scripts/lighthouse-report.mjs" artifact-name "$RAW_BRANCH" "${DOCS_DEPLOYMENT_ENVIRONMENT:-}")
TARGET_ARTIFACT_NAME=$(node "$REPOSITORY_ROOT/apps/docs/scripts/lighthouse-report.mjs" artifact-name "$RAW_TARGET_BRANCH" "$TARGET_ENVIRONMENT")

{
echo "LIGHTHOUSE_ARTIFACT_NAME=$ARTIFACT_NAME"
Expand Down
9 changes: 8 additions & 1 deletion .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ on:
workflow_dispatch:
inputs:
environment:
description: "Choose an environment to deploy to: <preview|production>"
description: "Deployment environment for docs and guide"
type: choice
options:
- preview
- production
required: true
default: "preview"
pull_request:
Expand Down Expand Up @@ -41,6 +45,7 @@ jobs:
- name: Set VITE_DEPLOYMENT_URL
env:
RAW_BRANCH: ${{ github.head_ref || github.ref_name }}
DEPLOY_ENVIRONMENT: ${{ inputs.environment }}
shell: bash
run: bash .github/scripts/deployment-environment.sh
- name: Build
Expand Down Expand Up @@ -93,6 +98,7 @@ jobs:
- name: Set deployment URL
env:
RAW_BRANCH: ${{ github.head_ref || github.ref_name }}
DEPLOY_ENVIRONMENT: ${{ inputs.environment }}
Comment thread
fhammerschmidt marked this conversation as resolved.
shell: bash
run: bash .github/scripts/deployment-environment.sh
- name: Set Lighthouse environment
Expand Down Expand Up @@ -250,6 +256,7 @@ jobs:
- name: Set deployment URL
env:
RAW_BRANCH: ${{ github.head_ref || github.ref_name }}
DEPLOY_ENVIRONMENT: ${{ inputs.environment }}
shell: bash
run: bash .github/scripts/deployment-environment.sh
- name: Cypress E2E tests
Expand Down
26 changes: 0 additions & 26 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
apps/docs/public/blog/feed.xml

node_modules/
.next/
out/
apps/docs/out/
index_data/*.json
Expand All @@ -28,15 +27,8 @@ apps/docs/lib/
apps/guide/lib/
packages/*/lib/

.vercel

apps/docs/src/**/*.mjs
apps/docs/src/**/*.jsx
apps/guide/src/**/*.mjs
apps/guide/src/**/*.jsx
packages/*/src/**/*.mjs
packages/*/src/**/*.jsx
apps/docs/scripts/generate_*.mjs
apps/docs/scripts/generate_*.jsx
apps/docs/scripts/LogAlgoliaEnvStatus.jsx
apps/docs/scripts/__tests__/**/*.jsx
Expand All @@ -48,38 +40,23 @@ apps/docs/public/llms/react/**/llm*.txt
apps/docs/markdown-pages/docs/**/**/llms.mdx

apps/docs/public/playground-bundles/
!apps/docs/public/_redirects

dist
build
apps/docs/dist
apps/docs/build
apps/guide/dist
apps/guide/build
.react-router
apps/docs/.react-router
apps/guide/.react-router
mdx-manifest.json
apps/docs/mdx-manifest.json

apps/docs/app/**/*.mjs
apps/docs/app/**/*.jsx
apps/guide/app/**/*.mjs
apps/guide/app/**/*.jsx
!apps/guide/app/root.jsx
!apps/guide/app/routes.jsx
apps/docs/functions/**/*.mjs
apps/docs/functions/**/*.jsx
apps/docs/__tests__/**/*.mjs
apps/docs/__tests__/**/*.jsx
apps/docs/test-utils/**/*.mjs
apps/docs/test-utils/**/*.jsx
apps/guide/__tests__/**/*.mjs
apps/guide/__tests__/**/*.jsx
apps/docs/e2e/**/*.mjs
apps/docs/e2e/**/*.jsx
!_shims.mjs
!_shims.jsx

# Yarn
.yarn/*
Expand All @@ -101,9 +78,6 @@ apps/docs/_scripts
.env.local
apps/docs/.env.local

# Local git worktrees
.worktrees

# Vitest screenshots
!apps/docs/__tests__/**/__screenshots__/**/*
.vitest-attachments
Expand Down
13 changes: 1 addition & 12 deletions .oxfmtrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,11 @@
"printWidth": 80,
"sortPackageJson": false,
"ignorePatterns": [
"!_shims.mjs",
"!apps/docs/public/_redirects",
".DS_Store",
".worktrees/",
".next/",
".react-router",
"*.swo",
"*.swp",
"apps/docs/app/**/*.mjs",
"apps/guide/app/**/*.jsx",
"build",
"data/api/**/*.json",
Expand All @@ -21,22 +17,15 @@
"apps/docs/out/",
"apps/docs/public/playground-bundles/",
"apps/docs/public/blog/feed.xml",
"_tempFile.cmi",
"_tempFile.cmj",
"_tempFile.cmt",
"_tempFile.res",
"temp",
".bsb.lock",
".merlin",
"lib/",
"apps/docs/lib/",
".vercel",
"apps/docs/src/**/*.mjs",
"apps/docs/scripts/generate_*.mjs",
"apps/docs/public/llms/manual/**/llm*.txt",
"apps/docs/public/llms/react/**/llm*.txt",
"apps/docs/markdown-pages/docs/**/**/llms.mdx",
"apps/docs/markdown-pages/docs/manual/installation.mdx",
".yarn/releases/yarn-4.12.0.cjs"
".yarn/releases/*.cjs"
]
}
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ clean:

.DEFAULT_GOAL := build

.PHONY: clean test
.PHONY: build dev clean test
2 changes: 1 addition & 1 deletion apps/docs/scripts/__tests__/LighthouseFixtures.res
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type commentInput = {
}

@module("../lighthouse-report.mjs")
external artifactName: string => string = "lighthouseArtifactName"
external artifactName: (string, ~environment: string=?) => string = "lighthouseArtifactName"
@module("../lighthouse-report.mjs") external median: array<float> => float = "median"
@module("../lighthouse-report.mjs")
external createBaseline: baselineInput => baseline = "createBaseline"
Expand Down
19 changes: 19 additions & 0 deletions apps/docs/scripts/__tests__/LighthouseReport_.test.res
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ test("artifact-name CLI prints the same key used by the report helper", async ()
expect(result.stdout)->toBe(`${artifactName("perf/fonts")}\n`)
})

for_([
("master", "preview"),
("perf/homepage", "production"),
])("artifact-name CLI separates %s baselines in %s", async ((branch, deploymentEnvironment)) => {
let state = await workspace()
let result = run(state, ["artifact-name", branch, deploymentEnvironment], ())
expectSuccess(result)
let artifact = artifactName(branch, ~environment=deploymentEnvironment)
expect(result.stdout)->toBe(`${artifact}\n`)
expect(artifact != artifactName(branch))->toBe(true)
})

test("artifact-name CLI rejects an invalid environment", async () => {
let state = await workspace()
let result = run(state, ["artifact-name", "master", "staging"], ())
expectStatus(result, 1)
expect(result.stderr)->toContain("Invalid Lighthouse deployment environment: staging")
})

for_([[], [""]])("artifact-name CLI rejects missing or empty branch %j", async arguments => {
let state = await workspace()
let result = run(state, ["artifact-name", ...arguments], ())
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/scripts/__tests__/LighthouseWorkflowFixtures.res
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ let fixture = async (~overrides=[], ()) => {
("CALLS", join([directory, "calls.jsonl"])),
("GITHUB_ENV", join([directory, "environment"])),
("GITHUB_EVENT_NAME", "pull_request"),
("DEPLOY_ENVIRONMENT", ""),
("DOCS_DEPLOYMENT_ENVIRONMENT", ""),
("GITHUB_REPOSITORY", "owner/site"),
("PR_NUMBER", "1355"),
("RAW_BRANCH", "Perf/Homepage"),
Expand Down
77 changes: 64 additions & 13 deletions apps/docs/scripts/__tests__/LighthouseWorkflow_.test.res
Original file line number Diff line number Diff line change
Expand Up @@ -28,23 +28,74 @@ test("production uses its own baseline without a PR lookup", async () => {
expect(exists(join([state.directory, "calls.jsonl"])))->toBe(false)
})

test("preview PR audits compare against the target branch's default environment", async () => {
let state = await Workflow.fixture(
~overrides=[("GH_RESPONSE", "master\n"), ("DOCS_DEPLOYMENT_ENVIRONMENT", "preview")],
(),
)
expectSuccess(Workflow.run("lighthouse-environment.sh", state))
let environment = await Workflow.environmentContents(state)
expect(environment)->toContain(
`LIGHTHOUSE_TARGET_ARTIFACT_NAME=${LighthouseFixtures.artifactName("master")}\n`,
)
expect(environment)->toContain("LIGHTHOUSE_TARGET_BRANCH=master\n")
})

let productionEnvironment = "SAFE_BRANCH=master\nDOCS_DEPLOYMENT_ENVIRONMENT=production\nVITE_DEPLOYMENT_URL=\nDOCS_DEPLOYMENT_URL=https://rescript-lang.org\n"
let homepagePreviewEnvironment = "SAFE_BRANCH=perf-homepage-19ab1c0e\nDOCS_DEPLOYMENT_ENVIRONMENT=preview\nVITE_DEPLOYMENT_URL=https://perf-homepage-19ab1c0e.rescript-lang.pages.dev\nDOCS_DEPLOYMENT_URL=https://perf-homepage-19ab1c0e.rescript-lang.pages.dev\n"
let masterPreviewEnvironment = "SAFE_BRANCH=master-fc613b4d\nDOCS_DEPLOYMENT_ENVIRONMENT=preview\nVITE_DEPLOYMENT_URL=https://master-fc613b4d.rescript-lang.pages.dev\nDOCS_DEPLOYMENT_URL=https://master-fc613b4d.rescript-lang.pages.dev\n"

for_([
("master", "VITE_DEPLOYMENT_URL=\n", "DOCS_DEPLOYMENT_URL=https://rescript-lang.org\n"),
(
"Perf/Homepage",
"VITE_DEPLOYMENT_URL=https://perf-homepage-19ab1c0e.rescript-lang.pages.dev\n",
"DOCS_DEPLOYMENT_URL=https://perf-homepage-19ab1c0e.rescript-lang.pages.dev\n",
),
])("deployment environment for %s does not depend on GitHub artifact access", async ((
("master", "preview"),
("Perf/Homepage", "production"),
])("manual Lighthouse baselines for %s in %s stay separate from the default environment", async ((
branch,
expectedViteUrl,
expectedDocsUrl,
deploymentEnvironment,
)) => {
let state = await Workflow.fixture(~overrides=[("RAW_BRANCH", branch), ("GH_FAIL", "1")], ())
expectSuccess(Workflow.run("deployment-environment.sh", state))
let state = await Workflow.fixture(
~overrides=[
("GITHUB_EVENT_NAME", "workflow_dispatch"),
("RAW_BRANCH", branch),
("DOCS_DEPLOYMENT_ENVIRONMENT", deploymentEnvironment),
("GH_FAIL", "1"),
],
(),
)
expectSuccess(Workflow.run("lighthouse-environment.sh", state))
let environment = await Workflow.environmentContents(state)
expect(environment)->toContain(expectedViteUrl)
expect(environment)->toContain(expectedDocsUrl)
let artifact = LighthouseFixtures.artifactName(branch, ~environment=deploymentEnvironment)
expect(artifact != LighthouseFixtures.artifactName(branch))->toBe(true)
expect(environment)->toContain(`LIGHTHOUSE_ARTIFACT_NAME=${artifact}\n`)
expect(environment)->toContain(`LIGHTHOUSE_TARGET_ARTIFACT_NAME=${artifact}\n`)
expect(environment)->toContain(`LIGHTHOUSE_BRANCH=${branch}\n`)
expect(exists(join([state.directory, "calls.jsonl"])))->toBe(false)
})

for_([
("push", "master", "", productionEnvironment),
("pull_request", "Perf/Homepage", "", homepagePreviewEnvironment),
("pull_request", "master", "", masterPreviewEnvironment),
("workflow_dispatch", "master", "preview", masterPreviewEnvironment),
("workflow_dispatch", "Perf/Homepage", "preview", homepagePreviewEnvironment),
("workflow_dispatch", "master", "production", productionEnvironment),
("workflow_dispatch", "Perf/Homepage", "production", productionEnvironment),
])("deployment environment for %s on %s with selection '%s'", async ((
event,
branch,
selection,
expectedEnvironment,
)) => {
let state = await Workflow.fixture(
~overrides=[
("GITHUB_EVENT_NAME", event),
("RAW_BRANCH", branch),
("DEPLOY_ENVIRONMENT", selection),
("GH_FAIL", "1"),
],
(),
)
expectSuccess(Workflow.run("deployment-environment.sh", state))
expect(await Workflow.environmentContents(state))->toBe(expectedEnvironment)
expect(exists(join([state.directory, "calls.jsonl"])))->toBe(false)
})

Expand Down
28 changes: 22 additions & 6 deletions apps/docs/scripts/lighthouse-report.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,32 @@ const reportCategoryKeys = {
seo: "seo",
};

export function lighthouseArtifactName(branch) {
export function lighthouseArtifactName(branch, environment) {
const defaultEnvironment = branch === "master" ? "production" : "preview";
const effectiveEnvironment = environment || defaultEnvironment;
if (!["production", "preview"].includes(effectiveEnvironment)) {
throw new Error(
`Invalid Lighthouse deployment environment: ${effectiveEnvironment}`,
);
}
// Preserve existing production-master and branch-preview keys. Alternative
// environments use a separate identity so they cannot overwrite those keys.
const isDefaultEnvironment = effectiveEnvironment === defaultEnvironment;
const identity = isDefaultEnvironment
? branch
: `${effectiveEnvironment}\0${branch}`;
const environmentPrefix = isDefaultEnvironment
? ""
: `${effectiveEnvironment}-`;
const slug = branch
.toLowerCase()
.replace(/[^a-z0-9-]+/g, "-")
.replace(/^-+|-+$/g, "")
.replace(/-+/g, "-")
.slice(0, 80);
const digest = createHash("sha256").update(branch, "utf8").digest("hex");
const digest = createHash("sha256").update(identity, "utf8").digest("hex");

return `homepage-lighthouse-${slug || "branch"}-${digest}`;
return `homepage-lighthouse-${environmentPrefix}${slug || "branch"}-${digest}`;
}

function getFiniteNumber(value, description) {
Expand Down Expand Up @@ -224,13 +240,13 @@ async function writeComment() {
);
}

async function main(command, branch) {
async function main(command, branch, environment) {
if (command === "artifact-name") {
if (!branch) {
throw new Error("A branch name is required for artifact-name");
}

console.log(lighthouseArtifactName(branch));
console.log(lighthouseArtifactName(branch, environment));
return;
}

Expand All @@ -252,5 +268,5 @@ const entryPath = process.argv[1]
: "";

if (import.meta.url === entryPath) {
await main(process.argv[2], process.argv[3]);
await main(process.argv[2], process.argv[3], process.argv[4]);
}
Loading