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
16 changes: 8 additions & 8 deletions .agents/bin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ run `.agents/bin/<name>` in any repo without knowing this repo's specific
commands. Each script is a thin, repo-owned wrapper. A script that is **absent**
means that capability is n/a here.

| Script | Purpose | This repo runs |
| ---------- | ---------------------------------------- | ---------------------------------------------------------------- |
| `setup` | Install dependencies | `bundle install` + `yarn install` |
| `validate` | Pre-push gate (run before pushing) | `lint` + `test` |
| `test` | Run tests | `bundle exec rake test` (rspec) + `yarn test --runInBand` (jest) |
| `lint` | Lint / format (pass `-A` to fix RuboCop) | `bundle exec rubocop` + `yarn lint` (eslint) |
| `build` | Build / type-check | `yarn build` + `yarn type-check` |
| `merge-readiness-check` | Pre-merge/replay readiness check | Verifies full `gh pr checks` completion, unresolved review threads, mergeability, and historical post-merge timing |
| Script | Purpose | This repo runs |
| ----------------------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| `setup` | Install dependencies | `bundle install` + `yarn install` |
| `validate` | Pre-push gate (run before pushing) | `lint` + `test` |
| `test` | Run tests | `bundle exec rake test` (rspec) + `yarn test --runInBand` (jest) |
| `lint` | Lint / format (pass `-A` to fix RuboCop) | `bundle exec rubocop` + `yarn lint` (eslint) |
| `build` | Build / type-check | `yarn build` + `yarn type-check` |
| `merge-readiness-check` | Pre-merge/replay readiness check | Verifies full `gh pr checks` completion, unresolved review threads, mergeability, and historical post-merge timing |

Canonical non-command policy lives in [`../../AGENTS.md`](../../AGENTS.md).
[`../agent-workflow.yml`](../agent-workflow.yml) is retained only as a
Expand Down
55 changes: 55 additions & 0 deletions .github/workflows/babel8-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Babel 8 smoke

on:
push:
branches:
- "main"
paths:
- ".github/workflows/babel8-smoke.yml"
- "package.json"
- "yarn.lock"
- "package/babel/**"
- "package/utils/**"
- "test/packages/babel8-smoke.test.js"
pull_request:
paths:
- ".github/workflows/babel8-smoke.yml"
- "package.json"
- "yarn.lock"
- "package/babel/**"
- "package/utils/**"
- "test/packages/babel8-smoke.test.js"
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
babel8-smoke:
name: Babel 8 smoke
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- uses: actions/checkout@v4
with:
persist-credentials: false

- name: Use Node.js 22
uses: actions/setup-node@v4
with:
node-version: "22.x"
cache: yarn

- name: Install dependencies
run: yarn --frozen-lockfile --non-interactive --prefer-offline

- name: Build TypeScript
run: yarn build

- name: Babel 8 smoke
run: yarn jest test/packages/babel8-smoke.test.js --runInBand
env:
BABEL_ENV: production
RUN_BABEL8_SMOKE: "1"
5 changes: 2 additions & 3 deletions .github/workflows/node.yml
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,7 @@ jobs:
git fetch origin ${{ github.event.pull_request.base.sha }}
if git diff --name-only ${{ github.event.pull_request.base.sha }} ${{ github.sha }} | grep -q '^.github/workflows'; then
echo "changed=true" >> "$GITHUB_OUTPUT"
response=$(curl -sf https://api.github.com/repos/rhysd/actionlint/releases/latest)
if [ $? -eq 0 ]; then
if response=$(curl -sf https://api.github.com/repos/rhysd/actionlint/releases/latest); then
actionlint_version=$(echo "$response" | jq -r .tag_name)
if [ -z "$actionlint_version" ]; then
echo "Failed to parse Actionlint version"
Expand Down Expand Up @@ -141,7 +140,7 @@ jobs:
--skipLibCheck \
--moduleResolution bundler \
--types node \
*.d.ts
./*.d.ts
test:
name: Testing
strategy:
Expand Down
252 changes: 252 additions & 0 deletions test/packages/babel8-smoke.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
// Opt-in Babel 8 compatibility smoke.
Comment thread
justin808 marked this conversation as resolved.
//
// The normal test suite intentionally keeps repository development pins on
// Babel 7. Enable this smoke with RUN_BABEL8_SMOKE=1 after `yarn build`; it
// installs Babel 8 packages into a temp app and runs Webpack through
// babel-loader 10 with Shakapacker's built Babel preset.
//
// Keep the pinned Babel 8 package versions below in sync during Babel
// compatibility reviews. This smoke covers the published preset path; the
// babel-loader version guard is covered by test/package/rules/babel.test.js.
// Babel 8 transform targets are app-owned, so this avoids asserting
// target-sensitive downlevel output.

const { spawnSync } = require("child_process")
const fs = require("fs")
const { createRequire } = require("module")
const os = require("os")
const path = require("path")

const repoRoot = path.resolve(__dirname, "../..")
const builtPackageDir = path.join(repoRoot, "package")
const builtPresetPath = path.join(builtPackageDir, "babel/preset.js")
const webpackPath = require.resolve("webpack")
const babel8SmokePackages = [
"@babel/core@8.0.1",
Comment thread
justin808 marked this conversation as resolved.
"@babel/plugin-transform-runtime@8.0.1",
"@babel/preset-env@8.0.2",
"@babel/runtime@8.0.0",
"babel-loader@10.1.1"
]
Comment thread
justin808 marked this conversation as resolved.
const optedIn = process.env.RUN_BABEL8_SMOKE === "1"
const coreIsBuilt = fs.existsSync(builtPresetPath)

const toolVersion = (cmd) => {
Comment thread
justin808 marked this conversation as resolved.
const r = spawnSync(cmd, ["--version"], {
encoding: "utf8",
cwd: os.tmpdir()
})
return r.status === 0 ? r.stdout.trim() : null
}
Comment thread
justin808 marked this conversation as resolved.

const npmVersion = toolVersion("npm")
const hasNpm = npmVersion !== null
const shouldRun = optedIn && coreIsBuilt && hasNpm

const run = (cmd, args, options) => {
const r = spawnSync(cmd, args, {
encoding: "utf8",
timeout: 180000,
...options
})
if (r.status !== 0) {
throw new Error(
`${cmd} ${args.join(" ")} failed in ${options.cwd}\nstdout:\n${r.stdout}\nstderr:\n${r.stderr}`
)
}
Comment thread
justin808 marked this conversation as resolved.
return r
}
Comment thread
justin808 marked this conversation as resolved.

const packageVersion = (appRequire, packageName) => {
const packageJsonPath = appRequire.resolve(`${packageName}/package.json`)
return appRequire(packageJsonPath).version
}

const installBuiltShakapackerPackage = (workRoot) => {
const packageRoot = path.join(workRoot, "node_modules/shakapacker")
const sourcePackageJson = JSON.parse(
fs.readFileSync(path.join(repoRoot, "package.json"), "utf8")
)
fs.mkdirSync(packageRoot, { recursive: true })
fs.writeFileSync(
path.join(packageRoot, "package.json"),
JSON.stringify(
{
name: sourcePackageJson.name,
version: sourcePackageJson.version,
private: true,
main: sourcePackageJson.main,
exports: sourcePackageJson.exports,
files: sourcePackageJson.files
},
null,
2
)
)

fs.cpSync(builtPackageDir, path.join(packageRoot, "package"), {
recursive: true
})
}
Comment thread
justin808 marked this conversation as resolved.

const writeWebpackSmokeRunner = ({ workRoot, srcDir, distDir, presetPath }) => {
const runnerPath = path.join(workRoot, "run-webpack-smoke.cjs")
fs.writeFileSync(
runnerPath,
`
const { createRequire } = require("module")
const path = require("path")
const webpack = require(${JSON.stringify(webpackPath)})

const workRoot = ${JSON.stringify(workRoot)}
const srcDir = ${JSON.stringify(srcDir)}
const distDir = ${JSON.stringify(distDir)}
const presetPath = ${JSON.stringify(presetPath)}
const appRequire = createRequire(path.join(workRoot, "package.json"))

const compiler = webpack({
mode: "development",
devtool: false,
target: ["web", "es5"],
context: workRoot,
entry: path.join(srcDir, "index.js"),
output: {
path: distDir,
filename: "bundle.js"
},
module: {
rules: [
{
test: /\\.js$/,
include: srcDir,
use: [
{
loader: appRequire.resolve("babel-loader"),
options: {
cacheDirectory: false,
cwd: workRoot,
envName: "production",
presets: [presetPath]
Comment thread
justin808 marked this conversation as resolved.
}
}
]
}
]
},
optimization: {
minimize: false
}
})

const finish = (failure) => {
compiler.close((closeError) => {
const finalError = closeError || failure
if (finalError) {
console.error(finalError.stack || finalError.message || String(finalError))
process.exit(1)
}
})
}

compiler.run((error, stats) => {
if (error) {
finish(error)
return
}

if (stats.hasErrors()) {
finish(
new Error(
stats.toString({
all: false,
errors: true,
errorDetails: true,
moduleTrace: true
})
)
)
return
}

finish()
})
`
)
return runnerPath
}

const computeSkipReason = () => {
if (!optedIn) return "RUN_BABEL8_SMOKE=1 not set"
if (!coreIsBuilt) return "shakapacker not built (run `yarn build`)"
if (!hasNpm) return "npm unavailable on PATH"
return "unknown skip reason"
}

describe("Babel 8 preset smoke (issue #1191)", () => {
let workRoot

beforeAll(() => {
if (!shouldRun) return

workRoot = fs.mkdtempSync(path.join(os.tmpdir(), "shaka-babel8-smoke-"))
fs.writeFileSync(
path.join(workRoot, "package.json"),
JSON.stringify({ name: "shaka-babel8-smoke", private: true }, null, 2)
)
run(
"npm",
[
"install",
"--no-audit",
"--no-fund",
"--save-dev",
...babel8SmokePackages
],
{ cwd: workRoot }
)
installBuiltShakapackerPackage(workRoot)
}, 180000)

afterAll(() => {
if (!workRoot) return
fs.rmSync(workRoot, { recursive: true, force: true })
})

if (!shouldRun) {
test.todo(`Babel 8 smoke skipped (${computeSkipReason()})`)
return
}

test("compiles through babel-loader 10 with the Shakapacker Babel preset and Babel 8", () => {
const srcDir = path.join(workRoot, "src")
Comment thread
justin808 marked this conversation as resolved.
const distDir = path.join(workRoot, "dist")
fs.mkdirSync(srcDir)
const entryPath = path.join(srcDir, "index.js")
fs.writeFileSync(entryPath, "var answer = 42;\nconsole.log(answer);\n")
Comment thread
justin808 marked this conversation as resolved.

const appRequire = createRequire(path.join(workRoot, "package.json"))
const presetPath = appRequire.resolve("shakapacker/package/babel/preset.js")
expect(packageVersion(appRequire, "@babel/core")).toBe("8.0.1")
expect(packageVersion(appRequire, "@babel/preset-env")).toBe("8.0.2")
expect(packageVersion(appRequire, "@babel/plugin-transform-runtime")).toBe(
"8.0.1"
)
expect(packageVersion(appRequire, "@babel/runtime")).toBe("8.0.0")
expect(packageVersion(appRequire, "babel-loader")).toBe("10.1.1")

const runnerPath = writeWebpackSmokeRunner({
workRoot,
srcDir,
distDir,
presetPath
})

run(process.execPath, [runnerPath], {
cwd: workRoot,
env: { ...process.env, BABEL_ENV: "production" }
})

const bundle = fs.readFileSync(path.join(distDir, "bundle.js"), "utf8")
expect(bundle).toContain("42")
}, 180000)
})
Loading