-
-
Notifications
You must be signed in to change notification settings - Fork 4.9k
chore: add initial ecosystem plugin tests workflow #19643
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
JoshuaKGoldberg
wants to merge
49
commits into
eslint:main
Choose a base branch
from
JoshuaKGoldberg:ecosystem-tests
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 24 commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
baa84df
chore: add initial ecosystem plugin tests workflow
JoshuaKGoldberg b53fc7a
Merge branch 'main' into ecosystem-tests
JoshuaKGoldberg 4bb2f02
Apply suggestions from code review
JoshuaKGoldberg f17af7d
Comments and structure
JoshuaKGoldberg 30404a4
Switch to nano-spawn, with plugins.json
JoshuaKGoldberg d822b05
Merge branch 'main'
JoshuaKGoldberg 4345a1a
Revert unintentional docs/src/_data/further_reading_links.json changes
JoshuaKGoldberg 3e9eff8
Tweaked docs text for runCommand
JoshuaKGoldberg ba6cc11
Added a script to update data
JoshuaKGoldberg 8674cba
Fix: errororing on error for unknown plugin
JoshuaKGoldberg 08d32ac
Add weekly cron to update data
JoshuaKGoldberg 073be89
Add comments to match index.mjs
JoshuaKGoldberg ece43e6
fix: .json files are formatted with two spaces
JoshuaKGoldberg 27b1cf7
Apply suggestions from code review
JoshuaKGoldberg 8b98d5b
Added the once-a-week comment
JoshuaKGoldberg d62f557
Merge branch 'main'
JoshuaKGoldberg 2365eaa
Default to all
JoshuaKGoldberg cb2fd6a
Mention the default of all
JoshuaKGoldberg 309d889
Merge branch 'main' into ecosystem-tests
JoshuaKGoldberg 79b3c45
npm run test:ecosystem:update
JoshuaKGoldberg 8312ff6
rm duplicate .json
JoshuaKGoldberg 76daffd
Merge branch 'main' into ecosystem-tests
JoshuaKGoldberg 1498b92
DISCORD_CONTRIBUTORS_WEBHOOK
JoshuaKGoldberg 007a82e
Correct error message for all plugins
JoshuaKGoldberg b65db91
Merge branch 'main'
JoshuaKGoldberg 5454ba9
Apply suggestions from code review
JoshuaKGoldberg 0d60d7c
Apply suggestions from code review
JoshuaKGoldberg 5288f49
Apply suggestions from code review
JoshuaKGoldberg e69f023
Continue bumping to latest
JoshuaKGoldberg bdf13de
chore: formatting
JoshuaKGoldberg aa75a32
Finish migration off of chalk
JoshuaKGoldberg c85df45
Remove nano-spawn
JoshuaKGoldberg a03b450
Added typescript-eslint and docs
JoshuaKGoldberg afe15a4
Merge branch 'main' into ecosystem-tests
JoshuaKGoldberg 997af03
Apply suggestions from code review
JoshuaKGoldberg 70fef79
More docs, and use prettier
JoshuaKGoldberg 14d745a
JSDoc correction
JoshuaKGoldberg ba685b1
Import sorting, while I'm in the area
JoshuaKGoldberg 2983232
fix: proper cross-OS file path/URLs to package.json
JoshuaKGoldberg d856e94
nit: proper comment placement
JoshuaKGoldberg b185105
'local' ESLint, not 'built'
JoshuaKGoldberg f60df01
further 'local'
JoshuaKGoldberg 5815b23
Add debug()
JoshuaKGoldberg 862dd99
NI_AUTO_INSTALL
JoshuaKGoldberg 3c712da
Update package.json
JoshuaKGoldberg b941959
NI_DEFAULT_AGENT
JoshuaKGoldberg 97e986e
{ NI_DEFAULT_AGENT: "npm" }
JoshuaKGoldberg 0444246
Switch to hardcoded commands
JoshuaKGoldberg 4d5e41d
Merge branch 'main' into ecosystem-tests
JoshuaKGoldberg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| name: Test Ecosystem Plugins | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - "ecosystem/*" | ||
| schedule: | ||
| # “At 00:00.” https://crontab.guru/#0_0_*_*_* | ||
| - cron: "0 0 * * *" | ||
| workflow_dispatch: ~ | ||
|
|
||
| permissions: read-all | ||
|
|
||
| jobs: | ||
| test_ecosystem: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-node@v4 | ||
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| with: | ||
| node-version: "lts/*" | ||
| - run: npm install | ||
| - id: tester | ||
| run: npm run test:ecosystem -- --plugin all | ||
| - if: steps.tester.outcome == 'failure' && github.head_ref == 'main' | ||
| env: | ||
| DISCORD_WEBHOOK: ${{ secrets.DISCORD_CONTRIBUTORS_WEBHOOK }} | ||
| uses: Ilshidur/action-discord@0c4b27844ba47cb1c7bee539c8eead5284ce9fa9 # v0.3.2 | ||
JoshuaKGoldberg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| with: | ||
| args: "Ecosystem tests failed." | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| name: Update Test Ecosystem Plugins | ||
|
|
||
| on: | ||
| schedule: | ||
| # “At 00:00 on Monday.” https://crontab.guru/#0_0_*_*_1 | ||
| - cron: "0 0 * * 1" | ||
JoshuaKGoldberg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| workflow_dispatch: ~ | ||
|
|
||
| permissions: read-all | ||
|
|
||
| jobs: | ||
| test_ecosystem: | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - uses: actions/setup-node@v4 | ||
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| with: | ||
| node-version: "lts/*" | ||
| - run: npm install | ||
| - run: npm run test:ecosystem:update -- --plugin all | ||
| - uses: peter-evans/[email protected] | ||
| with: | ||
| commit-message: "chore: update ecosystem plugins" | ||
| title: "chore: update ecosystem plugins" | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
| test.js | ||
| coverage/ | ||
| build/ | ||
| ecosystem/ | ||
| npm-debug.log | ||
| yarn-error.log | ||
| .pnpm-debug.log | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| /** | ||
| * @fileoverview Data utilities for ecosystem tests and updates to data. | ||
| * @author Josh Goldberg | ||
| */ | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Requirements | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| import chalk from "chalk"; | ||
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| import util from "node:util"; | ||
| import path from "node:path"; | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Types | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| /** | ||
| * Settings for how to clone, set up, and test an ecosystem plugin. | ||
| * @typedef {Object} PluginData | ||
| * @property {string} commit Hash to check out after cloning the plugin. | ||
| * @property {string} repository Repository URL to clone the plugin from. | ||
| */ | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Constants | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| export const pluginDataFilePath = path.join( | ||
| import.meta.dirname, | ||
| "plugins-data.json", | ||
| ); | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Functions | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| /** | ||
| * | ||
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * @param {"test" | "update"} action | ||
| * @returns {[string, PluginData][]} | ||
| */ | ||
| export async function getPlugins(action) { | ||
| const { values } = util.parseArgs({ | ||
| options: { | ||
| plugin: { | ||
| type: "string", | ||
| help: `The name of the plugin to ${action}, or 'all' for all plugins (default: 'all')`, | ||
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| }, | ||
| }, | ||
| }); | ||
|
|
||
| const { plugin: pluginRequested = "all" } = values; | ||
| const { default: pluginsData } = await import(pluginDataFilePath, { | ||
JoshuaKGoldberg marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| with: { type: "json" }, | ||
| }); | ||
|
|
||
| if (pluginRequested !== "all" && !(pluginRequested in pluginsData)) { | ||
| console.error(`The plugin "${values.plugin}" is not supported.`); | ||
| console.error( | ||
| `Supported plugins are: ${["", ...Object.keys(pluginsData)].join( | ||
| "\n ", | ||
| )}`, | ||
| ); | ||
| console.error( | ||
| `Alternately, run without --plugin to ${action} all plugins.`, | ||
| ); | ||
| process.exit(1); | ||
| } | ||
|
|
||
| const pluginsSelected = | ||
| pluginRequested === "all" | ||
| ? Object.entries(pluginsData) | ||
| : [[pluginRequested, pluginsData[pluginRequested]]]; | ||
|
|
||
| console.log( | ||
| `Plugins to ${action}:`, | ||
| chalk.bold(pluginsSelected.map(([key]) => key).join(", ")), | ||
| ); | ||
|
|
||
| return { pluginsData, pluginsSelected }; | ||
| } | ||
JoshuaKGoldberg marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,146 @@ | ||
| /** | ||
| * @fileoverview A utility to test ecosystem plugin(s) against the built ESLint. | ||
| * @author Josh Goldberg | ||
| */ | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Requirements | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| import chalk from "chalk"; | ||
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| import spawn from "nano-spawn"; | ||
| import fs from "node:fs/promises"; | ||
| import path from "node:path"; | ||
| import { getPlugins } from "./data.mjs"; | ||
|
|
||
| /** | ||
| * @typedef {import("./data").PluginSettings} PluginSettings | ||
| */ | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Helpers | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| /** | ||
| * Runs ecosystem tests for a single plugin. It will: | ||
| * 1. Clone the plugin repository into a sandbox directory | ||
| * 2. Check out the plugin's commit to test on | ||
| * 3. Install the plugin's dependencies | ||
| * 4. Link the built ESLint into the plugin | ||
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| * 5. Build, if the plugin defines a build script | ||
| * 6. Run tests | ||
| * This intentionally does not try/catch: any errors will be thrown. | ||
| * | ||
| * @param {string} pluginKey | ||
| * @param {PluginSettings} pluginSettings | ||
| */ | ||
| async function runTests(pluginKey, pluginSettings) { | ||
| const directory = path.join( | ||
| SANDBOX_DIRECTORY, | ||
| pluginKey | ||
| .replaceAll(/[^a-z-]/g, " ") | ||
| .trim() | ||
| .replaceAll(" ", "-"), | ||
| ); | ||
| console.log(chalk.bold(`Testing ${pluginKey} in ${directory}`)); | ||
|
|
||
| /** | ||
| * Attempts to run a command in the plugin sandbox directory. | ||
| * If it fails, any error stdout will be logged in red before a re-throw. | ||
| * @param {string} command | ||
| * @param {string[]} args | ||
| */ | ||
| const runCommand = async (command, ...args) => { | ||
| console.log(chalk.gray(`[${pluginKey}]`, [command, ...args].join(" "))); | ||
| try { | ||
| return await spawn(command, args, { | ||
| cwd: directory, | ||
| }); | ||
| } catch (error) { | ||
| console.error( | ||
| chalk.red(`[${pluginKey}]`), | ||
| "stdout" in error ? error.stdout : error, | ||
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ); | ||
| throw error; | ||
| } | ||
| }; | ||
|
|
||
| // 1. Clone the plugin repository into a sandbox directory | ||
| await fs.mkdir(directory, { force: true }); | ||
| await runCommand( | ||
| "git", | ||
| "clone", | ||
| pluginSettings.repository, | ||
| directory, | ||
| "--depth", | ||
| "1", | ||
| ); | ||
|
|
||
| // 2. Check out the plugin's commit to test on | ||
| await runCommand("git", "fetch", "origin", pluginSettings.commit); | ||
| await runCommand("git", "checkout", pluginSettings.commit); | ||
|
|
||
| // 3. Install the plugin's dependencies | ||
| await runCommand("pwd"); | ||
| await runCommand("ni"); | ||
JoshuaKGoldberg marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| // 4. Link the built ESLint into the plugin | ||
| await runCommand("npm", "link", "eslint"); | ||
|
|
||
| const packageJsonPath = path.resolve( | ||
| process.cwd(), | ||
| path.join(directory, "package.json"), | ||
| ); | ||
| const packageJson = await import(packageJsonPath, { | ||
| with: { type: "json" }, | ||
| }); | ||
|
|
||
| // 5. Build, if the plugin defines a build script | ||
| if (packageJson.default.scripts.build) { | ||
| await runCommand("nr", "build"); | ||
| } | ||
|
|
||
| // 6. Run test | ||
| await runCommand("nr", "test"); | ||
| } | ||
|
|
||
| //----------------------------------------------------------------------------- | ||
| // Main | ||
| //----------------------------------------------------------------------------- | ||
|
|
||
| const { pluginsSelected } = await getPlugins("test"); | ||
|
|
||
| const SANDBOX_DIRECTORY = path.join(process.cwd(), "ecosystem"); | ||
|
|
||
| console.log(`Clearing existing sandbox directory: ${SANDBOX_DIRECTORY}`); | ||
| await fs.rm(SANDBOX_DIRECTORY, { | ||
| force: true, | ||
| maxRetries: 8, | ||
| recursive: true, | ||
| }); | ||
| await fs.mkdir(SANDBOX_DIRECTORY, { recursive: true }); | ||
| console.log(""); | ||
|
|
||
| const errors = []; | ||
|
|
||
| // For each plugin to test, we try to runTests, recording thrown exceptions in errors | ||
| for (const [pluginKey, pluginSettings] of pluginsSelected) { | ||
| try { | ||
| await runTests(pluginKey, pluginSettings); | ||
| } catch (error) { | ||
| errors.push({ error, pluginKey }); | ||
| } | ||
|
|
||
| console.log(""); | ||
| } | ||
|
|
||
| // If we had any errors, report them and exit as failed | ||
| if (errors.length) { | ||
| console.error(chalk.red("Errors occurred while testing plugins:")); | ||
| for (const { error, pluginKey } of errors) { | ||
| console.error(`${chalk.bold.red(pluginKey)}: ${chalk.red(error)}`); | ||
| } | ||
| process.exitCode = 1; | ||
| } else { | ||
| console.log(chalk.green("All tests completed successfully.")); | ||
| } | ||
JoshuaKGoldberg marked this conversation as resolved.
Show resolved
Hide resolved
JoshuaKGoldberg marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| { | ||
| "@eslint/css": { | ||
| "commit": "26b902c4f42cccb33d7f8119a3376773e0ad91bd", | ||
| "repository": "https://github.com/eslint/css" | ||
| }, | ||
| "@eslint/json": { | ||
| "commit": "2d9722a9a3bab75301906d574266281305ec91df", | ||
| "repository": "https://github.com/eslint/json" | ||
| }, | ||
| "@eslint/markdown": { | ||
| "commit": "614ef3e0bf539655170f202467119fbbbf8963f6", | ||
| "repository": "https://github.com/eslint/markdown" | ||
| }, | ||
| "@eslint-community/eslint-plugin-eslint-comments": { | ||
| "commit": "d6869dfbb794437c00e0e27e6cc0dbdfd3c56fac", | ||
| "repository": "https://github.com/eslint-community/eslint-plugin-eslint-comments" | ||
| }, | ||
| "eslint-plugin-unicorn": { | ||
| "commit": "f4eb2e731358d68b031d7fd42bf725a23f9d1e4d", | ||
| "repository": "https://github.com/sindresorhus/eslint-plugin-unicorn" | ||
| }, | ||
| "eslint-plugin-vue": { | ||
| "commit": "fe0ce5a0590ee8b7aec57712f56f0d1d557035cb", | ||
| "repository": "https://github.com/vuejs/eslint-plugin-vue" | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.