diff --git a/AGENTS.md b/AGENTS.md index 220f723..fda4293 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -22,7 +22,7 @@ Dependencies come from `make install`, and CI uses the same target. The rest of **`make setup` installs nothing.** The target reads `setup: pull setup`, so make drops the circular dependency, runs `pull`, stops there and still exits 0. -`make test` needs the fixture image that `make pull` fetches. A single file goes through jest directly: `npx jest __tests__/packageChecker.test.js`. +`make test` needs the fixture image that `make pull` fetches. A single file goes through jest directly: `npx jest __tests__/index.test.js`. The fixture image name `hexlet-project-source-ci_en` is pinned in three places that have to agree: `Makefile` (target `pull`), `server.js` (the API stub for `e2e`) and `__tests__/index.test.js` (the nock response). @@ -31,7 +31,8 @@ The fixture image name `hexlet-project-source-ci_en` is pinned in three places t - `dist/` is gitignored and stays out of git: `release.yml` builds it with `@vercel/ncc` and force-adds it onto the `release` branch. `action.yml` points at `dist/run-tests/index.js` and `dist/run-post-actions/index.js`. - Two entry points in `bin/` are the two phases of the Action: `bin/run-tests.js` (main) and `bin/run-post-actions.js` (post — finishes the check and uploads artifacts). - `src/index.js` holds the orchestration: `prepareProject()` pulls the image and extracts the project source, `check()` runs Compose, `runTests()` and `runPostActions()` talk to the Hexlet API. -- `src/routes.js` builds the API urls. `src/packageChecker.js` validates the package name of the student's project against the conventions of its language, reading `pyproject.toml`, `composer.json` or `package.json`. +- `src/routes.js` builds the API urls. +- **The action does not check the name of the student's package.** It used to, per language, and the check was dropped: the name is load-bearing only where the project's own harness resolves the package by it. That is the php library projects, whose root `composer.json` requires `hexlet/code` from a path repository — a wrong name fails `composer install` on its own. For javascript the harness `package.json` names the dependency `"@hexlet/code": "file:code"`, and npm installs a path dependency under that key whatever the package calls itself, so the import resolves either way. For python nothing reads the distribution name: the console scripts have names of their own. - `check()` calls two fixed compose service names of the project — `app` for `make setup`, then `test` — and the exit code of `test` is the verdict. Both the fixed names and the flags carry `NOTE` comments in the code; read them before changing the commands. - Tests stub the Hexlet API with a local Fastify server (`server.js`), fixtures live in `__fixtures__/`. - Artifacts of the student's tests are collected from `/tmp/artifacts/*/**` and uploaded as the `test-results` artifact. The glob starts one level down, so a file lying directly in `tmp/artifacts/` never reaches the student. diff --git a/__fixtures__/package_files/correct/composer.json b/__fixtures__/package_files/correct/composer.json deleted file mode 100644 index 4e23685..0000000 --- a/__fixtures__/package_files/correct/composer.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "hexlet/code", - "type": "project", - "description": "Page Analyzer", - "keywords": [ - "page", - "analyzer" - ], - "license": "MIT", - "config": { - "optimize-autoloader": true, - "preferred-install": "dist", - "sort-packages": true - }, - "extra": { - "laravel": { - "dont-discover": [] - } - }, - "autoload": { - "psr-4": { - "App\\": "app/", - "Database\\Factories\\": "database/factories/", - "Database\\Seeders\\": "database/seeders/" - } - }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - } - }, - "minimum-stability": "dev", - "prefer-stable": true, - "scripts": { - "post-autoload-dump": [ - "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", - "@php artisan package:discover --ansi" - ], - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ], - "post-create-project-cmd": [ - "@php artisan key:generate --ansi" - ] - }, - "require": { - "doctrine/dbal": "^3.0", - "fideloper/proxy": "^4.4", - "fruitcake/laravel-cors": "^2.0", - "guzzlehttp/guzzle": "^7.2", - "imangazaliev/didom": "^1.16", - "laracasts/flash": "^3.2", - "laravel/framework": "^8.20", - "laravel/tinker": "^2.5", - "nesbot/carbon": "^2.43" - }, - "require-dev": { - "fakerphp/faker": "^1.13", - "mockery/mockery": "^1.4", - "nunomaduro/collision": "^5.1", - "phpunit/phpunit": "^9.5", - "squizlabs/php_codesniffer": "^3.5" - } -} diff --git a/__fixtures__/package_files/correct/package.json b/__fixtures__/package_files/correct/package.json deleted file mode 100644 index 7ca2afc..0000000 --- a/__fixtures__/package_files/correct/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "@hexlet/code", - "version": "0.0.2", - "description": "Compares two configuration files and shows a difference.", - "type": "module", - "main": "index.js", - "bin": { - "gendiff": "bin/gendiff.js" - }, - "engines": { - "node": ">=14" - }, - "scripts": { - "test": "npx jest" - }, - "author": "Hexlet", - "dependencies": { - "commander": "^6.1.0", - "js-yaml": "^3.14.0", - "lodash": "^4.17.20" - }, - "devDependencies": { - "eslint": "^7.13.0", - "eslint-config-airbnb-base": "^14.2.1", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.1.3", - "jest": "^26.6.3" - } -} diff --git a/__fixtures__/package_files/correct/pyproject.toml b/__fixtures__/package_files/correct/pyproject.toml deleted file mode 100644 index 11690f9..0000000 --- a/__fixtures__/package_files/correct/pyproject.toml +++ /dev/null @@ -1,27 +0,0 @@ -[project] -name = "hexlet-code" -version = "0.1.0" -description = "Diff generator" -readme = "README.md" -requires-python = ">=3.12" -dependencies = [ - "pathlib>=1.0.1", - "pyyaml>=6.0.2", -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["gendiff"] - -[dependency-groups] -dev = [ - "pytest-cov>=6.0.0", - "pytest>=8.3.4", - "ruff>=0.8.3", -] - -[project.scripts] -gendiff = "gendiff.scripts.gendiff:main" diff --git a/__fixtures__/package_files/wrong/composer.json b/__fixtures__/package_files/wrong/composer.json deleted file mode 100644 index 87ec063..0000000 --- a/__fixtures__/package_files/wrong/composer.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "wrong-package-name", - "type": "project", - "description": "Page Analyzer", - "keywords": [ - "page", - "analyzer" - ], - "license": "MIT", - "config": { - "optimize-autoloader": true, - "preferred-install": "dist", - "sort-packages": true - }, - "extra": { - "laravel": { - "dont-discover": [] - } - }, - "autoload": { - "psr-4": { - "App\\": "app/", - "Database\\Factories\\": "database/factories/", - "Database\\Seeders\\": "database/seeders/" - } - }, - "autoload-dev": { - "psr-4": { - "Tests\\": "tests/" - } - }, - "minimum-stability": "dev", - "prefer-stable": true, - "scripts": { - "post-autoload-dump": [ - "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump", - "@php artisan package:discover --ansi" - ], - "post-root-package-install": [ - "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" - ], - "post-create-project-cmd": [ - "@php artisan key:generate --ansi" - ] - }, - "require": { - "doctrine/dbal": "^3.0", - "fideloper/proxy": "^4.4", - "fruitcake/laravel-cors": "^2.0", - "guzzlehttp/guzzle": "^7.2", - "imangazaliev/didom": "^1.16", - "laracasts/flash": "^3.2", - "laravel/framework": "^8.20", - "laravel/tinker": "^2.5", - "nesbot/carbon": "^2.43" - }, - "require-dev": { - "fakerphp/faker": "^1.13", - "mockery/mockery": "^1.4", - "nunomaduro/collision": "^5.1", - "phpunit/phpunit": "^9.5", - "squizlabs/php_codesniffer": "^3.5" - } -} diff --git a/__fixtures__/package_files/wrong/package.json b/__fixtures__/package_files/wrong/package.json deleted file mode 100644 index 02450e9..0000000 --- a/__fixtures__/package_files/wrong/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "wrong-package-name", - "version": "0.0.2", - "description": "Compares two configuration files and shows a difference.", - "type": "module", - "main": "index.js", - "bin": { - "gendiff": "bin/gendiff.js" - }, - "engines": { - "node": ">=14" - }, - "scripts": { - "test": "npx jest" - }, - "author": "Hexlet", - "dependencies": { - "commander": "^6.1.0", - "js-yaml": "^3.14.0", - "lodash": "^4.17.20" - }, - "devDependencies": { - "eslint": "^7.13.0", - "eslint-config-airbnb-base": "^14.2.1", - "eslint-plugin-import": "^2.22.1", - "eslint-plugin-jest": "^24.1.3", - "jest": "^26.6.3" - } -} diff --git a/__fixtures__/package_files/wrong/pyproject.toml b/__fixtures__/package_files/wrong/pyproject.toml deleted file mode 100644 index 77cc2a4..0000000 --- a/__fixtures__/package_files/wrong/pyproject.toml +++ /dev/null @@ -1,33 +0,0 @@ -[tool.poetry] -name = "wrong-package-name" -version = "0.1.0" -description = "Task manager" -authors = ["Hexlet team "] -license = "MIT" -readme = "README.md" -homepage = "https://hexlet.io" - -packages = [ - { include = "task_manager" }, -] - -[tool.poetry.dependencies] -python = "^3.8" -Django = "^3.1.5" -python-dotenv = "^0.15.0" -gunicorn = "^20.0.4" -whitenoise = "^5.2.0" -django-bootstrap4 = "^2.3.1" -dj-database-url = "^0.5.0" -psycopg2-binary = "^2.8.6" -django-filter = "^2.4.0" - -[tool.poetry.dev-dependencies] -flake8 = "^3.8.4" -coverage = "^5.3.1" - -[tool.poetry.scripts] - -[build-system] -requires = ["poetry>=0.12"] -build-backend = "poetry.masonry.api" diff --git a/__tests__/packageChecker.test.js b/__tests__/packageChecker.test.js deleted file mode 100644 index 7bd8968..0000000 --- a/__tests__/packageChecker.test.js +++ /dev/null @@ -1,50 +0,0 @@ -import path from 'node:path'; -import { fileURLToPath } from 'node:url'; - -import checkPackageName from '../src/packageChecker.js'; - -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -const verifiableProjects = ['javascript', 'php', 'python']; - -// NOTE: Some projects are not packages. -// Also, in some languages, verification is not needed, -// since the package name is verified when installing the dependencies. -const notVerifiableProjects = [ - 'html', - 'ruby', - 'java', - 'undefined-language', - null, - undefined, -]; - -const getFixturePath = (dirname) => - path.join(__dirname, '..', '__fixtures__', 'package_files', dirname); - -describe('test projects with correct package name', () => { - const codePath = getFixturePath('correct'); - - test.each(verifiableProjects)('%s', (sourceLang) => { - expect(() => checkPackageName(codePath, sourceLang)).not.toThrow(); - }); -}); - -describe('test projects with wrong package name', () => { - const codePath = getFixturePath('wrong'); - - test.each(verifiableProjects)('%s', (sourceLang) => { - expect(() => checkPackageName(codePath, sourceLang)).toThrow( - /^Package name should be .+ instead of wrong-package-name$/, - ); - }); -}); - -describe('test not verifiable projects', () => { - const codePath = getFixturePath('correct'); - - test.each(notVerifiableProjects)('%s', (sourceLang) => { - expect(() => checkPackageName(codePath, sourceLang)).not.toThrow(); - }); -}); diff --git a/package-lock.json b/package-lock.json index 8370dd8..ea6726e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,6 @@ "ansi-colors": "^4.1.3", "chalk": "^5.6.2", "clean-stack": "^6.0.0", - "ini": "^6.0.0", "js-yaml": "^4.1.1", "lodash": "^4.18.1" }, @@ -4562,15 +4561,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "node_modules/ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/ipaddr.js": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", @@ -10651,11 +10641,6 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, - "ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==" - }, "ipaddr.js": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.3.0.tgz", diff --git a/package.json b/package.json index d725132..01aa70d 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,6 @@ "ansi-colors": "^4.1.3", "chalk": "^5.6.2", "clean-stack": "^6.0.0", - "ini": "^6.0.0", "js-yaml": "^4.1.1", "lodash": "^4.18.1" }, diff --git a/src/index.js b/src/index.js index 5341600..205abdc 100644 --- a/src/index.js +++ b/src/index.js @@ -13,7 +13,6 @@ import { HttpClient } from '@actions/http-client'; import * as io from '@actions/io'; import colors from 'ansi-colors'; import yaml from 'js-yaml'; -import checkPackageName from './packageChecker.js'; import buildRoutes from './routes.js'; const uploadArtifacts = async (diffpath) => { @@ -135,9 +134,7 @@ const prepareProject = async (options) => { }); }; -const check = async ({ projectSourcePath, codePath, projectMember }) => { - const sourceLang = projectMember.project.language; - checkPackageName(codePath, sourceLang); +const check = async ({ projectSourcePath }) => { const options = { cwd: projectSourcePath }; // NOTE: -f docker-compose.yml is required: the project image also carries // docker-compose.override.yml, which switches app to its dev command. diff --git a/src/packageChecker.js b/src/packageChecker.js deleted file mode 100644 index d7997e8..0000000 --- a/src/packageChecker.js +++ /dev/null @@ -1,62 +0,0 @@ -// @ts-check - -import fs from 'node:fs'; -import path from 'node:path'; -import ini from 'ini'; - -// import yaml from 'js-yaml'; -// import _ from 'lodash'; - -const parsers = { - json: JSON.parse, - toml: ini.parse, - // yml: yaml.load, -}; - -const getFullPath = (dirpath, filename) => path.resolve(dirpath, filename); -const getFormat = (filepath) => path.extname(filepath).slice(1); -const parse = (content, format) => parsers[format](content); -const getData = (filepath) => - parse(fs.readFileSync(filepath, 'utf-8'), getFormat(filepath)); - -const mapping = { - python: { - expectedPackageName: 'hexlet-code', - getPackageName: (codePath) => { - const data = getData(getFullPath(codePath, 'pyproject.toml')); - - return data.tool?.poetry?.name || data.project.name; - }, - }, - php: { - expectedPackageName: 'hexlet/code', - getPackageName: (codePath) => - getData(getFullPath(codePath, 'composer.json')).name, - }, - javascript: { - expectedPackageName: '@hexlet/code', - getPackageName: (codePath) => - getData(getFullPath(codePath, 'package.json')).name, - }, -}; - -const checkPackageName = (codePath, sourceLang) => { - const props = mapping[sourceLang]; - - // NOTE: If the properties for checking the current project - // is not found, skip the check. - if (!props) { - return; - } - - const { expectedPackageName, getPackageName } = props; - const packageName = getPackageName(codePath); - - if (packageName !== expectedPackageName) { - throw new Error( - `Package name should be ${expectedPackageName} instead of ${packageName}`, - ); - } -}; - -export default checkPackageName;