From de32d8b95f218204426f670bbf8cd19080676ae2 Mon Sep 17 00:00:00 2001 From: Shivam Mathur Date: Fri, 27 Dec 2019 06:56:49 +0530 Subject: [PATCH] Add tools support --- README.md | 41 ++++++-- __tests__/install.test.ts | 45 +++++---- __tests__/tools.test.ts | 61 ++++++++++++ __tests__/utils.test.ts | 6 +- action.yml | 8 +- dist/index.js | 204 ++++++++++++++++++++++++++++++++++---- src/config.ts | 4 +- src/install.ts | 15 +-- src/scripts/darwin.sh | 21 +++- src/scripts/linux.sh | 53 ++++------ src/scripts/win32.ps1 | 37 ++++++- src/tools.ts | 141 ++++++++++++++++++++++++++ src/utils.ts | 32 +++--- 13 files changed, 556 insertions(+), 112 deletions(-) create mode 100644 __tests__/tools.test.ts create mode 100644 src/tools.ts diff --git a/README.md b/README.md index 400e2b2c..e3150497 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,8 @@ Setup PHP with required extensions, php.ini configuration, code-coverage support - [PHP Support](#tada-php-support) - [OS/Platform Support](#cloud-osplatform-support) -- [PHP Extension Support](#wrench-php-extension-support) +- [PHP Extension Support](#heavy_plus_sign-php-extension-support) +- [Tools Support](#wrench-tools-support) - [Coverage support](#signal_strength-coverage-support) - [Xdebug](#xdebug) - [PCOV](#pcov) @@ -60,13 +61,36 @@ Setup PHP with required extensions, php.ini configuration, code-coverage support |Ubuntu 16.04|`ubuntu-16.04`| |macOS X Catalina 10.15|`macOS-latest` or `macOS-10.15`| -## :wrench: PHP Extension Support -- On `ubuntu` by default extensions which are available as a package can be installed. If the extension is not available as a package but it is on `PECL`, it can be installed by specifying `pecl: true`. +## :heavy_plus_sign: PHP Extension Support +- On `ubuntu` by default extensions which are available as a package can be installed. If the extension is not available as a package but it is on `PECL`, it can be installed by specifying `pecl` in the tools input. - On `windows` extensions which have `windows` binary on `PECL` can be installed. - On `macOS` extensions which are on `PECL` can be installed. - Extensions which are installed along with PHP if specified are enabled. - Extensions which cannot be installed gracefully leave an error message in the logs, the action is not interrupted. +## :wrench: Tools Support + +The following tools can be setup globally using the `tools` input + +- `php-cs-fixer` +- `phpcs` +- `phpcbf` +- `phpcpd` +- `phpstan` +- `phpmd` +- `codeception` +- `phpunit` +- `deployer` +- `prestissimo` +- `pecl` + +```yml +uses: shivammathur/setup-php@v1 +with: + php-version: '7.4' + tools: php-cs-fixer, phpunit +``` + ## :signal_strength: Coverage support ### Xdebug @@ -121,7 +145,7 @@ Inputs supported by this GitHub Action. - extensions `optional` - ini-values `optional` - coverage `optional` -- pecl `optional` +- tools `optional` See [action.yml](action.yml "Metadata for this GitHub Action") and usage below for more info. @@ -141,7 +165,7 @@ steps: extensions: mbstring, intl #optional, setup extensions ini-values: post_max_size=256M, short_open_tag=On #optional, setup php.ini configuration coverage: xdebug #optional, setup coverage driver - pecl: false #optional, setup PECL + tools: php-cs-fixer, phpunit #optional, setup tools globally ``` ### Matrix Setup @@ -168,7 +192,7 @@ jobs: extensions: mbstring, intl #optional, setup extensions ini-values: post_max_size=256M, short_open_tag=On #optional, setup php.ini configuration coverage: xdebug #optional, setup coverage driver - pecl: false #optional, setup PECL + tools: php-cs-fixer, phpunit #optional, setup tools globally ``` ### Experimental Setup @@ -191,7 +215,8 @@ steps: php-version: '8.0' extensions: mbstring #optional, setup extensions ini-values: opcache.jit_buffer_size=256M, opcache.jit=1235, pcre.jit=1 #optional, setup php.ini configuration - coverage: pcov #optional, setup PCOV, Xdebug does not support this version yet. + coverage: pcov #optional, setup PCOV, Xdebug does not support this version yet. + tools: php-cs-fixer, phpunit #optional, setup tools globally ``` ### Cache dependencies @@ -208,7 +233,7 @@ You can persist composer's internal cache directory using the [`action/cache`](h - name: Cache dependencies uses: actions/cache@v1 with: - path: ${{ steps.composer-cache.outputs.dir }} + path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} restore-keys: ${{ runner.os }}-composer- diff --git a/__tests__/install.test.ts b/__tests__/install.test.ts index 76616051..5c272af2 100644 --- a/__tests__/install.test.ts +++ b/__tests__/install.test.ts @@ -13,6 +13,11 @@ jest.mock('../src/install', () => ({ const extension_csv: string = process.env['extensions'] || ''; const ini_values_csv: string = process.env['ini-values'] || ''; const coverage_driver: string = process.env['coverage'] || ''; + let tools_csv: string = process.env['tools'] || ''; + const pecl: string = process.env['pecl'] || ''; + if (pecl == 'true') { + tools_csv = 'pecl, ' + tools_csv; + } let script = 'initial script ' + filename + version + os_version; if (extension_csv) { @@ -24,6 +29,9 @@ jest.mock('../src/install', () => ({ if (coverage_driver) { script += 'set coverage driver'; } + if (tools_csv) { + script += 'add_tool'; + } return script; } @@ -36,15 +44,10 @@ jest.mock('../src/install', () => ({ let script = ''; switch (os_version) { case 'darwin': + case 'linux': script = await install.build(os_version + '.sh', version, os_version); script += 'sh script.sh ' + version + ' ' + __dirname; break; - case 'linux': { - const pecl: string = process.env['pecl'] || ''; - script = await install.build(os_version + '.sh', version, os_version); - script += 'sh script.sh ' + version + ' ' + pecl + ' ' + __dirname; - break; - } case 'win32': script = await install.build(os_version + '.sh', version, os_version); script += 'pwsh script.ps1 ' + version + ' ' + __dirname; @@ -73,6 +76,7 @@ function setEnv( extension_csv: string, ini_values_csv: string, coverage_driver: string, + tools: string, pecl: string ): void { process.env['php-version'] = version.toString(); @@ -80,24 +84,25 @@ function setEnv( process.env['extensions'] = extension_csv; process.env['ini-values'] = ini_values_csv; process.env['coverage'] = coverage_driver; + process.env['tools'] = tools; process.env['pecl'] = pecl; } describe('Install', () => { it('Test install on windows', async () => { - setEnv('7.0', 'win32', '', '', '', ''); + setEnv('7.0', 'win32', '', '', '', '', ''); // @ts-ignore let script: string = await install.run(); expect(script).toContain('initial script'); expect(script).toContain('pwsh script.ps1 7.0 ' + __dirname); - setEnv('7.3', 'win32', '', '', '', ''); + setEnv('7.3', 'win32', '', '', '', '', ''); // @ts-ignore script = await install.run(); expect(script).toContain('initial script'); expect(script).toContain('pwsh script.ps1 7.3 ' + __dirname); - setEnv('7.3', 'win32', 'a, b', 'a=b', 'x', ''); + setEnv('7.3', 'win32', 'a, b', 'a=b', 'x', '', ''); // @ts-ignore script = await install.run(); expect(script).toContain('initial script'); @@ -108,39 +113,41 @@ describe('Install', () => { }); it('Test install on linux', async () => { - setEnv('7.3', 'linux', '', '', '', ''); + setEnv('7.3', 'linux', '', '', '', '', ''); // @ts-ignore let script: string = await install.run(); expect(script).toContain('initial script'); expect(script).toContain('sh script.sh 7.3 '); - setEnv('7.3', 'linux', 'a, b', 'a=b', 'x', 'true'); + setEnv('7.3', 'linux', 'a, b', 'a=b', 'x', 'phpunit', 'true'); // @ts-ignore script = await install.run(); expect(script).toContain('initial script'); expect(script).toContain('install extensions'); expect(script).toContain('edit php.ini'); expect(script).toContain('set coverage driver'); - expect(script).toContain('sh script.sh 7.3 true'); + expect(script).toContain('sh script.sh 7.3'); + expect(script).toContain('add_tool'); - setEnv('7.3', 'linux', 'a, b', 'a=b', 'x', 'true'); + setEnv('7.3', 'linux', 'a, b', 'a=b', 'x', 'phpunit', ''); // @ts-ignore script = await install.run(); expect(script).toContain('initial script'); expect(script).toContain('install extensions'); expect(script).toContain('edit php.ini'); expect(script).toContain('set coverage driver'); - expect(script).toContain('sh script.sh 7.3 true'); + expect(script).toContain('sh script.sh 7.3'); + expect(script).toContain('add_tool'); }); it('Test install on darwin', async () => { - setEnv('7.3', 'darwin', '', '', '', ''); + setEnv('7.3', 'darwin', '', '', '', '', ''); // @ts-ignore let script: string = await install.run(); expect(script).toContain('initial script'); expect(script).toContain('sh script.sh 7.3 ' + __dirname); - setEnv('7.3', 'darwin', 'a, b', 'a=b', 'x', ''); + setEnv('7.3', 'darwin', 'a, b', 'a=b', 'x', '', ''); // @ts-ignore script = await install.run(); expect(script).toContain('initial script'); @@ -151,19 +158,19 @@ describe('Install', () => { }); it('Test malformed version inputs', async () => { - setEnv('7.4.1', 'darwin', '', '', '', ''); + setEnv('7.4.1', 'darwin', '', '', '', '', ''); // @ts-ignore let script: string = await install.run(); expect(script).toContain('initial script'); expect(script).toContain('sh script.sh 7.4 ' + __dirname); - setEnv(8.0, 'darwin', '', '', '', ''); + setEnv(8.0, 'darwin', '', '', '', '', ''); // @ts-ignore script = await install.run(); expect(script).toContain('initial script'); expect(script).toContain('sh script.sh 8.0 ' + __dirname); - setEnv(8, 'darwin', '', '', '', ''); + setEnv(8, 'darwin', '', '', '', '', ''); // @ts-ignore script = await install.run(); expect(script).toContain('initial script'); diff --git a/__tests__/tools.test.ts b/__tests__/tools.test.ts new file mode 100644 index 00000000..debb2de9 --- /dev/null +++ b/__tests__/tools.test.ts @@ -0,0 +1,61 @@ +import * as tools from '../src/tools'; + +describe('Tools tests', () => { + it('checking getToolCommand', async () => { + expect(await tools.getToolCommand('linux')).toBe('add_tool '); + expect(await tools.getToolCommand('darwin')).toBe('add_tool '); + expect(await tools.getToolCommand('win32')).toBe('Add-Tool '); + expect(await tools.getToolCommand('fedora')).toContain( + 'Platform fedora is not supported' + ); + }); + + it('checking getPECLCommand', async () => { + expect(await tools.getPECLCommand('linux')).toBe('add_pecl '); + expect(await tools.getPECLCommand('darwin')).toBe('add_pecl '); + expect(await tools.getPECLCommand('win32')).toBe('Add-PECL '); + expect(await tools.getPECLCommand('fedora')).toContain( + 'Platform fedora is not supported' + ); + }); + + it('checking addTools', async () => { + let script: string = await tools.addTools( + 'php-cs-fixer, phpstan, phpunit, pecl', + 'linux' + ); + expect(script).toContain('add_tool https://getcomposer.org/composer.phar'); + expect(script).toContain( + 'add_tool https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/latest/download/php-cs-fixer.phar' + ); + expect(script).toContain( + 'add_tool https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar' + ); + expect(script).toContain('add_tool https://phar.phpunit.de/phpunit.phar'); + expect(script).toContain('add_pecl'); + + script = await tools.addTools('phpcs, phpcbf, phpcpd, phpmd', 'darwin'); + expect(script).toContain('add_tool https://getcomposer.org/composer.phar'); + expect(script).toContain( + 'add_tool https://github.com/squizlabs/PHP_CodeSniffer/releases/latest/download/phpcs.phar' + ); + expect(script).toContain( + 'add_tool https://github.com/squizlabs/PHP_CodeSniffer/releases/latest/download/phpcbf.phar' + ); + expect(script).toContain( + 'add_tool https://github.com/sebastianbergmann/phpcpd/releases/latest/download/phpcpd.phar' + ); + expect(script).toContain( + 'add_tool https://github.com/phpmd/phpmd/releases/latest/download/phpmd.phar' + ); + + script = await tools.addTools( + 'codeception, deployer, prestissimo, phpmd, does_not_exit', + 'win32' + ); + expect(script).toContain('Add-Tool https://getcomposer.org/composer.phar'); + expect(script).toContain('Add-Tool https://deployer.org/deployer.phar'); + expect(script).toContain('composer global require hirak/prestissimo'); + expect(script).toContain('Tool does_not_exit is not supported'); + }); +}); diff --git a/__tests__/utils.test.ts b/__tests__/utils.test.ts index 39aa3636..59dcb80e 100644 --- a/__tests__/utils.test.ts +++ b/__tests__/utils.test.ts @@ -87,13 +87,13 @@ describe('Utils tests', () => { }); it('checking INIArray', async () => { - expect(await utils.INIArray('a=1, b=2, c=3')).toEqual([ + expect(await utils.CSVArray('a=1, b=2, c=3')).toEqual([ 'a=1', 'b=2', 'c=3' ]); - expect(await utils.INIArray('')).toEqual([]); - expect(await utils.INIArray(' ')).toEqual([]); + expect(await utils.CSVArray('')).toEqual([]); + expect(await utils.CSVArray(' ')).toEqual([]); }); it('checking log', async () => { diff --git a/action.yml b/action.yml index 673c7e8b..70ab7a44 100644 --- a/action.yml +++ b/action.yml @@ -17,8 +17,8 @@ inputs: coverage: description: 'Setup code coverage driver.' required: false - pecl: - description: 'Setup PECL on ubuntu' + tools: + description: 'Setup popular tools globally.' required: false # Deprecated options, do not use. Will not be supported after February 1, 2020. extension-csv: @@ -29,6 +29,10 @@ inputs: description: 'Deprecated! Use ini-values instead.' deprecationMessage: 'The ini-values-csv property will not be supported after February 1, 2020. Use ini-values instead.' required: false + pecl: + description: 'Deprecated! Use tools instead to setup PECL.' + deprecationMessage: 'The pecl property will not be supported after February 1, 2020. Specify pecl in tools instead.' + required: false runs: using: 'node12' main: 'dist/index.js' diff --git a/dist/index.js b/dist/index.js index fdcdabc9..d7e4a7d6 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1172,36 +1172,42 @@ function extensionArray(extension_csv) { case ' ': return []; default: - return extension_csv.split(',').map(function (extension) { + return extension_csv + .split(',') + .map(function (extension) { return extension .trim() .replace('php-', '') .replace('php_', ''); - }); + }) + .filter(Boolean); } }); } exports.extensionArray = extensionArray; /** - * Function to break ini values csv into an array + * Function to break csv into an array * - * @param ini_values_csv + * @param values_csv * @constructor */ -function INIArray(ini_values_csv) { +function CSVArray(values_csv) { return __awaiter(this, void 0, void 0, function* () { - switch (ini_values_csv) { + switch (values_csv) { case '': case ' ': return []; default: - return ini_values_csv.split(',').map(function (ini_value) { - return ini_value.trim(); - }); + return values_csv + .split(',') + .map(function (value) { + return value.trim(); + }) + .filter(Boolean); } }); } -exports.INIArray = INIArray; +exports.CSVArray = CSVArray; /** * Function to get prefix required to load an extension. * @@ -1524,6 +1530,165 @@ function getState(name) { exports.getState = getState; //# sourceMappingURL=core.js.map +/***/ }), + +/***/ 534: +/***/ (function(__unusedmodule, exports, __webpack_require__) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; + result["default"] = mod; + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +const utils = __importStar(__webpack_require__(163)); +function getToolCommand(os_version) { + return __awaiter(this, void 0, void 0, function* () { + switch (os_version) { + case 'linux': + case 'darwin': + return 'add_tool '; + case 'win32': + return 'Add-Tool '; + default: + return yield utils.log('Platform ' + os_version + ' is not supported', os_version, 'error'); + } + }); +} +exports.getToolCommand = getToolCommand; +function getPECLCommand(os_version) { + return __awaiter(this, void 0, void 0, function* () { + switch (os_version) { + case 'linux': + case 'darwin': + return 'add_pecl '; + case 'win32': + return 'Add-PECL '; + default: + return yield utils.log('Platform ' + os_version + ' is not supported', os_version, 'error'); + } + }); +} +exports.getPECLCommand = getPECLCommand; +/** + * Setup tools + * + * @param tool_csv + * @param os_version + */ +function addTools(tools_csv, os_version) { + return __awaiter(this, void 0, void 0, function* () { + let script = yield utils.stepLog('Setup Tools', os_version); + let tools = yield utils.CSVArray(tools_csv); + tools = tools.filter(tool => tool !== 'composer'); + tools.unshift('composer'); + yield utils.asyncForEach(tools, function (tool) { + return __awaiter(this, void 0, void 0, function* () { + script += '\n'; + switch (tool) { + case 'php-cs-fixer': + script += + (yield getToolCommand(os_version)) + + 'https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/latest/download/php-cs-fixer.phar' + + ' ' + + 'php-cs-fixer'; + break; + case 'phpcs': + script += + (yield getToolCommand(os_version)) + + 'https://github.com/squizlabs/PHP_CodeSniffer/releases/latest/download/phpcs.phar' + + ' ' + + 'phpcs'; + break; + case 'phpcbf': + script += + (yield getToolCommand(os_version)) + + 'https://github.com/squizlabs/PHP_CodeSniffer/releases/latest/download/phpcbf.phar' + + ' ' + + 'phpcbf'; + break; + case 'phpcpd': + script += + (yield getToolCommand(os_version)) + + 'https://github.com/sebastianbergmann/phpcpd/releases/latest/download/phpcpd.phar' + + ' ' + + 'phpcpd'; + break; + case 'phpstan': + script += + (yield getToolCommand(os_version)) + + 'https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar' + + ' ' + + 'phpstan'; + break; + case 'phpmd': + script += + (yield getToolCommand(os_version)) + + 'https://github.com/phpmd/phpmd/releases/latest/download/phpmd.phar' + + ' ' + + 'phpmd'; + break; + case 'composer': + script += + (yield getToolCommand(os_version)) + + 'https://getcomposer.org/composer.phar' + + ' ' + + 'composer'; + break; + case 'codeception': + script += + (yield getToolCommand(os_version)) + + 'https://codeception.com/codecept.phar' + + ' ' + + 'codeception'; + break; + case 'phpunit': + script += + (yield getToolCommand(os_version)) + + 'https://phar.phpunit.de/phpunit.phar' + + ' ' + + 'phpunit'; + break; + case 'deployer': + script += + (yield getToolCommand(os_version)) + + 'https://deployer.org/deployer.phar' + + ' ' + + 'deployer'; + break; + case 'prestissimo': + script += + 'composer global require hirak/prestissimo' + + (yield utils.suppressOutput(os_version)); + break; + case 'pecl': + script += yield getPECLCommand(os_version); + break; + default: + script += yield utils.log('Tool ' + tool + ' is not supported', os_version, 'error'); + break; + } + }); + }); + return script; + }); +} +exports.addTools = addTools; + + /***/ }), /***/ 614: @@ -1714,7 +1879,7 @@ const utils = __importStar(__webpack_require__(163)); */ function addINIValuesUnix(ini_values_csv) { return __awaiter(this, void 0, void 0, function* () { - const ini_values = yield utils.INIArray(ini_values_csv); + const ini_values = yield utils.CSVArray(ini_values_csv); let script = '\n'; yield utils.asyncForEach(ini_values, function (line) { return __awaiter(this, void 0, void 0, function* () { @@ -1733,7 +1898,7 @@ exports.addINIValuesUnix = addINIValuesUnix; */ function addINIValuesWindows(ini_values_csv) { return __awaiter(this, void 0, void 0, function* () { - const ini_values = yield utils.INIArray(ini_values_csv); + const ini_values = yield utils.CSVArray(ini_values_csv); let script = '\n'; yield utils.asyncForEach(ini_values, function (line) { return __awaiter(this, void 0, void 0, function* () { @@ -1812,6 +1977,7 @@ const core = __importStar(__webpack_require__(470)); const config = __importStar(__webpack_require__(641)); const coverage = __importStar(__webpack_require__(635)); const extensions = __importStar(__webpack_require__(911)); +const tools = __importStar(__webpack_require__(534)); const utils = __importStar(__webpack_require__(163)); const matchers = __importStar(__webpack_require__(86)); /** @@ -1829,7 +1995,11 @@ function build(filename, version, os_version) { const ini_values_csv = (yield utils.getInput('ini-values', false)) || (yield utils.getInput('ini-values-csv', false)); const coverage_driver = yield utils.getInput('coverage', false); - const setup_matchers = yield utils.getInput('matchers', false); + const pecl = yield utils.getInput('pecl', false); + let tools_csv = yield utils.getInput('tools', false); + if (pecl == 'true') { + tools_csv = 'pecl, ' + tools_csv; + } let script = yield utils.readScript(filename, version, os_version); if (extension_csv) { script += yield extensions.addExtension(extension_csv, version, os_version); @@ -1840,6 +2010,7 @@ function build(filename, version, os_version) { if (coverage_driver) { script += yield coverage.addCoverage(coverage_driver, version, os_version); } + script += yield tools.addTools(tools_csv, os_version); return yield utils.writeScript(filename, script); }); } @@ -1857,15 +2028,10 @@ function run() { let script_path = ''; switch (os_version) { case 'darwin': + case 'linux': script_path = yield build(os_version + '.sh', version, os_version); yield exec_1.exec('sh ' + script_path + ' ' + version + ' ' + __dirname); break; - case 'linux': { - const pecl = yield utils.getInput('pecl', false); - script_path = yield build(os_version + '.sh', version, os_version); - yield exec_1.exec('sh ' + script_path + ' ' + version + ' ' + pecl); - break; - } case 'win32': script_path = yield build('win32.ps1', version, os_version); yield exec_1.exec('pwsh ' + script_path + ' ' + version + ' ' + __dirname); diff --git a/src/config.ts b/src/config.ts index a8cfe4af..66c209ba 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,7 +8,7 @@ import * as utils from './utils'; export async function addINIValuesUnix( ini_values_csv: string ): Promise { - const ini_values: Array = await utils.INIArray(ini_values_csv); + const ini_values: Array = await utils.CSVArray(ini_values_csv); let script = '\n'; await utils.asyncForEach(ini_values, async function(line: string) { script += @@ -25,7 +25,7 @@ export async function addINIValuesUnix( export async function addINIValuesWindows( ini_values_csv: string ): Promise { - const ini_values: Array = await utils.INIArray(ini_values_csv); + const ini_values: Array = await utils.CSVArray(ini_values_csv); let script = '\n'; await utils.asyncForEach(ini_values, async function(line: string) { script += diff --git a/src/install.ts b/src/install.ts index c0b8f97f..eccc25d7 100644 --- a/src/install.ts +++ b/src/install.ts @@ -3,6 +3,7 @@ import * as core from '@actions/core'; import * as config from './config'; import * as coverage from './coverage'; import * as extensions from './extensions'; +import * as tools from './tools'; import * as utils from './utils'; import * as matchers from './matchers'; @@ -26,7 +27,11 @@ export async function build( (await utils.getInput('ini-values', false)) || (await utils.getInput('ini-values-csv', false)); const coverage_driver: string = await utils.getInput('coverage', false); - const setup_matchers: string = await utils.getInput('matchers', false); + const pecl: string = await utils.getInput('pecl', false); + let tools_csv: string = await utils.getInput('tools', false); + if (pecl == 'true') { + tools_csv = 'pecl, ' + tools_csv; + } let script: string = await utils.readScript(filename, version, os_version); if (extension_csv) { @@ -38,6 +43,7 @@ export async function build( if (coverage_driver) { script += await coverage.addCoverage(coverage_driver, version, os_version); } + script += await tools.addTools(tools_csv, os_version); return await utils.writeScript(filename, script); } @@ -54,15 +60,10 @@ export async function run(): Promise { let script_path = ''; switch (os_version) { case 'darwin': + case 'linux': script_path = await build(os_version + '.sh', version, os_version); await exec('sh ' + script_path + ' ' + version + ' ' + __dirname); break; - case 'linux': { - const pecl: string = await utils.getInput('pecl', false); - script_path = await build(os_version + '.sh', version, os_version); - await exec('sh ' + script_path + ' ' + version + ' ' + pecl); - break; - } case 'win32': script_path = await build('win32.ps1', version, os_version); await exec('pwsh ' + script_path + ' ' + version + ' ' + __dirname); diff --git a/src/scripts/darwin.sh b/src/scripts/darwin.sh index b3a78a36..d7421287 100644 --- a/src/scripts/darwin.sh +++ b/src/scripts/darwin.sh @@ -47,11 +47,27 @@ remove_extension() { sudo rm -rf "$ext_dir"/"$1".so >/dev/null 2>&1 } +# Function to setup a remote tool +add_tool() { + url=$1 + tool=$2 + if [ ! -e /usr/local/bin/"$tool" ]; then + rm -rf /usr/local/bin/"${tool:?}" + fi + sudo curl -o /usr/local/bin/"$tool" -L "$url" >/dev/null 2>&1 + sudo chmod a+x /usr/local/bin/"$tool" + add_log "$tick" "$tool" "Added" +} + +add_pecl() { + add_log "$tick" "PECL" "Added" +} + # Function to setup PHP and composer setup_php_and_composer() { export HOMEBREW_NO_INSTALL_CLEANUP=TRUE brew tap shivammathur/homebrew-php >/dev/null 2>&1 - brew install shivammathur/php/php@"$version" composer >/dev/null 2>&1 + brew install shivammathur/php/php@"$version" >/dev/null 2>&1 brew link --force --overwrite php@"$version" >/dev/null 2>&1 } @@ -61,7 +77,7 @@ cross="✗" version=$1 # Setup PHP and composer -step_log "Setup PHP and Composer" +step_log "Setup PHP" setup_php_and_composer ini_file=$(php -d "date.timezone=UTC" --ini | grep "Loaded Configuration" | sed -e "s|.*:s*||" | sed "s/ //g") echo "date.timezone=UTC" >> "$ini_file" @@ -70,4 +86,3 @@ sudo chmod 777 "$ini_file" mkdir -p "$(pecl config-get ext_dir)" semver=$(php -v | head -n 1 | cut -f 2 -d ' ') add_log "$tick" "PHP" "Installed PHP $semver" -add_log "$tick" "Composer" "Installed" diff --git a/src/scripts/linux.sh b/src/scripts/linux.sh index d22c3259..b65490c0 100644 --- a/src/scripts/linux.sh +++ b/src/scripts/linux.sh @@ -43,11 +43,23 @@ add_extension() { # Function to remove extensions remove_extension() { extension=$1 - if [ -e /etc/php/"$version"/mods-available/$1.ini ]; then - sudo phpdismod -v "$version" $1 + if [ -e /etc/php/"$version"/mods-available/"$extension".ini ]; then + sudo phpdismod -v "$version" "$extension" fi - sudo sed -i "/$1/d" "$ini_file" - sudo DEBIAN_FRONTEND=noninteractive apt-get remove php-$1 -y >/dev/null 2>&1 + sudo sed -i "/$extension/d" "$ini_file" + sudo DEBIAN_FRONTEND=noninteractive apt-get remove php-"$extension" -y >/dev/null 2>&1 +} + +# Function to setup a remote tool +add_tool() { + url=$1 + tool=$2 + if [ ! -e /usr/local/bin/"$tool" ]; then + rm -rf /usr/local/bin/"${tool:?}" + fi + sudo curl -o /usr/local/bin/"$tool" -L "$url" >/dev/null 2>&1 + sudo chmod a+x /usr/local/bin/"$tool" + add_log "$tick" "$tool" "Added" } # Function to setup the nightly build from master branch @@ -64,30 +76,18 @@ setup_master() { } # Function to setup PECL -setup_pecl() { +add_pecl() { + update_ppa $apt_install php"$version"-dev php"$version"-xml >/dev/null 2>&1 sudo update-alternatives --set php-config /usr/bin/php-config"$version" >/dev/null 2>&1 sudo update-alternatives --set phpize /usr/bin/phpize"$version" >/dev/null 2>&1 wget https://github.com/pear/pearweb_phars/raw/master/install-pear-nozlib.phar >/dev/null 2>&1 sudo php install-pear-nozlib.phar >/dev/null 2>&1 + sudo rm -rf install-pear-nozlib.phar >/dev/null 2>&1 sudo pear config-set php_ini "$ini_file" >/dev/null 2>&1 sudo pear config-set auto_discover 1 >/dev/null 2>&1 sudo pear channel-update pear.php.net >/dev/null 2>&1 -} - -# Function to setup composer -setup_composer() { - if [ ! -e "/usr/bin/composer" ]; then - curl -s -L https://getcomposer.org/installer >composer-setup.php - if [ "$(curl -s https://composer.github.io/installer.sig)" != "$(php -r "echo hash_file('sha384', 'composer-setup.php');")" ]; then - echo >&2 'ERROR: Invalid installer signature' - else - export COMPOSER_ALLOW_SUPERUSER=1 - sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer - fi - rm composer-setup.php - fi - add_log "$tick" "Composer" "Installed" + add_log "$tick" "PECL" "Added" } # Function to switch versions of PHP binaries @@ -104,13 +104,12 @@ tick="✓" cross="✗" ppa_updated="false" version=$1 -pecl=$2 apt_install="sudo DEBIAN_FRONTEND=noninteractive apt-fast install -y" existing_version=$(php-config --version | cut -c 1-3) semver=$(php -v | head -n 1 | cut -f 2 -d ' ' | cut -f 1 -d '-') # Setup PHP -step_log "Setup PHP and Composer" +step_log "Setup PHP" sudo mkdir -p /var/run sudo mkdir -p /run/php @@ -150,13 +149,3 @@ ini_file=$(php --ini | grep "Loaded Configuration" | sed -e "s|.*:s*||" | sed "s ext_dir=$(php -i | grep "extension_dir => /usr" | sed -e "s|.*=> s*||") sudo chmod 777 "$ini_file" add_log "$tick" "PHP" "$status" - -# Setup PECL -if [ "$pecl" = "true" ]; then - update_ppa - setup_pecl - add_log "$tick" "PECL" "Installed" -fi - -# Setup composer -setup_composer diff --git a/src/scripts/win32.ps1 b/src/scripts/win32.ps1 index 66e5849c..3e8bd4ca 100644 --- a/src/scripts/win32.ps1 +++ b/src/scripts/win32.ps1 @@ -75,6 +75,38 @@ Function Remove-Extension() { } } +# Function to setup a remote tool +Function Add-Tool() { + Param ( + [Parameter(Position = 0, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $url, + [Parameter(Position = 1, Mandatory = $true)] + [ValidateNotNull()] + [ValidateLength(1, [int]::MaxValue)] + [string] + $tool + ) + if (Test-Path $php_dir\$tool) { + Remove-Item $php_dir\$tool + } + Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $php_dir\$tool > $null 2>&1 + $bat_content = @() + $bat_content += "@ECHO off" + $bat_content += "setlocal DISABLEDELAYEDEXPANSION" + $bat_content += "SET BIN_TARGET=%~dp0/" + $tool + $bat_content += "php %BIN_TARGET% %*" + Set-Content -Path $php_dir\$tool.bat -Value $bat_content + Add-Content -Path $PsHome\profile.ps1 -Value "New-Alias $tool $php_dir\$tool.bat" + Add-Log $tick $tool "Added" +} + +Function Add-PECL() { + Add-Log $tick "PECL" "Use extensions input or Install-PhpExtension to setup PECL extensions on windows" +} + # Variables $tick = ([char]8730) $cross = ([char]10007) @@ -96,7 +128,7 @@ if (Test-Path -LiteralPath $php_dir -PathType Container) { catch { } } -Step-Log "Setup PHP and Composer" +Step-Log "Setup PHP" if ($null -eq $installed -or -not("$($installed.Version).".StartsWith(($version -replace '^(\d+(\.\d+)*).*', '$1.')))) { if ($version -lt '7.0') { Install-Module -Name VcRedist -Force @@ -123,6 +155,3 @@ if ($version -eq 'master') { Set-PhpIniKey -Key 'opcache.jit' -Value '1235' -Path $php_dir } Add-Log $tick "PHP" $status - -Install-Composer -Scope System -Path $php_dir -PhpPath $php_dir -Add-Log $tick "Composer" "Installed" diff --git a/src/tools.ts b/src/tools.ts new file mode 100644 index 00000000..41805e77 --- /dev/null +++ b/src/tools.ts @@ -0,0 +1,141 @@ +import * as utils from './utils'; + +export async function getToolCommand(os_version: string): Promise { + switch (os_version) { + case 'linux': + case 'darwin': + return 'add_tool '; + case 'win32': + return 'Add-Tool '; + default: + return await utils.log( + 'Platform ' + os_version + ' is not supported', + os_version, + 'error' + ); + } +} + +export async function getPECLCommand(os_version: string): Promise { + switch (os_version) { + case 'linux': + case 'darwin': + return 'add_pecl '; + case 'win32': + return 'Add-PECL '; + default: + return await utils.log( + 'Platform ' + os_version + ' is not supported', + os_version, + 'error' + ); + } +} + +/** + * Setup tools + * + * @param tool_csv + * @param os_version + */ +export async function addTools( + tools_csv: string, + os_version: string +): Promise { + let script = await utils.stepLog('Setup Tools', os_version); + let tools: Array = await utils.CSVArray(tools_csv); + tools = tools.filter(tool => tool !== 'composer'); + tools.unshift('composer'); + await utils.asyncForEach(tools, async function(tool: string) { + script += '\n'; + switch (tool) { + case 'php-cs-fixer': + script += + (await getToolCommand(os_version)) + + 'https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/latest/download/php-cs-fixer.phar' + + ' ' + + 'php-cs-fixer'; + break; + case 'phpcs': + script += + (await getToolCommand(os_version)) + + 'https://github.com/squizlabs/PHP_CodeSniffer/releases/latest/download/phpcs.phar' + + ' ' + + 'phpcs'; + break; + case 'phpcbf': + script += + (await getToolCommand(os_version)) + + 'https://github.com/squizlabs/PHP_CodeSniffer/releases/latest/download/phpcbf.phar' + + ' ' + + 'phpcbf'; + break; + case 'phpcpd': + script += + (await getToolCommand(os_version)) + + 'https://github.com/sebastianbergmann/phpcpd/releases/latest/download/phpcpd.phar' + + ' ' + + 'phpcpd'; + break; + case 'phpstan': + script += + (await getToolCommand(os_version)) + + 'https://github.com/phpstan/phpstan/releases/latest/download/phpstan.phar' + + ' ' + + 'phpstan'; + break; + case 'phpmd': + script += + (await getToolCommand(os_version)) + + 'https://github.com/phpmd/phpmd/releases/latest/download/phpmd.phar' + + ' ' + + 'phpmd'; + break; + case 'composer': + script += + (await getToolCommand(os_version)) + + 'https://getcomposer.org/composer.phar' + + ' ' + + 'composer'; + break; + case 'codeception': + script += + (await getToolCommand(os_version)) + + 'https://codeception.com/codecept.phar' + + ' ' + + 'codeception'; + break; + case 'phpunit': + script += + (await getToolCommand(os_version)) + + 'https://phar.phpunit.de/phpunit.phar' + + ' ' + + 'phpunit'; + break; + case 'deployer': + script += + (await getToolCommand(os_version)) + + 'https://deployer.org/deployer.phar' + + ' ' + + 'deployer'; + break; + case 'prestissimo': + script += + 'composer global require hirak/prestissimo' + + (await utils.suppressOutput(os_version)); + break; + case 'pecl': + script += await getPECLCommand(os_version); + break; + default: + script += await utils.log( + 'Tool ' + tool + ' is not supported', + os_version, + 'error' + ); + break; + } + }); + + return script; +} diff --git a/src/utils.ts b/src/utils.ts index ec17b782..af305504 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -191,30 +191,36 @@ export async function extensionArray( case ' ': return []; default: - return extension_csv.split(',').map(function(extension: string) { - return extension - .trim() - .replace('php-', '') - .replace('php_', ''); - }); + return extension_csv + .split(',') + .map(function(extension: string) { + return extension + .trim() + .replace('php-', '') + .replace('php_', ''); + }) + .filter(Boolean); } } /** - * Function to break ini values csv into an array + * Function to break csv into an array * - * @param ini_values_csv + * @param values_csv * @constructor */ -export async function INIArray(ini_values_csv: string): Promise> { - switch (ini_values_csv) { +export async function CSVArray(values_csv: string): Promise> { + switch (values_csv) { case '': case ' ': return []; default: - return ini_values_csv.split(',').map(function(ini_value: string) { - return ini_value.trim(); - }); + return values_csv + .split(',') + .map(function(value: string) { + return value.trim(); + }) + .filter(Boolean); } }