mirror of
https://github.com/shivammathur/setup-php.git
synced 2026-05-15 01:50:57 +07:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c071dfe9d | ||
|
|
eeef37e059 | ||
|
|
0dc33069a3 | ||
|
|
680a983990 | ||
|
|
694649a4a3 | ||
|
|
46a991b6aa | ||
|
|
7748c24380 | ||
|
|
ac9c953234 | ||
|
|
7729e411ec | ||
|
|
af2322b95c | ||
|
|
45e37a5311 | ||
|
|
690cb7c9d8 | ||
|
|
b2cf73f5fa | ||
|
|
64e2975255 | ||
|
|
106fd0866c | ||
|
|
44724c9282 | ||
|
|
2fa35d2e4e | ||
|
|
29e04e0a1d | ||
|
|
ea13793c13 | ||
|
|
fd580061e0 | ||
|
|
90d81e2adc | ||
|
|
93cb3149d2 | ||
|
|
accd6127cb | ||
|
|
a5c2146f3f | ||
|
|
6a1d559c57 | ||
|
|
076a5e3f0d | ||
|
|
00c8f84a71 | ||
|
|
c033e31e7c | ||
|
|
bc6f40a11a | ||
|
|
fe26b509d7 | ||
|
|
e67ff94e49 | ||
|
|
4e89813b4b | ||
|
|
a33066c001 | ||
|
|
f1643fd598 | ||
|
|
e167f5c259 | ||
|
|
45158d762a | ||
|
|
8724c1dcc1 | ||
|
|
a1e0f566a8 | ||
|
|
650d05dc41 | ||
|
|
746e1a46d1 | ||
|
|
a8ca9e3783 | ||
|
|
769a4a81fd | ||
|
|
d042aafd13 | ||
|
|
f97ca00780 | ||
|
|
3aeeb03660 | ||
|
|
57e8183dae | ||
|
|
5e98c022f7 | ||
|
|
f0b3fd9afe | ||
|
|
1eee54fe48 | ||
|
|
341bc9e176 | ||
|
|
185f9de395 | ||
|
|
46cb5030ab | ||
|
|
6300a313a9 | ||
|
|
b7741bd785 | ||
|
|
109ae4d1c0 | ||
|
|
871ff01b2b | ||
|
|
f0e37f9e90 | ||
|
|
46ae35f333 | ||
|
|
f89a301251 | ||
|
|
5efa2a774e | ||
|
|
f72fc99524 | ||
|
|
c84edb415f | ||
|
|
4dda6da925 | ||
|
|
c14319add5 | ||
|
|
5ba12107fc | ||
|
|
8bd624e171 | ||
|
|
3dfaca4ee1 |
4
.github/workflows/docs.yml
vendored
4
.github/workflows/docs.yml
vendored
@@ -88,7 +88,7 @@ jobs:
|
||||
Remove-Item "$env:file.all" -Force
|
||||
Remove-Item "$env:file.builtin" -Force
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@v5
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: lists-php${{ matrix.php-versions }}-${{ matrix.operating-system }}.md
|
||||
path: php${{ matrix.php-versions }}-${{ matrix.operating-system }}.md
|
||||
@@ -105,7 +105,7 @@ jobs:
|
||||
with:
|
||||
repository: ${{ github.repository }}.wiki
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v6
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
path: ${{ github.workspace }}/lists
|
||||
pattern: lists-*
|
||||
|
||||
6
.github/workflows/node.yml
vendored
6
.github/workflows/node.yml
vendored
@@ -33,10 +33,10 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
- name: Setup Node.js 20.x
|
||||
- name: Setup Node.js 24.x
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 20.x
|
||||
node-version: 24.x
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
run: npm audit
|
||||
|
||||
- name: Send Coverage
|
||||
uses: codecov/codecov-action@v5
|
||||
uses: codecov/codecov-action@v6
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: coverage/lcov.info
|
||||
|
||||
2
.github/workflows/php.yml
vendored
2
.github/workflows/php.yml
vendored
@@ -50,7 +50,7 @@ jobs:
|
||||
key: ${{ env.key }}
|
||||
|
||||
- name: Cache extensions
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.cache-env.outputs.dir }}
|
||||
key: ${{ steps.cache-env.outputs.key }}
|
||||
|
||||
5
.github/workflows/publish.yml
vendored
5
.github/workflows/publish.yml
vendored
@@ -16,6 +16,7 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
id-token: write
|
||||
steps:
|
||||
- name: Checkout release
|
||||
if: github.event_name != 'workflow_dispatch'
|
||||
@@ -30,7 +31,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: '20.x'
|
||||
node-version: '24.x'
|
||||
registry-url: https://registry.npmjs.org
|
||||
|
||||
- name: Install dependencies and add lib
|
||||
@@ -42,8 +43,6 @@ jobs:
|
||||
- name: Publish to NPM
|
||||
if: "!contains(github.event.inputs.skip, 'skip-npm')"
|
||||
run: npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
- name: Change to GitHub Packages registry
|
||||
uses: actions/setup-node@v6
|
||||
|
||||
27
README.md
27
README.md
@@ -74,13 +74,13 @@ Both `GitHub-hosted` and `self-hosted` runners are supported by `setup-php` on t
|
||||
| Ubuntu 22.04 | x86_64 | `ubuntu-22.04` | `PHP 8.1` |
|
||||
| Ubuntu 24.04 | aarch64 | `ubuntu-24.04-arm` | `PHP 8.3` |
|
||||
| Ubuntu 22.04 | aarch64 | `ubuntu-22.04-arm` | `PHP 8.1` |
|
||||
| Windows Server 2025 | x64 | `windows-2025` | `PHP 8.3` |
|
||||
| Windows Server 2022 | x64 | `windows-latest` or `windows-2022` | `PHP 8.3` |
|
||||
| Windows Server 2025 | x64 | `windows-2025` | `PHP 8.5` |
|
||||
| Windows Server 2022 | x64 | `windows-latest` or `windows-2022` | `PHP 8.5` |
|
||||
| macOS Tahoe 26.x | arm64 | `macos-26` | - |
|
||||
| macOS Sequoia 15.x | arm64 | `macos-latest` or `macos-15` | - |
|
||||
| macOS Sonoma 14.x | arm64 | `macos-14` | - |
|
||||
| macOS Sequoia 15.x | x86_64 | `macos-15-intel` | `PHP 8.3` |
|
||||
| macOS Ventura 13.x | x86_64 | `macos-13` | `PHP 8.3` |
|
||||
| macOS Tahoe 26.x | x86_64 | `macos-26-intel` | `PHP 8.5` |
|
||||
| macOS Sequoia 15.x | x86_64 | `macos-15-intel` | `PHP 8.5` |
|
||||
|
||||
### Self-Hosted Runners
|
||||
|
||||
@@ -121,9 +121,9 @@ On all supported OS/Platforms, the following PHP versions can be set up as per t
|
||||
| `7.3` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` |
|
||||
| `7.4` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` |
|
||||
| `8.0` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` |
|
||||
| `8.1` | `Stable` | `Security fixes only` | `GitHub-hosted`, `self-hosted` |
|
||||
| `8.1` | `Stable` | `End of life` | `GitHub-hosted`, `self-hosted` |
|
||||
| `8.2` | `Stable` | `Security fixes only` | `GitHub-hosted`, `self-hosted` |
|
||||
| `8.3` | `Stable` | `Active` | `GitHub-hosted`, `self-hosted` |
|
||||
| `8.3` | `Stable` | `Security fixes only` | `GitHub-hosted`, `self-hosted` |
|
||||
| `8.4` | `Stable` | `Active` | `GitHub-hosted`, `self-hosted` |
|
||||
| `8.5` | `Stable` | `Active` | `GitHub-hosted`, `self-hosted` |
|
||||
| `8.6` | `Nightly` | `In development` | `GitHub-hosted`, `self-hosted` |
|
||||
@@ -268,7 +268,7 @@ These tools can be set up globally using the `tools` input. It accepts a string
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.5'
|
||||
tools: composer:v1
|
||||
tools: composer:v2
|
||||
```
|
||||
|
||||
- If you do not use composer in your workflow, you can specify `tools: none` to skip it.
|
||||
@@ -950,11 +950,12 @@ Examples of using `setup-php` with various PHP frameworks and packages.
|
||||
| Framework/Package | Runs on | Workflow |
|
||||
|----------------------------------------|---------------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| Blackfire | `macOS`, `ubuntu` and `windows` | [blackfire.yml](./examples/blackfire.yml "GitHub Action using Blackfire") |
|
||||
| Blackfire Player | `macOS`, `ubuntu` and `windows` | [blackfire-player.yml](./examples/blackfire-player.yml "GitHub Action using Blackfire Player") |
|
||||
| Blackfire Player | `macOS` and `ubuntu` | [blackfire-player.yml](./examples/blackfire-player.yml "GitHub Action using Blackfire Player") |
|
||||
| CakePHP with `MySQL` and `Redis` | `ubuntu` | [cakephp-mysql.yml](./examples/cakephp-mysql.yml "GitHub Action for CakePHP with MySQL and Redis") |
|
||||
| CakePHP with `PostgreSQL` and `Redis` | `ubuntu` | [cakephp-postgres.yml](./examples/cakephp-postgres.yml "GitHub Action for CakePHP with Postgres and Redis") |
|
||||
| CakePHP without services | `macOS`, `ubuntu` and `windows` | [cakephp.yml](./examples/cakephp.yml "GitHub Action for CakePHP without services") |
|
||||
| CodeIgniter | `macOS`, `ubuntu` and `windows` | [codeigniter.yml](./examples/codeigniter.yml "GitHub Action for CodeIgniter") |
|
||||
| Drupal 11 (Composer-managed) | `ubuntu` | [drupal.yml](./examples/drupal.yml "GitHub Action for Drupal 11 composer-managed projects") |
|
||||
| Laminas MVC | `macOS`, `ubuntu` and `windows` | [laminas-mvc.yml](./examples/laminas-mvc.yml "GitHub Action for Laminas Framework MVC Projects") |
|
||||
| Laravel with `MySQL` and `Redis` | `ubuntu` | [laravel-mysql.yml](./examples/laravel-mysql.yml "GitHub Action for Laravel with MySQL and Redis") |
|
||||
| Laravel with `PostgreSQL` and `Redis` | `ubuntu` | [laravel-postgres.yml](./examples/laravel-postgres.yml "GitHub Action for Laravel with PostgreSQL and Redis") |
|
||||
@@ -964,14 +965,16 @@ Examples of using `setup-php` with various PHP frameworks and packages.
|
||||
| Lumen without services | `macOS`, `ubuntu` and `windows` | [lumen.yml](./examples/lumen.yml "GitHub Action for Lumen without services") |
|
||||
| Phalcon with `MySQL` | `ubuntu` | [phalcon-mysql.yml](./examples/phalcon-mysql.yml "GitHub Action for Phalcon with MySQL") |
|
||||
| Phalcon with `PostgreSQL` | `ubuntu` | [phalcon-postgres.yml](./examples/phalcon-postgres.yml "GitHub Action for Phalcon with PostgreSQL") |
|
||||
| Roots/bedrock | `ubuntu` | [bedrock.yml](./examples/bedrock.yml "GitHub Action for Wordpress Development using @roots/bedrock") |
|
||||
| Roots/sage | `ubuntu` | [sage.yml](./examples/sage.yml "GitHub Action for Wordpress Development using @roots/sage") |
|
||||
| Slim Framework | `macOS`, `ubuntu` and `windows` | [slim-framework.yml](./examples/slim-framework.yml "GitHub Action for Slim Framework") |
|
||||
| Symfony with `MySQL` | `ubuntu` | [symfony-mysql.yml](./examples/symfony-mysql.yml "GitHub Action for Symfony with MySQL") |
|
||||
| Symfony with `PostgreSQL` | `ubuntu` | [symfony-postgres.yml](./examples/symfony-postgres.yml "GitHub Action for Symfony with PostgreSQL") |
|
||||
| Symfony without services | `macOS`, `ubuntu` and `windows` | [symfony.yml](./examples/symfony.yml "GitHub Action for Symfony without services") |
|
||||
| Yii2 Starter Kit with `MySQL` | `ubuntu` | [yii2-mysql.yml](./examples/yii2-mysql.yml "GitHub Action for Yii2 Starter Kit with MySQL") |
|
||||
| Yii2 Starter Kit with `PostgreSQL` | `ubuntu` | [yii2-postgres.yml](./examples/yii2-postgres.yml "GitHub Action for Yii2 Starter Kit with PostgreSQL") |
|
||||
| WordPress plugin | `ubuntu` | [wordpress.yml](./examples/wordpress.yml "GitHub Action for WordPress plugins") |
|
||||
| WordPress with Roots/Bedrock | `ubuntu` | [bedrock.yml](./examples/bedrock.yml "GitHub Action for WordPress development using @roots/bedrock") |
|
||||
| WordPress with Roots/Sage | `ubuntu` | [sage.yml](./examples/sage.yml "GitHub Action for WordPress development using @roots/sage") |
|
||||
| Yii3 web application with `MySQL` | `ubuntu` | [yii3-mysql.yml](./examples/yii3-mysql.yml "GitHub Action for Yii3 web application with MySQL") |
|
||||
| Yii3 web application with `PostgreSQL` | `ubuntu` | [yii3-postgres.yml](./examples/yii3-postgres.yml "GitHub Action for Yii3 web application with PostgreSQL") |
|
||||
| Yii3 web application | `ubuntu` and `windows` | [yii3.yml](./examples/yii3.yml "GitHub Action for Yii3 web application") |
|
||||
|
||||
## :bookmark: Versioning
|
||||
|
||||
|
||||
@@ -2,14 +2,18 @@ import * as config from '../src/config';
|
||||
|
||||
describe('Config tests', () => {
|
||||
it.each`
|
||||
ini_values | os | output
|
||||
${'a=b, c=d'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=b\nc=d"'}
|
||||
${'a=b, c=d'} | ${'linux'} | ${'echo "a=b\nc=d" | sudo tee -a "${pecl_file:-${ini_file[@]}}"'}
|
||||
${'a=b, c=d'} | ${'darwin'} | ${'echo "a=b\nc=d" | sudo tee -a "${pecl_file:-${ini_file[@]}}"'}
|
||||
${'a=b & ~c'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=\'b & ~c\'"'}
|
||||
${'a="~(b)"'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=\'~(b)\'"'}
|
||||
${'a="b, c"'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=b, c"'}
|
||||
${'a=b, c=d'} | ${'openbsd'} | ${'Platform openbsd is not supported'}
|
||||
ini_values | os | output
|
||||
${'a=b, c=d'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=b\nc=d"'}
|
||||
${'a=b, c=d'} | ${'linux'} | ${'echo "a=b\nc=d" | sudo tee -a "${pecl_file:-${ini_file[@]}}"'}
|
||||
${'a=b, c=d'} | ${'darwin'} | ${'echo "a=b\nc=d" | sudo tee -a "${pecl_file:-${ini_file[@]}}"'}
|
||||
${'a=b & ~c'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=\'b & ~c\'"'}
|
||||
${'a="~(b)"'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=\'~(b)\'"'}
|
||||
${'a="b, c"'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=b, c"'}
|
||||
${'disable_functions="exec,system"'} | ${'linux'} | ${'echo "disable_functions=exec,system" | sudo tee -a'}
|
||||
${'disable_functions="exec,system"'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "disable_functions=exec,system"'}
|
||||
${'a=$(id)'} | ${'linux'} | ${'echo "a=\'\\$(id)\'"'}
|
||||
${'a=$(id)'} | ${'win32'} | ${'Add-Content "$php_dir\\php.ini" "a=\'`$(id)\'"'}
|
||||
${'a=b, c=d'} | ${'openbsd'} | ${'Platform openbsd is not supported'}
|
||||
`('checking addINIValues on $os', async ({ini_values, os, output}) => {
|
||||
expect(await config.addINIValues(ini_values, os)).toContain(output);
|
||||
});
|
||||
|
||||
106
__tests__/core.test.ts
Normal file
106
__tests__/core.test.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import * as core from '../src/core';
|
||||
|
||||
describe('Core tests', () => {
|
||||
const originalEnv = process.env;
|
||||
const originalExitCode = process.exitCode;
|
||||
let stdoutOutput: string;
|
||||
const originalWrite = process.stdout.write;
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = {...originalEnv};
|
||||
process.exitCode = undefined;
|
||||
stdoutOutput = '';
|
||||
process.stdout.write = jest.fn((chunk: string | Uint8Array): boolean => {
|
||||
stdoutOutput += chunk.toString();
|
||||
return true;
|
||||
}) as unknown as typeof process.stdout.write;
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
process.env = originalEnv;
|
||||
process.exitCode = originalExitCode;
|
||||
process.stdout.write = originalWrite;
|
||||
});
|
||||
|
||||
it('checking issueCommand with no properties', () => {
|
||||
core.issueCommand('warning', {}, 'test message');
|
||||
expect(stdoutOutput).toContain('::warning::test message');
|
||||
});
|
||||
|
||||
it('checking issueCommand with properties', () => {
|
||||
core.issueCommand('error', {file: 'test.ts', line: '10'}, 'error message');
|
||||
expect(stdoutOutput).toContain(
|
||||
'::error file=test.ts,line=10::error message'
|
||||
);
|
||||
});
|
||||
|
||||
it('checking issueCommand escapes special characters in message', () => {
|
||||
core.issueCommand('warning', {}, 'line1\nline2\rline3%percent');
|
||||
expect(stdoutOutput).toContain(
|
||||
'::warning::line1%0Aline2%0Dline3%25percent'
|
||||
);
|
||||
});
|
||||
|
||||
it('checking issueCommand escapes special characters in properties', () => {
|
||||
core.issueCommand('error', {file: 'path:to,file'}, 'message');
|
||||
expect(stdoutOutput).toContain('::error file=path%3Ato%2Cfile::message');
|
||||
});
|
||||
|
||||
it('checking issueCommand with Error object', () => {
|
||||
const error = new Error('test error');
|
||||
core.issueCommand('error', {}, error);
|
||||
expect(stdoutOutput).toContain('::error::Error: test error');
|
||||
});
|
||||
|
||||
it('checking issueCommand filters empty properties', () => {
|
||||
core.issueCommand('warning', {file: 'test.ts', line: ''}, 'message');
|
||||
expect(stdoutOutput).toContain('::warning file=test.ts::message');
|
||||
});
|
||||
|
||||
it('checking error', () => {
|
||||
core.error('error message');
|
||||
expect(stdoutOutput).toContain('::error::error message');
|
||||
});
|
||||
|
||||
it('checking error with Error object', () => {
|
||||
core.error(new Error('error instance'));
|
||||
expect(stdoutOutput).toContain('::error::Error: error instance');
|
||||
});
|
||||
|
||||
it('checking setFailed', () => {
|
||||
core.setFailed('failure message');
|
||||
expect(process.exitCode).toBe(1);
|
||||
expect(stdoutOutput).toContain('::error::failure message');
|
||||
});
|
||||
|
||||
it('checking setFailed with Error object', () => {
|
||||
core.setFailed(new Error('failure error'));
|
||||
expect(process.exitCode).toBe(1);
|
||||
expect(stdoutOutput).toContain('::error::Error: failure error');
|
||||
});
|
||||
|
||||
it('checking getInput returns value', () => {
|
||||
process.env['INPUT_TEST-INPUT'] = 'test value';
|
||||
expect(core.getInput('test-input')).toBe('test value');
|
||||
});
|
||||
|
||||
it('checking getInput trims value', () => {
|
||||
process.env['INPUT_TEST-INPUT'] = ' trimmed ';
|
||||
expect(core.getInput('test-input')).toBe('trimmed');
|
||||
});
|
||||
|
||||
it('checking getInput returns empty string for missing input', () => {
|
||||
expect(core.getInput('missing-input')).toBe('');
|
||||
});
|
||||
|
||||
it('checking getInput throws for required missing input', () => {
|
||||
expect(() => core.getInput('missing-input', true)).toThrow(
|
||||
'Input required and not supplied: missing-input'
|
||||
);
|
||||
});
|
||||
|
||||
it('checking getInput handles spaces in name', () => {
|
||||
process.env['INPUT_INPUT_WITH_SPACES'] = 'spaced value';
|
||||
expect(core.getInput('input with spaces')).toBe('spaced value');
|
||||
});
|
||||
});
|
||||
@@ -21,6 +21,7 @@ describe('Extension tests', () => {
|
||||
${'ibm_db2'} | ${'7.4'} | ${'Add-Ibm ibm_db2'}
|
||||
${'pdo_ibm'} | ${'7.4'} | ${'Add-Ibm pdo_ibm'}
|
||||
${'pecl_http'} | ${'7.4'} | ${'Add-Http'}
|
||||
${'http'} | ${'8.5'} | ${'Add-Http'}
|
||||
${'pdo_sqlsrv'} | ${'7.4'} | ${'Add-Sqlsrv pdo_sqlsrv'}
|
||||
${'phalcon3'} | ${'7.2'} | ${'Add-Phalcon phalcon3'}
|
||||
${'phalcon4'} | ${'7.4'} | ${'Add-Phalcon phalcon4'}
|
||||
@@ -131,7 +132,11 @@ describe('Extension tests', () => {
|
||||
)
|
||||
? `add_${ext_name}`
|
||||
: `add_brew_extension ${formula} ${prefix}`;
|
||||
return [formula, formula === 'phalcon3' ? '7.3' : '7.4', output];
|
||||
return [
|
||||
formula,
|
||||
formula.match(/phalcon3|lua|propro/) ? '7.3' : '8.1',
|
||||
output
|
||||
];
|
||||
});
|
||||
|
||||
it.each(data)(
|
||||
|
||||
@@ -19,7 +19,9 @@ it('checking fetch', async () => {
|
||||
Location: host_url + '/pong'
|
||||
})
|
||||
.get('/pong')
|
||||
.reply(200, 'pong');
|
||||
.reply(200, 'pong')
|
||||
.get('/error')
|
||||
.replyWithError('Network failure');
|
||||
|
||||
let response: Record<string, string> = await fetch.fetch(manifest_url);
|
||||
expect(response.error).toBe(undefined);
|
||||
@@ -36,4 +38,8 @@ it('checking fetch', async () => {
|
||||
response = await fetch.fetch(manifest_url, 'invalid_token');
|
||||
expect(response.error).not.toBe(undefined);
|
||||
expect(response.data).toBe(undefined);
|
||||
|
||||
response = await fetch.fetch(host_url + '/error');
|
||||
expect(response.error).toContain('Fetch error:');
|
||||
expect(response.data).toBe(undefined);
|
||||
});
|
||||
|
||||
@@ -1,43 +1,42 @@
|
||||
import * as fs from 'fs';
|
||||
import * as tools from '../src/tools';
|
||||
import {ToolData, ToolInput} from '../src/tools';
|
||||
|
||||
interface IData {
|
||||
tool: string;
|
||||
version?: string;
|
||||
domain?: string;
|
||||
extension?: string;
|
||||
os?: string;
|
||||
php_version?: string;
|
||||
release?: string;
|
||||
repository?: string;
|
||||
scope?: string;
|
||||
type?: string;
|
||||
fetch_latest?: string;
|
||||
version_parameter?: string;
|
||||
version_prefix?: string;
|
||||
}
|
||||
|
||||
function getData(data: IData): Record<string, string> {
|
||||
function getData(data: Partial<ToolData>): ToolData {
|
||||
const tool = data.tool || 'tool';
|
||||
const version = data.version || '';
|
||||
return {
|
||||
tool: data.tool,
|
||||
version: data.version || '',
|
||||
tool,
|
||||
version,
|
||||
url: data.url || '',
|
||||
domain: data.domain || 'https://example.com',
|
||||
extension: data.extension || '.phar',
|
||||
os: data.os || 'linux',
|
||||
php_version: data.php_version || '7.4',
|
||||
release: data.release || [data.tool, data.version].join(':'),
|
||||
release: data.release || [tool, version].join(':'),
|
||||
repository: data.repository || '',
|
||||
scope: data.scope || 'global',
|
||||
type: data.type || 'phar',
|
||||
fetch_latest: data.fetch_latest || 'false',
|
||||
version_parameter: data.version_parameter || '-V',
|
||||
version_prefix: data.version_prefix || '',
|
||||
github: 'https://github.com',
|
||||
prefix: 'releases',
|
||||
verb: 'download'
|
||||
github: data.github || 'https://github.com',
|
||||
prefix: data.prefix || 'releases',
|
||||
verb: data.verb || 'download',
|
||||
packagist: data.packagist || data.repository || '',
|
||||
function: data.function,
|
||||
alias: data.alias,
|
||||
uri: data.uri,
|
||||
error: data.error
|
||||
};
|
||||
}
|
||||
|
||||
function unsetComposerAuthEnv(): void {
|
||||
delete process.env['GITHUB_TOKEN'];
|
||||
delete process.env['COMPOSER_TOKEN'];
|
||||
delete process.env['COMPOSER_AUTH_JSON'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock fetch.ts
|
||||
*/
|
||||
@@ -161,6 +160,18 @@ describe('Tools tests', () => {
|
||||
}
|
||||
);
|
||||
|
||||
it('checking getLatestVersion with fetch_latest=true but no repository', async () => {
|
||||
expect(
|
||||
await tools.getLatestVersion(
|
||||
getData({
|
||||
tool: 'tool',
|
||||
repository: '',
|
||||
fetch_latest: 'true'
|
||||
})
|
||||
)
|
||||
).toBe('latest');
|
||||
});
|
||||
|
||||
it.each`
|
||||
version | tool | type | expected
|
||||
${'latest'} | ${'tool'} | ${'phar'} | ${'latest'}
|
||||
@@ -176,6 +187,7 @@ describe('Tools tests', () => {
|
||||
${'1.2.3-dev'} | ${'tool'} | ${'phar'} | ${'1.2.3-dev'}
|
||||
${'1.2.3-alpha1'} | ${'tool'} | ${'phar'} | ${'1.2.3-alpha1'}
|
||||
${'1.2.3-alpha.1'} | ${'tool'} | ${'phar'} | ${'1.2.3-alpha.1'}
|
||||
${'1.>=0'} | ${'tool'} | ${'phar'} | ${'1.0'}
|
||||
`(
|
||||
'checking getVersion: $version, $tool, $type',
|
||||
async ({version, tool, type, expected}) => {
|
||||
@@ -245,15 +257,17 @@ describe('Tools tests', () => {
|
||||
);
|
||||
|
||||
it('checking getUrl handles undefined version without double slash', async () => {
|
||||
const data = getData({
|
||||
tool: 'cs2pr',
|
||||
repository: 'staabm/annotate-pull-request-from-checkstyle',
|
||||
domain: 'https://github.com'
|
||||
});
|
||||
data['extension'] = '';
|
||||
delete data['version'];
|
||||
const data: ToolInput = {
|
||||
...getData({
|
||||
tool: 'cs2pr',
|
||||
repository: 'staabm/annotate-pull-request-from-checkstyle',
|
||||
domain: 'https://github.com'
|
||||
}),
|
||||
version: undefined
|
||||
};
|
||||
data.extension = '';
|
||||
expect(await tools.getUrl(data)).toBe(
|
||||
'https://github.com/staabm/annotate-pull-request-from-checkstyle/releases/download/cs2pr'
|
||||
'https://github.com/staabm/annotate-pull-request-from-checkstyle/releases/latest/download/cs2pr'
|
||||
);
|
||||
});
|
||||
|
||||
@@ -284,29 +298,37 @@ describe('Tools tests', () => {
|
||||
tool: 'tool',
|
||||
version: 'latest',
|
||||
version_parameter: JSON.stringify('-v'),
|
||||
os: os
|
||||
os: os,
|
||||
url: 'https://example.com/tool.phar'
|
||||
});
|
||||
data['url'] = 'https://example.com/tool.phar';
|
||||
expect(await tools.addArchive(data)).toContain(script);
|
||||
});
|
||||
|
||||
it.each`
|
||||
os | script | scope
|
||||
${'linux'} | ${'add_composer_tool tool tool:1.2.3 user/ global'} | ${'global'}
|
||||
${'darwin'} | ${'add_composer_tool tool tool:1.2.3 user/ scoped'} | ${'scoped'}
|
||||
${'win32'} | ${'Add-ComposerTool tool tool:1.2.3 user/ scoped'} | ${'scoped'}
|
||||
${'openbsd'} | ${'Platform openbsd is not supported'} | ${'global'}
|
||||
`('checking addPackage: $os, $scope', async ({os, script, scope}) => {
|
||||
const data = getData({
|
||||
tool: 'tool',
|
||||
version: '1.2.3',
|
||||
repository: 'user/tool',
|
||||
os: os,
|
||||
scope: scope
|
||||
});
|
||||
data['release'] = [data['tool'], data['version']].join(':');
|
||||
expect(await tools.addPackage(data)).toContain(script);
|
||||
});
|
||||
os | release | scope | script
|
||||
${'linux'} | ${'tool:1.2.3'} | ${'global'} | ${'add_composer_tool tool tool:1.2.3 user/ global'}
|
||||
${'darwin'} | ${'tool:1.2.3'} | ${'scoped'} | ${'add_composer_tool tool tool:1.2.3 user/ scoped'}
|
||||
${'win32'} | ${'tool:1.2.3'} | ${'scoped'} | ${'Add-ComposerTool tool tool:1.2.3 user/ scoped'}
|
||||
${'linux'} | ${'tool:>=1.2'} | ${'global'} | ${'add_composer_tool tool "tool:>=1.2" user/ global'}
|
||||
${'win32'} | ${'tool:>=1.2'} | ${'global'} | ${'Add-ComposerTool tool "tool:>=1.2" user/ global'}
|
||||
${'linux'} | ${'tool:1.*'} | ${'global'} | ${'add_composer_tool tool "tool:1.*" user/ global'}
|
||||
${'linux'} | ${'psalm:^5||^6'} | ${'global'} | ${'add_composer_tool tool "psalm:^5||^6" user/ global'}
|
||||
${'linux'} | ${'psalm:>=5,<6'} | ${'global'} | ${'add_composer_tool tool "psalm:>=5,<6" user/ global'}
|
||||
${'openbsd'} | ${'tool:1.2.3'} | ${'global'} | ${'Platform openbsd is not supported'}
|
||||
`(
|
||||
'checking addPackage: $os, $release',
|
||||
async ({os, release, scope, script}) => {
|
||||
const data = getData({
|
||||
tool: 'tool',
|
||||
version: '1.2.3',
|
||||
repository: 'user/tool',
|
||||
os,
|
||||
scope
|
||||
});
|
||||
data['release'] = release;
|
||||
expect(await tools.addPackage(data)).toContain(script);
|
||||
}
|
||||
);
|
||||
|
||||
it.each`
|
||||
version | php_version | os | script
|
||||
@@ -416,6 +438,118 @@ describe('Tools tests', () => {
|
||||
}
|
||||
);
|
||||
|
||||
it.each`
|
||||
version | affected
|
||||
${'1'} | ${false}
|
||||
${'1.0.0-alpha1'} | ${true}
|
||||
${'1.0.0-alpha2'} | ${true}
|
||||
${'1.0.0-alpha3'} | ${true}
|
||||
${'1.0.0-alpha4'} | ${true}
|
||||
${'1.0.0-alpha5'} | ${true}
|
||||
${'1.0.0-alpha6'} | ${true}
|
||||
${'1.0.0-alpha7'} | ${true}
|
||||
${'1.0.0-alpha8'} | ${true}
|
||||
${'1.0.0-alpha9'} | ${true}
|
||||
${'1.0.0-alpha10'} | ${true}
|
||||
${'1.0.0-alpha11'} | ${true}
|
||||
${'1.0.0-beta1'} | ${true}
|
||||
${'1.0.0-beta2'} | ${true}
|
||||
${'1.0.0'} | ${true}
|
||||
${'1.10.27'} | ${true}
|
||||
${'1.10.28'} | ${false}
|
||||
${'2.0.0-alpha1'} | ${true}
|
||||
${'2.0.0-alpha2'} | ${true}
|
||||
${'2.0.0-alpha3'} | ${true}
|
||||
${'2.0.0-RC1'} | ${true}
|
||||
${'2.0.0-RC2'} | ${true}
|
||||
${'2.2.27'} | ${true}
|
||||
${'2.2.28'} | ${false}
|
||||
${'2.3.0-RC1'} | ${true}
|
||||
${'2.3.0-RC2'} | ${true}
|
||||
${'2.9.7'} | ${true}
|
||||
${'2.9.7-RC1'} | ${true}
|
||||
${'2.9.8'} | ${false}
|
||||
${'2.9.0RC1'} | ${false}
|
||||
${'2.9.x-dev'} | ${false}
|
||||
`('checking affected composer version: $version', ({version, affected}) => {
|
||||
expect(tools.skipGitHubAuthForComposerVersion(version)).toBe(affected);
|
||||
});
|
||||
|
||||
it('checking affected composer version with CRLF ranges', async () => {
|
||||
let affected = false;
|
||||
let fixed = true;
|
||||
await jest.isolateModulesAsync(async () => {
|
||||
jest.doMock('fs', () => ({
|
||||
...jest.requireActual('fs'),
|
||||
readFileSync: (
|
||||
filePath: fs.PathOrFileDescriptor,
|
||||
options?: unknown
|
||||
) => {
|
||||
if (String(filePath).includes('composer-gh-auth-no-op')) {
|
||||
return '1.0.0-0 1.10.28\r\n2.0.0-0 2.2.28\r\n2.3.0-0 2.9.8';
|
||||
}
|
||||
return (jest.requireActual('fs') as typeof fs).readFileSync(
|
||||
filePath,
|
||||
options as fs.ObjectEncodingOptions & {flag?: string}
|
||||
);
|
||||
}
|
||||
}));
|
||||
const isolatedTools = await import('../src/tools');
|
||||
affected = isolatedTools.skipGitHubAuthForComposerVersion('2.9.7');
|
||||
fixed = isolatedTools.skipGitHubAuthForComposerVersion('2.9.8');
|
||||
});
|
||||
expect(affected).toBe(true);
|
||||
expect(fixed).toBe(false);
|
||||
});
|
||||
|
||||
it.each`
|
||||
auth_json | expected
|
||||
${'{"github-oauth":{"github.com":"ghs_new-token"},"http-basic":{"repo.example":{"username":"u","password":"p"}}}'} | ${'{"http-basic":{"repo.example":{"username":"u","password":"p"}}}'}
|
||||
${'{"github-oauth":{"github.com":"ghs_new-token"}}'} | ${undefined}
|
||||
${'{"http-basic":{"repo.example":{"username":"u","password":"p"}}}'} | ${'{"http-basic":{"repo.example":{"username":"u","password":"p"}}}'}
|
||||
${'{"nested":{"github-oauth":{"github.com":"ghs_new-token"}}}'} | ${'{"nested":{"github-oauth":{"github.com":"ghs_new-token"}}}'}
|
||||
${'{"github-oauth":'} | ${'{"github-oauth":'}
|
||||
`('cleaning composer auth json', ({auth_json, expected}) => {
|
||||
unsetComposerAuthEnv();
|
||||
process.env['COMPOSER_AUTH_JSON'] = auth_json;
|
||||
tools.cleanComposerAuthJson();
|
||||
expect(process.env['COMPOSER_AUTH_JSON']).toBe(expected);
|
||||
unsetComposerAuthEnv();
|
||||
});
|
||||
|
||||
it.each`
|
||||
version | os | envs | skip_github_auth
|
||||
${'latest'} | ${'linux'} | ${{GITHUB_TOKEN: 'ghs_token'}} | ${false}
|
||||
${'1'} | ${'linux'} | ${{GITHUB_TOKEN: 'ghs_token'}} | ${false}
|
||||
${'2'} | ${'linux'} | ${{GITHUB_TOKEN: 'ghs_token'}} | ${false}
|
||||
${'2.9.7'} | ${'linux'} | ${{}} | ${true}
|
||||
${'2.9.7'} | ${'linux'} | ${{GITHUB_TOKEN: 'ghs_token'}} | ${true}
|
||||
${'2.9.7'} | ${'linux'} | ${{COMPOSER_TOKEN: 'ghs_token'}} | ${true}
|
||||
${'2.9.7'} | ${'linux'} | ${{COMPOSER_AUTH_JSON: '{"github-oauth":{"github.com":"ghs_new-token"}}'}} | ${true}
|
||||
${'2.9.7'} | ${'linux'} | ${{COMPOSER_AUTH_JSON: '{"http-basic":{"repo.example":{"username":"u","password":"p"}}}'}} | ${true}
|
||||
${'2.9.8'} | ${'linux'} | ${{GITHUB_TOKEN: 'ghs_token'}} | ${false}
|
||||
${'2.9.7'} | ${'win32'} | ${{GITHUB_TOKEN: 'ghs_token'}} | ${true}
|
||||
`(
|
||||
'checking composer github auth skip flag: $version, $os',
|
||||
async ({version, os, envs, skip_github_auth}) => {
|
||||
unsetComposerAuthEnv();
|
||||
Object.assign(process.env, envs);
|
||||
const data = getData({
|
||||
tool: 'composer',
|
||||
os: os,
|
||||
php_version: '7.4',
|
||||
domain: 'https://getcomposer.org',
|
||||
repository: 'composer/composer',
|
||||
version: version
|
||||
});
|
||||
const script = await tools.addComposer(data);
|
||||
expect(script).toContain(
|
||||
`composer ${version}${skip_github_auth ? ' true' : ''}`
|
||||
);
|
||||
unsetComposerAuthEnv();
|
||||
}
|
||||
);
|
||||
|
||||
it.each`
|
||||
version | uri
|
||||
${'latest'} | ${'wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true'}
|
||||
@@ -526,7 +660,7 @@ describe('Tools tests', () => {
|
||||
'add_devtools phpize',
|
||||
'add_tool https://github.com/phpmd/phpmd/releases/latest/download/phpmd.phar phpmd "--version"',
|
||||
'add_tool https://github.com/phpspec/phpspec/releases/latest/download/phpspec.phar phpspec "-V"',
|
||||
'add_composer_tool phpunit-bridge phpunit-bridge:5.6.* symfony/ global',
|
||||
'add_composer_tool phpunit-bridge "phpunit-bridge:5.6.*" symfony/ global',
|
||||
'add_composer_tool phpunit-polyfills phpunit-polyfills:1.0.1 yoast/ global',
|
||||
'add_protoc 1.2.3',
|
||||
'add_tool https://github.com/vimeo/psalm/releases/latest/download/psalm.phar psalm "-v"',
|
||||
@@ -586,7 +720,7 @@ describe('Tools tests', () => {
|
||||
'Add-ComposerTool codeception codeception codeception/ global',
|
||||
'Add-ComposerTool prestissimo prestissimo hirak/ global',
|
||||
'Add-ComposerTool automatic-composer-prefetcher automatic-composer-prefetcher narrowspark/ global',
|
||||
'Add-ComposerTool phinx phinx:1.2.* robmorgan/ scoped',
|
||||
'Add-ComposerTool phinx "phinx:1.2.*" robmorgan/ scoped',
|
||||
'Add-ComposerTool phinx phinx:^1.2 robmorgan/ global',
|
||||
'Add-ComposerTool tool tool:1.2.3 user/ global',
|
||||
'Add-ComposerTool tool tool:~1.2 user/ global'
|
||||
@@ -635,6 +769,7 @@ describe('Tools tests', () => {
|
||||
${'composer:preview'} | ${'add_tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-preview.phar,https://artifacts.setup-php.com/composer/composer-7.4-preview.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-preview.phar,https://getcomposer.org/composer-preview.phar composer preview'}
|
||||
${'composer, composer:v1'} | ${'add_tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-1.phar,https://artifacts.setup-php.com/composer/composer-7.4-1.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-1.phar,https://getcomposer.org/composer-1.phar composer'}
|
||||
${'composer:v1, composer:preview, composer:snapshot'} | ${'add_tool https://github.com/shivammathur/composer-cache/releases/latest/download/composer-7.4-snapshot.phar,https://artifacts.setup-php.com/composer/composer-7.4-snapshot.phar,https://dl.cloudsmith.io/public/shivammathur/composer-cache/raw/files/composer-7.4-snapshot.phar,https://getcomposer.org/composer.phar composer snapshot'}
|
||||
${'composer:2.9.7'} | ${'add_tool https://github.com/composer/composer/releases/download/2.9.7/composer.phar,https://getcomposer.org/download/2.9.7/composer.phar composer 2.9.7 true'}
|
||||
`('checking composer setup: $tools_csv', async ({tools_csv, script}) => {
|
||||
expect(await tools.addTools(tools_csv, '7.4', 'linux')).toContain(script);
|
||||
});
|
||||
@@ -649,14 +784,43 @@ describe('Tools tests', () => {
|
||||
expect(await tools.addTools(tools_csv, '7.4', 'linux')).toContain(script);
|
||||
});
|
||||
|
||||
it.each`
|
||||
tools_csv | token | script
|
||||
${'cs2pr:1.2'} | ${'invalid_token'} | ${'add_log "$cross" "cs2pr" "Invalid token"'}
|
||||
${'phpunit:1.2'} | ${'invalid_token'} | ${'add_log "$cross" "phpunit" "Invalid token"'}
|
||||
${'phpunit:0.1'} | ${'no_data'} | ${'add_log "$cross" "phpunit" "No version found with prefix 0.1."'}
|
||||
`('checking error: $tools_csv', async ({tools_csv, token, script}) => {
|
||||
process.env['GITHUB_TOKEN'] = token;
|
||||
expect(await tools.addTools(tools_csv, '7.4', 'linux')).toContain(script);
|
||||
it('checking error when custom-function tool is missing function field', async () => {
|
||||
const brokenToolsJson = JSON.stringify({
|
||||
composer: {
|
||||
type: 'custom-function',
|
||||
domain: 'https://getcomposer.org',
|
||||
repository: 'composer/composer',
|
||||
function: 'composer'
|
||||
},
|
||||
'broken-tool': {
|
||||
type: 'custom-function'
|
||||
}
|
||||
});
|
||||
|
||||
let result: string = '';
|
||||
await jest.isolateModulesAsync(async () => {
|
||||
jest.doMock('fs', () => ({
|
||||
...jest.requireActual('fs'),
|
||||
readFileSync: (
|
||||
filePath: fs.PathOrFileDescriptor,
|
||||
options?: unknown
|
||||
) => {
|
||||
if (String(filePath).includes('tools.json')) {
|
||||
return brokenToolsJson;
|
||||
}
|
||||
return (jest.requireActual('fs') as typeof fs).readFileSync(
|
||||
filePath,
|
||||
options as fs.ObjectEncodingOptions & {flag?: string}
|
||||
);
|
||||
}
|
||||
}));
|
||||
const isolatedTools = await import('../src/tools');
|
||||
result = await isolatedTools.addTools('broken-tool', '7.4', 'linux');
|
||||
});
|
||||
|
||||
expect(result).toContain(
|
||||
'add_log "$cross" "broken-tool" "broken-tool has no function defined. Please report this issue."'
|
||||
);
|
||||
});
|
||||
|
||||
it.each`
|
||||
|
||||
@@ -3,16 +3,6 @@ import * as path from 'path';
|
||||
import * as utils from '../src/utils';
|
||||
import * as fetchModule from '../src/fetch';
|
||||
|
||||
/**
|
||||
* Mock @actions/core
|
||||
*/
|
||||
jest.mock('@actions/core', () => ({
|
||||
getInput: jest.fn().mockImplementation(key => {
|
||||
return ['setup-php'].indexOf(key) !== -1 ? key : '';
|
||||
}),
|
||||
info: jest.fn()
|
||||
}));
|
||||
|
||||
describe('Utils tests', () => {
|
||||
it('checking readEnv', async () => {
|
||||
process.env['test'] = 'setup-php';
|
||||
@@ -26,12 +16,14 @@ describe('Utils tests', () => {
|
||||
|
||||
it('checking getInput', async () => {
|
||||
process.env['test'] = 'setup-php';
|
||||
process.env['INPUT_SETUP-PHP'] = 'setup-php';
|
||||
expect(await utils.getInput('test', false)).toBe('setup-php');
|
||||
expect(await utils.getInput('setup-php', false)).toBe('setup-php');
|
||||
expect(await utils.getInput('DoesNotExist', false)).toBe('');
|
||||
await expect(async () => {
|
||||
await utils.getInput('DoesNotExist', true);
|
||||
}).rejects.toThrow('Input required and not supplied: DoesNotExist');
|
||||
delete process.env['INPUT_SETUP-PHP'];
|
||||
});
|
||||
|
||||
it('checking getManifestURL', async () => {
|
||||
@@ -48,7 +40,19 @@ describe('Utils tests', () => {
|
||||
expect(await utils.parseVersion('7')).toBe('7.0');
|
||||
expect(await utils.parseVersion('7.4')).toBe('7.4');
|
||||
expect(await utils.parseVersion('5.x')).toBe('5.6');
|
||||
expect(await utils.parseVersion('4.x')).toBe(undefined);
|
||||
expect(await utils.parseVersion('pre')).toBe('pre');
|
||||
expect(await utils.parseVersion('pre-installed')).toBe('pre');
|
||||
await expect(utils.parseVersion('4.x')).rejects.toThrow(
|
||||
'Invalid PHP version: 4.x'
|
||||
);
|
||||
await expect(utils.parseVersion('foo')).rejects.toThrow(
|
||||
'Invalid PHP version:'
|
||||
);
|
||||
|
||||
fetchSpy.mockResolvedValue({data: '{ "latest": "8.1.0" }'});
|
||||
await expect(utils.parseVersion('latest')).rejects.toThrow(
|
||||
'Invalid PHP version in manifest:'
|
||||
);
|
||||
|
||||
fetchSpy.mockReset();
|
||||
fetchSpy.mockResolvedValueOnce({}).mockResolvedValueOnce({});
|
||||
@@ -64,6 +68,12 @@ describe('Utils tests', () => {
|
||||
expect(await utils.parseIniFile('none')).toBe('none');
|
||||
expect(await utils.parseIniFile('php.ini-production')).toBe('production');
|
||||
expect(await utils.parseIniFile('php.ini-development')).toBe('development');
|
||||
expect(await utils.parseIniFile('/etc/php.ini-production')).toBe(
|
||||
'production'
|
||||
);
|
||||
expect(await utils.parseIniFile('/a-b/php.ini-development')).toBe(
|
||||
'development'
|
||||
);
|
||||
expect(await utils.parseIniFile('invalid')).toBe('production');
|
||||
});
|
||||
|
||||
@@ -93,6 +103,26 @@ describe('Utils tests', () => {
|
||||
|
||||
expect(await utils.extensionArray('')).toEqual([]);
|
||||
expect(await utils.extensionArray(' ')).toEqual([]);
|
||||
|
||||
expect(
|
||||
await utils.extensionArray('apcu, mbstring, \\ pdo_pgsql, posix, session')
|
||||
).toEqual(['apcu', 'mbstring', 'pdo_pgsql', 'posix', 'session']);
|
||||
});
|
||||
|
||||
it('checking shell helpers', () => {
|
||||
expect(utils.escapeForShell('a$b`c\\d"e', 'linux')).toBe(
|
||||
'a\\$b\\`c\\\\d\\"e'
|
||||
);
|
||||
expect(utils.escapeForShell('a$b`c"d', 'win32')).toBe('a`$b``c`"d');
|
||||
expect(utils.safeArg('vendor-pkg/repo@v1.0.0', 'linux')).toBe(
|
||||
'vendor-pkg/repo@v1.0.0'
|
||||
);
|
||||
expect(utils.safeArg('phpcs:>=3.0', 'linux')).toBe('"phpcs:>=3.0"');
|
||||
expect(utils.safeArg('foo$bar', 'win32')).toBe('"foo`$bar"');
|
||||
expect(utils.sanitizeShellInput('foo;$(`ls`)bar')).toBe('foolsbar');
|
||||
expect(utils.sanitizeShellInput('vendor/foo:1.*', true)).toBe(
|
||||
'vendor/foo:1.'
|
||||
);
|
||||
});
|
||||
|
||||
it('checking INIArray', async () => {
|
||||
@@ -286,6 +316,9 @@ describe('Utils tests', () => {
|
||||
process.env['php-version'] = '8.2';
|
||||
expect(await utils.readPHPVersion()).toBe('8.2');
|
||||
|
||||
process.env['php-version'] = 'pre-installed';
|
||||
expect(await utils.readPHPVersion()).toBe('pre-installed');
|
||||
|
||||
delete process.env['php-version-file'];
|
||||
delete process.env['php-version'];
|
||||
|
||||
@@ -295,7 +328,7 @@ describe('Utils tests', () => {
|
||||
|
||||
existsSync.mockReturnValue(true);
|
||||
readFileSync.mockReturnValue('setup-php');
|
||||
expect(await utils.readPHPVersion()).toBe('setup-php');
|
||||
await expect(utils.readPHPVersion()).rejects.toThrow('Invalid PHP version');
|
||||
|
||||
existsSync.mockReturnValueOnce(false).mockReturnValueOnce(true);
|
||||
readFileSync.mockReturnValue(
|
||||
@@ -316,6 +349,37 @@ describe('Utils tests', () => {
|
||||
readFileSync.mockClear();
|
||||
});
|
||||
|
||||
it('readPHPVersion rejects unsupported values from each source', async () => {
|
||||
const existsSync = jest.spyOn(fs, 'existsSync').mockImplementation();
|
||||
const readFileSync = jest.spyOn(fs, 'readFileSync').mockImplementation();
|
||||
|
||||
process.env['php-version'] = 'bogus';
|
||||
await expect(utils.readPHPVersion()).rejects.toThrow('php-version input');
|
||||
delete process.env['php-version'];
|
||||
|
||||
existsSync.mockReturnValue(true);
|
||||
readFileSync.mockReturnValue('bogus');
|
||||
await expect(utils.readPHPVersion()).rejects.toThrow('.php-version');
|
||||
|
||||
existsSync.mockReturnValueOnce(false).mockReturnValueOnce(true);
|
||||
readFileSync.mockReturnValue('{"platform-overrides":{"php":"bogus"}}');
|
||||
await expect(utils.readPHPVersion()).rejects.toThrow(
|
||||
'composer.lock platform-overrides.php'
|
||||
);
|
||||
|
||||
existsSync
|
||||
.mockReturnValueOnce(false)
|
||||
.mockReturnValueOnce(false)
|
||||
.mockReturnValueOnce(true);
|
||||
readFileSync.mockReturnValue('{"config":{"platform":{"php":"bogus"}}}');
|
||||
await expect(utils.readPHPVersion()).rejects.toThrow(
|
||||
'composer.json config.platform.php'
|
||||
);
|
||||
|
||||
existsSync.mockClear();
|
||||
readFileSync.mockClear();
|
||||
});
|
||||
|
||||
it('checking setVariable', async () => {
|
||||
let script: string = await utils.setVariable('var', 'command', 'linux');
|
||||
expect(script).toEqual('\nvar="$(command)"\n');
|
||||
|
||||
@@ -34,5 +34,5 @@ outputs:
|
||||
php-version:
|
||||
description: 'PHP version in semver format'
|
||||
runs:
|
||||
using: 'node20'
|
||||
using: 'node24'
|
||||
main: 'dist/index.js'
|
||||
|
||||
4
dist/index.js
vendored
4
dist/index.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,39 +1,22 @@
|
||||
import {fixupConfigRules, fixupPluginRules} from '@eslint/compat';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import typescriptEslint from '@typescript-eslint/eslint-plugin';
|
||||
import {importX} from 'eslint-plugin-import-x';
|
||||
import jest from 'eslint-plugin-jest';
|
||||
import prettierRecommended from 'eslint-plugin-prettier/recommended';
|
||||
import eslintConfigPrettier from 'eslint-config-prettier';
|
||||
import globals from 'globals';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import tsParser from '@typescript-eslint/parser';
|
||||
import path from 'node:path';
|
||||
import {fileURLToPath} from 'node:url';
|
||||
import js from '@eslint/js';
|
||||
import {FlatCompat} from '@eslint/eslintrc';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const compat = new FlatCompat({
|
||||
baseDirectory: __dirname,
|
||||
recommendedConfig: js.configs.recommended,
|
||||
allConfig: js.configs.all
|
||||
});
|
||||
|
||||
export default [
|
||||
...fixupConfigRules(
|
||||
compat.extends(
|
||||
'eslint:recommended',
|
||||
'plugin:@typescript-eslint/eslint-recommended',
|
||||
'plugin:@typescript-eslint/recommended',
|
||||
'plugin:import/errors',
|
||||
'plugin:import/warnings',
|
||||
'plugin:import/typescript',
|
||||
'plugin:prettier/recommended',
|
||||
'prettier'
|
||||
)
|
||||
),
|
||||
js.configs.recommended,
|
||||
...typescriptEslint.configs['flat/recommended'],
|
||||
importX.flatConfigs.errors,
|
||||
importX.flatConfigs.warnings,
|
||||
importX.flatConfigs.typescript,
|
||||
prettierRecommended,
|
||||
eslintConfigPrettier,
|
||||
{
|
||||
plugins: {
|
||||
'@typescript-eslint': fixupPluginRules(typescriptEslint),
|
||||
jest
|
||||
},
|
||||
|
||||
@@ -46,6 +29,21 @@ export default [
|
||||
parser: tsParser,
|
||||
ecmaVersion: 2021,
|
||||
sourceType: 'module'
|
||||
},
|
||||
|
||||
settings: {
|
||||
'import-x/resolver': {
|
||||
typescript: {
|
||||
alwaysTryTypes: true,
|
||||
project: './tsconfig.json'
|
||||
},
|
||||
node: {
|
||||
extensions: ['.js', '.ts']
|
||||
}
|
||||
},
|
||||
'import-x/parsers': {
|
||||
'@typescript-eslint/parser': ['.ts']
|
||||
}
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -8,7 +8,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -23,7 +23,7 @@ jobs:
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
|
||||
@@ -4,6 +4,9 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
blackfire-player:
|
||||
name: Blackfire (PHP ${{ matrix.php-versions }})
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
# Add your Blackfire credentials securely using GitHub Secrets
|
||||
env:
|
||||
BLACKFIRE_SERVER_ID: ${{ secrets.BLACKFIRE_SERVER_ID }}
|
||||
@@ -14,9 +17,9 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
# blackfire-player supports PHP >= 5.5
|
||||
operating-system: [ubuntu-latest, macos-latest]
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
# Blackfire Player supports PHP 8.5 and is available on Ubuntu and macOS.
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -31,6 +34,14 @@ jobs:
|
||||
tools: blackfire, blackfire-player
|
||||
coverage: none
|
||||
|
||||
# Refer to https://blackfire.io/docs/player/index#usage
|
||||
- name: Start local endpoint
|
||||
run: |
|
||||
php -S 127.0.0.1:8080 > "$RUNNER_TEMP/blackfire-player.log" 2>&1 &
|
||||
sleep 5
|
||||
|
||||
- name: Validate scenario
|
||||
run: blackfire-player validate scenario.bkf
|
||||
|
||||
# Refer to https://docs.blackfire.io/builds-cookbooks/player
|
||||
- name: Play the scenario
|
||||
run: blackfire-player run scenario.bkf
|
||||
run: blackfire-player run scenario.bkf --endpoint=http://127.0.0.1:8080
|
||||
|
||||
@@ -15,8 +15,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
# Blackfire supports PHP >= 5.3 on Ubuntu and macOS, and PHP >= 5.4 on Windows
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
# Blackfire supports the current PHP releases on Ubuntu, macOS, and Windows.
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -26,12 +26,24 @@ jobs:
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
# Setup Blackfire extension and CLI
|
||||
extensions: blackfire
|
||||
# Setup Blackfire extension and CLI.
|
||||
extensions: blackfire, :xdebug
|
||||
tools: blackfire
|
||||
# Disable Xdebug and PCOV coverage drivers
|
||||
coverage: none
|
||||
|
||||
# Refer to https://blackfire.io/docs/cookbooks/profiling-cli
|
||||
- name: Profile
|
||||
run: blackfire run php my-script.php
|
||||
shell: bash
|
||||
run: |
|
||||
set +e
|
||||
output=$(blackfire run php my-script.php 2>&1)
|
||||
exit_code=$?
|
||||
printf '%s\n' "$output"
|
||||
if [ "$exit_code" -ne 0 ]; then
|
||||
if printf '%s' "$output" | grep -q "upgrade your subscription"; then
|
||||
echo "Blackfire profiling reached the repository quota limit; treating this as a known non-fatal condition."
|
||||
exit 0
|
||||
fi
|
||||
exit "$exit_code"
|
||||
fi
|
||||
|
||||
@@ -6,7 +6,8 @@ jobs:
|
||||
tests:
|
||||
strategy:
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.4', '8.5']
|
||||
# The latest cakephp/app release resolves dev dependencies that require PHP 8.4+.
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
@@ -37,7 +38,7 @@ jobs:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
# You can also use ext-apcu or ext-memcached instead of ext-redis
|
||||
# Install memcached if using ext-memcached
|
||||
extensions: mbstring, intl, redis, pdo_mysql
|
||||
extensions: mbstring, intl, redis, apcu, pdo_mysql
|
||||
coverage: pcov
|
||||
|
||||
# Local MySQL service in GitHub hosted environments is disabled by default.
|
||||
@@ -50,7 +51,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -61,14 +62,15 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
composer run-script post-install-cmd
|
||||
composer run-script post-install-cmd --no-interaction
|
||||
|
||||
# Add a step to run migrations if required
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit --coverage-text
|
||||
env:
|
||||
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
|
||||
DB_DSN: "mysql://root:password@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/cakephp?init[]=SET sql_mode = \"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION\""
|
||||
DATABASE_URL: "mysql://root:password@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/cakephp?init[]=SET sql_mode = \"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\""
|
||||
DATABASE_TEST_URL: "mysql://root:password@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/cakephp?init[]=SET sql_mode = \"STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION\""
|
||||
|
||||
coding-standard:
|
||||
name: Coding Standard
|
||||
@@ -81,7 +83,7 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
php-version: '8.5'
|
||||
extensions: mbstring, intl
|
||||
|
||||
- name: Get composer cache directory
|
||||
@@ -89,7 +91,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -114,7 +116,7 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
php-version: '8.5'
|
||||
extensions: mbstring, intl
|
||||
tools: phpstan
|
||||
|
||||
@@ -123,7 +125,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -132,7 +134,9 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
run: |
|
||||
composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
composer run-script post-install-cmd --no-interaction
|
||||
|
||||
- name: Static Analysis using PHPStan
|
||||
run: phpstan analyse --no-progress src/
|
||||
|
||||
@@ -5,8 +5,10 @@ on: [push, pull_request]
|
||||
jobs:
|
||||
tests:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.4', '8.5']
|
||||
# The latest cakephp/app release resolves dev dependencies that require PHP 8.4+.
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
@@ -37,7 +39,7 @@ jobs:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
# You can also use ext-apcu or ext-memcached instead of ext-redis
|
||||
# Install memcached if using ext-memcached
|
||||
extensions: mbstring, intl, redis, pdo_pgsql
|
||||
extensions: mbstring, intl, redis, apcu, pdo_pgsql
|
||||
coverage: pcov
|
||||
|
||||
# Local PostgreSQL service in GitHub hosted environments is disabled by default.
|
||||
@@ -50,7 +52,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -61,14 +63,15 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
composer run-script post-install-cmd
|
||||
composer run-script post-install-cmd --no-interaction
|
||||
|
||||
# Add a step to run migrations if required
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit --coverage-text
|
||||
env:
|
||||
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
|
||||
DB_DSN: postgres://postgres@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/postgres
|
||||
DATABASE_URL: postgres://postgres:postgres@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/postgres?encoding=UTF8
|
||||
DATABASE_TEST_URL: postgres://postgres:postgres@127.0.0.1:${{ job.services.postgres.ports['5432'] }}/postgres?encoding=UTF8
|
||||
|
||||
coding-standard:
|
||||
name: Coding Standard
|
||||
@@ -81,15 +84,15 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
extensions: mbstring, intl
|
||||
php-version: '8.5'
|
||||
extensions: mbstring, intl, apcu
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -114,8 +117,8 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
extensions: mbstring, intl
|
||||
php-version: '8.5'
|
||||
extensions: mbstring, intl, apcu
|
||||
tools: phpstan
|
||||
|
||||
- name: Get composer cache directory
|
||||
@@ -123,7 +126,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -132,7 +135,9 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
run: |
|
||||
composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
composer run-script post-install-cmd --no-interaction
|
||||
|
||||
- name: Static Analysis using PHPStan
|
||||
run: phpstan analyse --no-progress src/
|
||||
|
||||
@@ -7,7 +7,8 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.4', '8.5']
|
||||
# The latest cakephp/app release resolves dev dependencies that require PHP 8.4+.
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -23,10 +24,11 @@ jobs:
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -37,7 +39,7 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
composer run-script post-install-cmd
|
||||
composer run-script post-install-cmd --no-interaction
|
||||
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit --coverage-text
|
||||
@@ -53,14 +55,15 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
php-version: '8.5'
|
||||
extensions: mbstring, intl
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -85,16 +88,17 @@ jobs:
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '8.1'
|
||||
php-version: '8.5'
|
||||
extensions: mbstring, intl
|
||||
tools: phpstan
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -103,7 +107,9 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
run: |
|
||||
composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
composer run-script post-install-cmd --no-interaction
|
||||
|
||||
- name: Static Analysis using PHPStan
|
||||
run: phpstan analyse --no-progress src/
|
||||
|
||||
@@ -6,7 +6,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -17,15 +17,16 @@ jobs:
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mbstring, intl, curl, dom
|
||||
extensions: mbstring, intl, curl, dom, sqlite3, pdo_sqlite
|
||||
coverage: xdebug
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
|
||||
59
examples/drupal.yml
Normal file
59
examples/drupal.yml
Normal file
@@ -0,0 +1,59 @@
|
||||
# GitHub Action for Drupal 11 composer-managed projects
|
||||
# Requires drupal/core-dev in require-dev for vendor/bin/phpunit
|
||||
name: Testing Drupal
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
drupal:
|
||||
name: Drupal (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
SIMPLETEST_BASE_URL: http://127.0.0.1:8080
|
||||
SIMPLETEST_DB: sqlite://localhost/sites/default/files/.ht.sqlite
|
||||
BROWSERTEST_OUTPUT_DIRECTORY: /tmp/browser_output
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Docs: https://github.com/shivammathur/setup-php
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: apcu, ctype, curl, dom, gd, iconv, intl, mbstring, pdo_sqlite, simplexml, xml, zip
|
||||
coverage: none
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: |
|
||||
if [ "${{ matrix.php-versions }}" = "8.3" ]; then
|
||||
composer require --dev drupal/core-dev:11.2.10 doctrine/instantiator:^2.0.0 --no-interaction --no-update
|
||||
composer update drupal/core-dev doctrine/instantiator --with-all-dependencies --no-interaction --no-progress --prefer-dist --optimize-autoloader
|
||||
else
|
||||
composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader
|
||||
fi
|
||||
|
||||
- name: Prepare Drupal test directories
|
||||
run: mkdir -p web/sites/default/files "$BROWSERTEST_OUTPUT_DIRECTORY"
|
||||
|
||||
- name: Start Drupal web server
|
||||
run: php -S 127.0.0.1:8080 -t web >/tmp/php-server.log 2>&1 &
|
||||
|
||||
- name: Test with phpunit
|
||||
# Adjust the test path to match your custom modules or themes.
|
||||
run: vendor/bin/phpunit -c web/core web/modules/custom
|
||||
@@ -1,12 +1,12 @@
|
||||
# GitHub Action for Laminas framework MVC projects
|
||||
name: Testing Zend Framework
|
||||
name: Testing Laminas MVC
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.1', '8.2', '8.3']
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -21,10 +21,11 @@ jobs:
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
|
||||
@@ -6,11 +6,13 @@ jobs:
|
||||
name: Laravel (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DB_CONNECTION: mysql
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_DATABASE: laravel
|
||||
DB_USERNAME: root
|
||||
DB_PASSWORD: password
|
||||
BROADCAST_DRIVER: log
|
||||
CACHE_DRIVER: redis
|
||||
BROADCAST_CONNECTION: log
|
||||
CACHE_STORE: redis
|
||||
QUEUE_CONNECTION: redis
|
||||
SESSION_DRIVER: redis
|
||||
|
||||
@@ -34,7 +36,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -57,7 +59,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
QUEUE_CONNECTION: redis
|
||||
SESSION_DRIVER: redis
|
||||
DB_CONNECTION: pgsql
|
||||
DB_HOST: localhost
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_PASSWORD: postgres
|
||||
DB_USERNAME: postgres
|
||||
DB_DATABASE: postgres
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -81,11 +81,11 @@ jobs:
|
||||
- name: Run Migration
|
||||
run: php artisan migrate -v
|
||||
env:
|
||||
DB_PORT: ${{ job.services.postgres.ports[5432] }}
|
||||
DB_PORT: ${{ job.services.postgres.ports['5432'] }}
|
||||
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
|
||||
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit --coverage-text
|
||||
env:
|
||||
DB_PORT: ${{ job.services.postgres.ports[5432] }}
|
||||
DB_PORT: ${{ job.services.postgres.ports['5432'] }}
|
||||
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -24,10 +24,11 @@ jobs:
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -83,7 +83,7 @@ jobs:
|
||||
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
|
||||
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit --coverage-text
|
||||
run: vendor/bin/phpunit --coverage-text --coverage-filter app
|
||||
env:
|
||||
DB_PORT: ${{ job.services.mysql.ports['3306'] }}
|
||||
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
QUEUE_CONNECTION: redis
|
||||
SESSION_DRIVER: redis
|
||||
DB_CONNECTION: pgsql
|
||||
DB_HOST: localhost
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_PASSWORD: postgres
|
||||
DB_USERNAME: postgres
|
||||
DB_DATABASE: postgres
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -47,7 +47,7 @@ jobs:
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mbstring, dom, fileinfo, pgsql
|
||||
coverage: xdebug
|
||||
coverage: none
|
||||
|
||||
# Local PostgreSQL service in GitHub hosted environments is disabled by default.
|
||||
# If you are using it instead of service containers, make sure you start it.
|
||||
@@ -59,7 +59,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -81,11 +81,11 @@ jobs:
|
||||
- name: Run Migration
|
||||
run: php artisan migrate -v
|
||||
env:
|
||||
DB_PORT: ${{ job.services.postgres.ports[5432] }}
|
||||
DB_PORT: ${{ job.services.postgres.ports['5432'] }}
|
||||
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
|
||||
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit --coverage-text
|
||||
run: vendor/bin/phpunit
|
||||
env:
|
||||
DB_PORT: ${{ job.services.postgres.ports[5432] }}
|
||||
DB_PORT: ${{ job.services.postgres.ports['5432'] }}
|
||||
REDIS_PORT: ${{ job.services.redis.ports['6379'] }}
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -24,10 +24,11 @@ jobs:
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -42,4 +43,4 @@ jobs:
|
||||
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
|
||||
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit --coverage-text
|
||||
run: vendor/bin/phpunit --coverage-text --coverage-filter app
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
env:
|
||||
DB_ADAPTER: mysql
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_NAME: phalcon
|
||||
DB_NAME: vokuro
|
||||
DB_USERNAME: root
|
||||
DB_PASSWORD: password
|
||||
CODECEPTION_URL: 127.0.0.1
|
||||
@@ -20,11 +20,11 @@ jobs:
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:latest
|
||||
image: mysql:5.7
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: false
|
||||
MYSQL_ROOT_PASSWORD: password
|
||||
MYSQL_DATABASE: phalcon
|
||||
MYSQL_DATABASE: vokuro
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
@@ -32,8 +32,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.2', '7.3', '7.4']
|
||||
# For phalcon 3.x, use
|
||||
# php-versions: ['7.0', '7.1', '7.2', '7.3']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -43,7 +41,7 @@ jobs:
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
# Use phalcon3 for the phalcon 3.x.
|
||||
# Use phalcon4 for the latest compatible Vokuro sample release.
|
||||
extensions: mbstring, dom, zip, phalcon4, mysql
|
||||
coverage: xdebug
|
||||
|
||||
@@ -57,7 +55,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -73,7 +71,6 @@ jobs:
|
||||
|
||||
- name: Run Migration
|
||||
run: |
|
||||
if [ ! -e phinx.yml ]; then vendor/bin/phinx init; fi
|
||||
vendor/bin/phinx migrate
|
||||
vendor/bin/phinx seed:run
|
||||
env:
|
||||
|
||||
@@ -11,21 +11,18 @@ jobs:
|
||||
env:
|
||||
DB_ADAPTER: pgsql
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_NAME: postgres
|
||||
DB_NAME: vokuro
|
||||
DB_USERNAME: postgres
|
||||
DB_PASSWORD: postgres
|
||||
CODECEPTION_URL: 127.0.0.1
|
||||
CODECEPTION_PORT: 8888
|
||||
DB_CONNECTION: pgsql
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: postgres
|
||||
POSTGRES_DB: vokuro
|
||||
ports:
|
||||
- 5432/tcp
|
||||
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3
|
||||
@@ -33,8 +30,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.2', '7.3', '7.4']
|
||||
# For phalcon 3.x, use
|
||||
# php-versions: ['7.0', '7.1', '7.2', '7.3']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -44,40 +39,39 @@ jobs:
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
# Use phalcon3 for the phalcon 3.x
|
||||
extensions: mbstring, dom, zip, phalcon4, pgsql
|
||||
coverage: xdebug
|
||||
|
||||
# Local PostgreSQL service in GitHub hosted environments is disabled by default.
|
||||
# If you are using it instead of service containers, make sure you start it.
|
||||
# - name: Start postgresql service
|
||||
# run: sudo systemctl start postgresql.service
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader --no-security-blocking
|
||||
|
||||
- name: Prepare the application
|
||||
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
|
||||
run: |
|
||||
php -r "file_exists('.env') || copy('.env.example', '.env');"
|
||||
mkdir -p var/cache/acl var/cache/metaData var/cache/session var/cache/volt var/logs
|
||||
chmod -R 777 var/cache var/logs
|
||||
|
||||
- name: Run Migration
|
||||
run: |
|
||||
if [ ! -e phinx.yml ]; then vendor/bin/phinx init; fi
|
||||
vendor/bin/phinx migrate
|
||||
vendor/bin/phinx seed:run
|
||||
env:
|
||||
DB_PORT: ${{ job.services.postgres.ports['5432'] }}
|
||||
|
||||
- name: Run Tests
|
||||
run: |
|
||||
(cd public && nohup php -S $CODECEPTION_URL:$CODECEPTION_PORT > phalcon.log 2>&1 &)
|
||||
(cd public && nohup php -S $CODECEPTION_URL:$CODECEPTION_PORT > vokuro.log 2>&1 &)
|
||||
vendor/bin/codecept build
|
||||
vendor/bin/codecept run
|
||||
env:
|
||||
|
||||
@@ -8,8 +8,8 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
node-versions: ['16']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
node-versions: ['20']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -33,7 +33,7 @@ jobs:
|
||||
id: yarn-cache
|
||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.yarn-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -53,17 +53,10 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install yarn dependencies
|
||||
run: yarn -V
|
||||
run: yarn install --frozen-lockfile --non-interactive
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Yarn test and build
|
||||
run: |
|
||||
yarn run test
|
||||
yarn run build
|
||||
yarn run rmdist
|
||||
yarn run "build:production"
|
||||
|
||||
- name: PHP test
|
||||
run: composer test
|
||||
- name: Yarn build
|
||||
run: yarn build
|
||||
|
||||
@@ -6,7 +6,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -22,10 +22,11 @@ jobs:
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
|
||||
@@ -5,11 +5,13 @@ jobs:
|
||||
symfony:
|
||||
name: Symfony (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
APP_ENV: test
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:latest
|
||||
image: mysql:8.4
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: false
|
||||
MYSQL_ROOT_PASSWORD: symfony
|
||||
@@ -20,7 +22,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.4', '8.5', '8.6']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -30,7 +32,6 @@ jobs:
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: phpunit-bridge
|
||||
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, mysql
|
||||
coverage: xdebug
|
||||
|
||||
@@ -44,7 +45,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -53,18 +54,17 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
run: composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Run Migration
|
||||
- name: Prepare database
|
||||
run: |
|
||||
composer require --dev symfony/orm-pack
|
||||
php bin/console doctrine:schema:update --force || echo "No migrations found or schema update failed"
|
||||
php bin/console doctrine:migrations:migrate || echo "No migrations found or migration failed"
|
||||
php bin/console doctrine:database:create --if-not-exists --no-interaction
|
||||
php bin/console doctrine:schema:create --no-interaction
|
||||
php bin/console doctrine:fixtures:load --no-interaction
|
||||
env:
|
||||
DATABASE_URL: mysql://root:symfony@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/symfony
|
||||
|
||||
- name: Install PHPUnit
|
||||
run: simple-phpunit install
|
||||
DATABASE_URL: mysql://root:symfony@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/symfony?serverVersion=8.4&charset=utf8mb4
|
||||
|
||||
- name: Run tests
|
||||
run: simple-phpunit --coverage-text
|
||||
run: php bin/phpunit --coverage-text
|
||||
env:
|
||||
DATABASE_URL: mysql://root:symfony@127.0.0.1:${{ job.services.mysql.ports['3306'] }}/symfony?serverVersion=8.4&charset=utf8mb4
|
||||
|
||||
@@ -5,11 +5,13 @@ jobs:
|
||||
symfony:
|
||||
name: Symfony (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
APP_ENV: test
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
image: postgres:16
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
@@ -20,7 +22,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.4', '8.5', '8.6']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -30,8 +32,7 @@ jobs:
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: phpunit-bridge
|
||||
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, pgsql
|
||||
extensions: mbstring, xml, ctype, iconv, intl, pdo_pgsql, pgsql
|
||||
coverage: xdebug
|
||||
|
||||
# Local PostgreSQL service in GitHub hosted environments is disabled by default.
|
||||
@@ -44,7 +45,7 @@ jobs:
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -55,16 +56,15 @@ jobs:
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Run Migration
|
||||
- name: Prepare database
|
||||
run: |
|
||||
composer require --dev symfony/orm-pack
|
||||
php bin/console doctrine:schema:update --force || echo "No migrations found or schema update failed"
|
||||
php bin/console doctrine:migrations:migrate || echo "No migrations found or migration failed"
|
||||
php bin/console doctrine:database:create --if-not-exists --no-interaction
|
||||
php bin/console doctrine:schema:create --no-interaction
|
||||
php bin/console doctrine:fixtures:load --no-interaction
|
||||
env:
|
||||
DATABASE_URL: postgres://postgres:postgres@127.0.0.1:${{ job.services.postgres.ports[5432] }}/postgres?charset=UTF-8
|
||||
|
||||
- name: Install PHPUnit
|
||||
run: simple-phpunit install
|
||||
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:${{ job.services.postgres.ports[5432] }}/postgres?serverVersion=16.0.0&charset=utf8
|
||||
|
||||
- name: Run tests
|
||||
run: simple-phpunit --coverage-text
|
||||
run: php bin/phpunit --coverage-text
|
||||
env:
|
||||
DATABASE_URL: postgresql://postgres:postgres@127.0.0.1:${{ job.services.postgres.ports[5432] }}/postgres?serverVersion=16.0.0&charset=utf8
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest, macos-latest]
|
||||
php-versions: ['7.4', '8.0', '8.1']
|
||||
php-versions: ['8.4', '8.5', '8.6']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -19,16 +19,16 @@ jobs:
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
tools: phpunit-bridge
|
||||
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite
|
||||
extensions: mbstring, xml, ctype, iconv, intl, pdo_sqlite, zip
|
||||
coverage: xdebug
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
@@ -39,8 +39,5 @@ jobs:
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Install PHPUnit
|
||||
run: simple-phpunit install
|
||||
|
||||
- name: Run tests
|
||||
run: simple-phpunit --coverage-text
|
||||
run: ./bin/phpunit --coverage-text
|
||||
|
||||
68
examples/wordpress.yml
Normal file
68
examples/wordpress.yml
Normal file
@@ -0,0 +1,68 @@
|
||||
# GitHub Action for WordPress plugins
|
||||
# Tested with files scaffolded by wp scaffold plugin-tests --ci=github
|
||||
# Requires phpunit/phpunit and yoast/phpunit-polyfills in require-dev for vendor/bin/phpunit
|
||||
name: Testing WordPress
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
wordpress:
|
||||
name: WordPress (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['8.3', '8.4', '8.5']
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:latest
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: false
|
||||
MYSQL_ROOT_PASSWORD: root
|
||||
MYSQL_DATABASE: wordpress_test
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Docs: https://github.com/shivammathur/setup-php
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mbstring, xml, zip, intl, mysql
|
||||
coverage: none
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install system dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y subversion default-mysql-client
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: |
|
||||
if [ "${{ matrix.php-versions }}" = "8.3" ]; then
|
||||
composer require --dev doctrine/instantiator:^2.0.0 --no-interaction --no-update
|
||||
composer update doctrine/instantiator --with-all-dependencies --no-interaction --no-progress --prefer-dist --optimize-autoloader
|
||||
else
|
||||
composer install --no-interaction --no-progress --prefer-dist --optimize-autoloader
|
||||
fi
|
||||
|
||||
- name: Install WordPress test environment
|
||||
run: bash bin/install-wp-tests.sh wordpress_test root root 127.0.0.1:${{ job.services.mysql.ports['3306'] }} latest true
|
||||
|
||||
- name: Test with phpunit
|
||||
run: vendor/bin/phpunit
|
||||
@@ -1,86 +0,0 @@
|
||||
# GitHub Action for Yii Framework with MySQL
|
||||
name: Testing Yii2 with MySQL
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
yii:
|
||||
name: Yii2 (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DB_USERNAME: root
|
||||
DB_PASSWORD: yii
|
||||
TEST_DB_USERNAME: root
|
||||
TEST_DB_PASSWORD: yii
|
||||
DB_CHARSET: utf8
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:latest
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: false
|
||||
MYSQL_ROOT_PASSWORD: yii
|
||||
MYSQL_DATABASE: yii
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set Node.js 10.x
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 10.x
|
||||
|
||||
# Docs: https://github.com/shivammathur/setup-php
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mbstring, intl, gd, imagick, zip, dom, mysql
|
||||
coverage: xdebug
|
||||
|
||||
# Local MySQL service in GitHub hosted environments is disabled by default.
|
||||
# If you are using it instead of service containers, make sure you start it.
|
||||
# - name: Start mysql service
|
||||
# run: sudo systemctl start mysql.service
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Prepare the application
|
||||
run: |
|
||||
php -r "file_exists('.env') || copy('.env.dist', '.env');"
|
||||
php console/yii app/setup
|
||||
npm install --development
|
||||
npm run build
|
||||
env:
|
||||
DB_DSN: mysql:host=127.0.0.1;port=${{ job.services.mysql.ports['3306'] }};dbname=yii
|
||||
TEST_DB_DSN: mysql:host=127.0.0.1;port=${{ job.services.mysql.ports['3306'] }};dbname=yii
|
||||
|
||||
- name: Run Tests
|
||||
run: |
|
||||
vendor/bin/codecept build
|
||||
php tests/bin/yii app/setup --interactive=0
|
||||
nohup php -S localhost:8080 > yii.log 2>&1 &
|
||||
vendor/bin/codecept run
|
||||
env:
|
||||
DB_DSN: mysql:host=127.0.0.1;port=${{ job.services.mysql.ports['3306'] }};dbname=yii
|
||||
TEST_DB_DSN: mysql:host=127.0.0.1;port=${{ job.services.mysql.ports['3306'] }};dbname=yii
|
||||
@@ -1,86 +0,0 @@
|
||||
# GitHub Action for Yii Framework with PostgreSQL
|
||||
name: Testing Yii2 with PostgreSQL
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
yii:
|
||||
name: Yii2 (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
DB_USERNAME: postgres
|
||||
DB_PASSWORD: postgres
|
||||
TEST_DB_USERNAME: postgres
|
||||
TEST_DB_PASSWORD: postgres
|
||||
DB_CHARSET: utf8
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:latest
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: postgres
|
||||
ports:
|
||||
- 5432/tcp
|
||||
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['7.4', '8.0']
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Set Node.js 10.x
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
node-version: 10.x
|
||||
|
||||
# Docs: https://github.com/shivammathur/setup-php
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: mbstring, intl, gd, imagick, zip, dom, pgsql
|
||||
coverage: xdebug
|
||||
|
||||
# Local PostgreSQL service in GitHub hosted environments is disabled by default.
|
||||
# If you are using it instead of service containers, make sure you start it.
|
||||
# - name: Start postgresql service
|
||||
# run: sudo systemctl start postgresql.service
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Prepare the application
|
||||
run: |
|
||||
php -r "file_exists('.env') || copy('.env.dist', '.env');"
|
||||
php console/yii app/setup
|
||||
npm install --development
|
||||
npm run build
|
||||
env:
|
||||
DB_DSN: pgsql:host=127.0.0.1;port=${{ job.services.postgres.ports['5432'] }};dbname=postgres
|
||||
TEST_DB_DSN: pgsql:host=127.0.0.1;port=${{ job.services.postgres.ports['5432'] }};dbname=postgres
|
||||
|
||||
- name: Run Tests
|
||||
run: |
|
||||
vendor/bin/codecept build
|
||||
php tests/bin/yii app/setup --interactive=0
|
||||
nohup php -S localhost:8080 > yii.log 2>&1 &
|
||||
vendor/bin/codecept run
|
||||
env:
|
||||
DB_DSN: pgsql:host=127.0.0.1;port=${{ job.services.postgres.ports['5432'] }};dbname=postgres
|
||||
TEST_DB_DSN: pgsql:host=127.0.0.1;port=${{ job.services.postgres.ports['5432'] }};dbname=postgres
|
||||
78
examples/yii3-mysql.yml
Normal file
78
examples/yii3-mysql.yml
Normal file
@@ -0,0 +1,78 @@
|
||||
# GitHub Action for Yii3 web application with MySQL
|
||||
# Tested with https://github.com/yiisoft/app
|
||||
name: Testing Yii3 with MySQL
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
yii:
|
||||
name: Yii3 (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
APP_C3: true
|
||||
APP_ENV: test
|
||||
APP_DEBUG: false
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:8.4
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: false
|
||||
MYSQL_ROOT_PASSWORD: password
|
||||
MYSQL_DATABASE: app
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['8.4', '8.5']
|
||||
# The latest yiisoft/app release resolves Symfony 8.0 packages that require PHP 8.4+.
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Docs: https://github.com/shivammathur/setup-php
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: fileinfo, intl, pdo_mysql
|
||||
ini-values: date.timezone='UTC', register_argc_argv=On
|
||||
coverage: none
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Run migrations
|
||||
run: php yii migrate:up --no-interaction
|
||||
env:
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_PORT: ${{ job.services.mysql.ports['3306'] }}
|
||||
DB_NAME: app
|
||||
DB_USERNAME: root
|
||||
DB_PASSWORD: password
|
||||
|
||||
- name: Run codeception build
|
||||
run: vendor/bin/codecept build
|
||||
|
||||
- name: Run tests with Codeception
|
||||
run: vendor/bin/codecept run
|
||||
env:
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_PORT: ${{ job.services.mysql.ports['3306'] }}
|
||||
DB_NAME: app
|
||||
DB_USERNAME: root
|
||||
DB_PASSWORD: password
|
||||
78
examples/yii3-postgres.yml
Normal file
78
examples/yii3-postgres.yml
Normal file
@@ -0,0 +1,78 @@
|
||||
# GitHub Action for Yii3 web application with PostgreSQL
|
||||
# Tested with https://github.com/yiisoft/app
|
||||
name: Testing Yii3 with PostgreSQL
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
yii:
|
||||
name: Yii3 (PHP ${{ matrix.php-versions }})
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
APP_C3: true
|
||||
APP_ENV: test
|
||||
APP_DEBUG: false
|
||||
|
||||
# Docs: https://docs.github.com/en/actions/using-containerized-services
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_DB: app
|
||||
ports:
|
||||
- 5432/tcp
|
||||
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 3
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php-versions: ['8.4', '8.5']
|
||||
# The latest yiisoft/app release resolves Symfony 8.0 packages that require PHP 8.4+.
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Docs: https://github.com/shivammathur/setup-php
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: fileinfo, intl, pdo_pgsql
|
||||
ini-values: date.timezone='UTC', register_argc_argv=On
|
||||
coverage: none
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Run migrations
|
||||
run: php yii migrate:up --no-interaction
|
||||
env:
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_PORT: ${{ job.services.postgres.ports['5432'] }}
|
||||
DB_NAME: app
|
||||
DB_USERNAME: postgres
|
||||
DB_PASSWORD: postgres
|
||||
|
||||
- name: Run codeception build
|
||||
run: vendor/bin/codecept build
|
||||
|
||||
- name: Run tests with Codeception
|
||||
run: vendor/bin/codecept run
|
||||
env:
|
||||
DB_HOST: 127.0.0.1
|
||||
DB_PORT: ${{ job.services.postgres.ports['5432'] }}
|
||||
DB_NAME: app
|
||||
DB_USERNAME: postgres
|
||||
DB_PASSWORD: postgres
|
||||
53
examples/yii3.yml
Normal file
53
examples/yii3.yml
Normal file
@@ -0,0 +1,53 @@
|
||||
# GitHub Action for Yii3 web application
|
||||
# Tested with https://github.com/yiisoft/app
|
||||
name: Testing Yii3
|
||||
on: [push, pull_request]
|
||||
jobs:
|
||||
yii:
|
||||
name: Yii3 (PHP ${{ matrix.php-versions }} on ${{ matrix.operating-system }})
|
||||
runs-on: ${{ matrix.operating-system }}
|
||||
env:
|
||||
APP_C3: true
|
||||
APP_ENV: test
|
||||
APP_DEBUG: false
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
operating-system: [ubuntu-latest, windows-latest]
|
||||
php-versions: ['8.4', '8.5']
|
||||
# The latest yiisoft/app release resolves Symfony 8.0 packages that require PHP 8.4+.
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Docs: https://github.com/shivammathur/setup-php
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-versions }}
|
||||
extensions: fileinfo, intl
|
||||
ini-values: date.timezone='UTC', register_argc_argv=On
|
||||
coverage: none
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
shell: bash
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
# Use composer.json for key, if composer.lock is not committed.
|
||||
# key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }}
|
||||
key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}
|
||||
restore-keys: ${{ runner.os }}-composer-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
run: composer install --no-progress --prefer-dist --optimize-autoloader
|
||||
|
||||
- name: Run codeception build
|
||||
run: vendor/bin/codecept build
|
||||
|
||||
- name: Run tests with Codeception
|
||||
run: vendor/bin/codecept run
|
||||
4596
package-lock.json
generated
4596
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
40
package.json
40
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "setup-php",
|
||||
"version": "2.36.0",
|
||||
"version": "2.37.1",
|
||||
"private": false,
|
||||
"description": "Setup PHP for use with GitHub Actions",
|
||||
"main": "lib/install.js",
|
||||
@@ -34,36 +34,36 @@
|
||||
"author": "shivammathur",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.11.1",
|
||||
"@actions/exec": "^1.1.1",
|
||||
"@actions/io": "^2.0.0",
|
||||
"@actions/exec": "^2.0.0",
|
||||
"compare-versions": "^6.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/compat": "^2.0.0",
|
||||
"@eslint/js": "9.39.1",
|
||||
"@eslint/compat": "^2.1.0",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/jest": "^30.0.0",
|
||||
"@types/node": "^24.10.1",
|
||||
"@typescript-eslint/eslint-plugin": "^8.48.0",
|
||||
"@typescript-eslint/parser": "^8.48.0",
|
||||
"@types/node": "^25.7.0",
|
||||
"@typescript-eslint/eslint-plugin": "^8.59.3",
|
||||
"@typescript-eslint/parser": "^8.59.3",
|
||||
"@vercel/ncc": "^0.38.4",
|
||||
"eslint": "9.39.1",
|
||||
"eslint": "^10.3.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-plugin-import": "^2.32.0",
|
||||
"eslint-plugin-jest": "^29.2.1",
|
||||
"eslint-plugin-prettier": "^5.5.4",
|
||||
"globals": "^16.5.0",
|
||||
"jest": "^30.2.0",
|
||||
"jest-circus": "^30.2.0",
|
||||
"nock": "^14.0.10",
|
||||
"prettier": "^3.6.2",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-import-x": "^4.16.2",
|
||||
"eslint-plugin-jest": "^29.15.2",
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"globals": "^17.6.0",
|
||||
"jest": "^30.4.2",
|
||||
"jest-circus": "^30.4.2",
|
||||
"nock": "^14.0.15",
|
||||
"prettier": "^3.8.3",
|
||||
"simple-git-hooks": "^2.13.1",
|
||||
"ts-jest": "^29.4.5",
|
||||
"ts-jest": "^29.4.9",
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"overrides": {
|
||||
"test-exclude": "^7.0.1",
|
||||
"glob": "^11.1.0"
|
||||
"glob": "^13.0.6",
|
||||
"minimatch": "^10.2.1"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/shivammathur/setup-php/issues"
|
||||
|
||||
@@ -16,7 +16,7 @@ export async function addINIValuesUnix(
|
||||
});
|
||||
return (
|
||||
'echo "' +
|
||||
ini_values.join('\n') +
|
||||
ini_values.map(v => utils.escapeForShell(v, 'linux')).join('\n') +
|
||||
'" | sudo tee -a "${pecl_file:-${ini_file[@]}}" >/dev/null 2>&1' +
|
||||
script
|
||||
);
|
||||
@@ -37,7 +37,10 @@ export async function addINIValuesWindows(
|
||||
(await utils.addLog('$tick', line, 'Added to php.ini', 'win32')) + '\n';
|
||||
});
|
||||
return (
|
||||
'Add-Content "$php_dir\\php.ini" "' + ini_values.join('\n') + '"' + script
|
||||
'Add-Content "$php_dir\\php.ini" "' +
|
||||
ini_values.map(v => utils.escapeForShell(v, 'win32')).join('\n') +
|
||||
'"' +
|
||||
script
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,40 @@
|
||||
amqp=amqp
|
||||
apcu=apcu
|
||||
ast=ast
|
||||
brotli=brotli
|
||||
couchbase=couchbase
|
||||
ds=ds
|
||||
event=event
|
||||
excimer=excimer
|
||||
expect=expect
|
||||
gearman=gearman
|
||||
gmagick=gmagick
|
||||
gnupg=gnupg
|
||||
grpc=grpc
|
||||
igbinary=igbinary
|
||||
imagick=imagick
|
||||
imap=imap
|
||||
interbase=interbase
|
||||
lua=lua
|
||||
mailparse=mailparse
|
||||
maxminddb=maxminddb
|
||||
mcrypt=mcrypt
|
||||
memcache=memcache
|
||||
memcached=memcached
|
||||
mongodb=mongodb
|
||||
mongodb1=mongodb1
|
||||
msgpack=msgpack
|
||||
newrelic=newrelic
|
||||
oauth=oauth
|
||||
opentelemetry=opentelemetry
|
||||
pcov=pcov
|
||||
pdo_firebird=pdo_firebird
|
||||
pdo_sqlsrv=pdo_sqlsrv
|
||||
pecl_http=http
|
||||
phalcon3=phalcon
|
||||
phalcon4=phalcon
|
||||
phalcon5=phalcon
|
||||
pinba=pinba
|
||||
propro=propro
|
||||
protobuf=protobuf
|
||||
psr=psr
|
||||
@@ -31,16 +42,24 @@ raphf=raphf
|
||||
rdkafka=rdkafka
|
||||
phpredis=redis
|
||||
redis=redis
|
||||
seaslog=seaslog
|
||||
scalar_objects=scalar_objects
|
||||
snmp=snmp
|
||||
sqlsrv=sqlsrv
|
||||
spx=spx
|
||||
ssh2=ssh2
|
||||
swoole=swoole
|
||||
swow=swow
|
||||
uopz=uopz
|
||||
uploadprogress=uploadprogress
|
||||
uuid=uuid
|
||||
v8js=v8js
|
||||
vips=vips
|
||||
vld=vld
|
||||
xdebug=xdebug
|
||||
xdebug2=xdebug
|
||||
xhprof=xhprof
|
||||
xlswriter=xlswriter
|
||||
yaml=yaml
|
||||
zmq=zmq
|
||||
zstd=zstd
|
||||
|
||||
3
src/configs/composer-gh-auth-no-op
Normal file
3
src/configs/composer-gh-auth-no-op
Normal file
@@ -0,0 +1,3 @@
|
||||
1.0.0-0 1.10.28
|
||||
2.0.0-0 2.2.28
|
||||
2.3.0-0 2.9.8
|
||||
1
src/configs/composer-gh-auth-warn
Normal file
1
src/configs/composer-gh-auth-warn
Normal file
@@ -0,0 +1 @@
|
||||
Composer %s has a known GitHub token parsing bug that exposes GitHub tokens in the error output. So, GitHub authentication has not been configured for this Composer version. Please update to the latest version of Composer. See: https://github.com/composer/composer/security/advisories/GHSA-f9f8-rm49-7jv2
|
||||
@@ -21,4 +21,7 @@
|
||||
23.10,mantic
|
||||
24.04,noble
|
||||
24.10,oracular
|
||||
25.10,plucky
|
||||
25.05,plucky
|
||||
25.10,questing
|
||||
26.04,resolute
|
||||
26.10,stonking
|
||||
|
||||
|
112
src/core.ts
Normal file
112
src/core.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import {EOL} from 'os';
|
||||
|
||||
/**
|
||||
* Commands
|
||||
*
|
||||
* Command Format:
|
||||
* ::name key=value,key=value::message
|
||||
*
|
||||
* @see https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions
|
||||
*/
|
||||
|
||||
interface CommandProperties {
|
||||
[key: string]: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes the message for use in a workflow command.
|
||||
* @param message
|
||||
*/
|
||||
function toCommandValue(message: string | Error): string {
|
||||
if (message instanceof Error) {
|
||||
return message.toString();
|
||||
}
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes data for safe use in workflow command messages.
|
||||
* @param s
|
||||
*/
|
||||
function escapeData(s: string | Error): string {
|
||||
return toCommandValue(s)
|
||||
.replace(/%/g, '%25')
|
||||
.replace(/\r/g, '%0D')
|
||||
.replace(/\n/g, '%0A');
|
||||
}
|
||||
|
||||
/**
|
||||
* Escapes property values for safe use in workflow command properties.
|
||||
* @param s
|
||||
*/
|
||||
function escapeProperty(s: string): string {
|
||||
return s
|
||||
.replace(/%/g, '%25')
|
||||
.replace(/\r/g, '%0D')
|
||||
.replace(/\n/g, '%0A')
|
||||
.replace(/:/g, '%3A')
|
||||
.replace(/,/g, '%2C');
|
||||
}
|
||||
|
||||
/**
|
||||
* Issues a command to the GitHub Actions runner.
|
||||
*
|
||||
* @param command - The command name to issue
|
||||
* @param properties - Additional properties for the command (key-value pairs)
|
||||
* @param message - The message to include with the command
|
||||
*/
|
||||
export function issueCommand(
|
||||
command: string,
|
||||
properties: CommandProperties,
|
||||
message: string | Error
|
||||
): void {
|
||||
let cmdStr = `::${command}`;
|
||||
|
||||
if (properties && Object.keys(properties).length > 0) {
|
||||
cmdStr += ' ';
|
||||
const props = Object.entries(properties)
|
||||
.filter(([, val]) => val)
|
||||
.map(([key, val]) => `${key}=${escapeProperty(val)}`)
|
||||
.join(',');
|
||||
cmdStr += props;
|
||||
}
|
||||
|
||||
cmdStr += `::${escapeData(message)}`;
|
||||
process.stdout.write(cmdStr + EOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an error issue.
|
||||
* @param message - error issue message
|
||||
*/
|
||||
export function error(message: string | Error): void {
|
||||
issueCommand('error', {}, message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the action status to failed.
|
||||
* When the action exits it will be with an exit code of 1.
|
||||
* @param message - add error issue message
|
||||
*/
|
||||
export function setFailed(message: string | Error): void {
|
||||
process.exitCode = 1;
|
||||
error(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of an input.
|
||||
* The value is trimmed.
|
||||
* Returns an empty string if the value is not defined.
|
||||
*
|
||||
* @param name - name of the input to get
|
||||
* @param required - whether the input is required
|
||||
* @returns string
|
||||
*/
|
||||
export function getInput(name: string, required = false): string {
|
||||
const val: string =
|
||||
process.env[`INPUT_${name.replace(/ /g, '_').toUpperCase()}`] || '';
|
||||
if (required && !val) {
|
||||
throw new Error(`Input required and not supplied: ${name}`);
|
||||
}
|
||||
return val.trim();
|
||||
}
|
||||
@@ -35,9 +35,9 @@ export async function addExtensionDarwin(
|
||||
// match 5.3blackfire...8.5blackfire
|
||||
// match 5.3blackfire-(semver)...8.5blackfire-(semver)
|
||||
// match couchbase, event, geos, ibm_db2, pdo_ibm, pdo_oci, oci8, http, pecl_http
|
||||
// match 5.3ioncube...8.4ioncube
|
||||
// match 5.3ioncube...8.5ioncube
|
||||
// match 7.0phalcon3...7.3phalcon3, 7.2phalcon4...7.4phalcon4, and 7.4phalcon5...8.4phalcon5
|
||||
// match 7.0zephir_parser...8.4zephir_parser
|
||||
// match 7.0zephir_parser...8.5zephir_parser
|
||||
case /^(7\.4|8\.[0-5])relay(-v?\d+\.\d+\.\d+|-nightly)?$/.test(
|
||||
version_extension
|
||||
):
|
||||
@@ -47,12 +47,12 @@ export async function addExtensionDarwin(
|
||||
case /^couchbase|^event|^gearman$|^geos$|^ibm_db2$|^pdo_ibm$|^pdo_oci$|^oci8$|^(pecl_)?http|^pdo_firebird$/.test(
|
||||
extension
|
||||
):
|
||||
case /^(5\.[3-6]|7\.[0-4]|8\.[0-4])ioncube$/.test(version_extension):
|
||||
case /^(5\.[3-6]|7\.[0-4]|8\.[0-5])ioncube$/.test(version_extension):
|
||||
case /(5\.6|7\.[0-3])phalcon3|7\.[2-4]phalcon4|(7\.4|8\.[0-4])phalcon5?/.test(
|
||||
version_extension
|
||||
):
|
||||
case /(?<!5\.[3-6])(pdo_)?sqlsrv$/.test(version_extension):
|
||||
case /^(7\.[0-4]|8\.[0-4])zephir_parser(-v?\d+\.\d+\.\d+)?$/.test(
|
||||
case /^(7\.[0-4]|8\.[0-5])zephir_parser(-v?\d+\.\d+\.\d+)?$/.test(
|
||||
version_extension
|
||||
):
|
||||
add_script += await utils.customPackage(
|
||||
@@ -85,13 +85,14 @@ export async function addExtensionDarwin(
|
||||
add_script += await utils.getUnsupportedLog('pcov', version, 'darwin');
|
||||
return;
|
||||
// match brew extensions
|
||||
case /(?<!5\.[3-5])(amqp|apcu|expect|gnupg|grpc|igbinary|imagick|imap|mailparse|mcrypt|memcache|memcached|mongodb|msgpack|protobuf|psr|raphf|rdkafka|redis|snmp|ssh2|swoole|uuid|vld|xdebug|xdebug2|yaml|zmq)/.test(
|
||||
case /(?<!5\.[3-5])(amqp|apcu|brotli|excimer|expect|gmagick|gnupg|grpc|igbinary|imagick|imap|interbase|mailparse|maxminddb|mcrypt|memcache|memcached|mongodb|mongodb1|msgpack|newrelic|oauth|opentelemetry|pdo_firebird|pinba|protobuf|psr|raphf|rdkafka|redis|scalar_objects|seaslog|snmp|spx|ssh2|swoole|uopz|uploadprogress|uuid|vld|xdebug|xdebug2|xhprof|yaml|zmq|zstd)/.test(
|
||||
version_extension
|
||||
):
|
||||
case /(?<!5\.[3-6])(ds|v8js)/.test(version_extension):
|
||||
case /(5\.6|7\.[0-4])(propro|lua)/.test(version_extension):
|
||||
case /(?<!5\.[3-6]|7\.0)pcov/.test(version_extension):
|
||||
case /(?<!5\.[3-6])(ast|vips|xlswriter)/.test(version_extension):
|
||||
case /^(8\.[0-5])swow$/.test(version_extension):
|
||||
add_script += await utils.joins(
|
||||
'\nadd_brew_extension',
|
||||
ext_name,
|
||||
@@ -139,23 +140,23 @@ export async function addExtensionWindows(
|
||||
// match 5.3blackfire...8.5blackfire
|
||||
// match 5.3blackfire-(semver)...8.5blackfire-(semver)
|
||||
// match ibm_db2, pdo_ibm, pdo_oci and oci8
|
||||
// match 5.3ioncube...8.4ioncube
|
||||
// match 5.3ioncube...8.5ioncube
|
||||
// match 7.0phalcon3...7.3phalcon3, 7.2phalcon4...7.4phalcon4, and 7.4phalcon5...8.4phalcon5
|
||||
// match 7.1pecl_http...8.1pecl_http and 7.1http...8.1http
|
||||
// match 7.0zephir_parser...8.4zephir_parser
|
||||
// match 7.1pecl_http...8.5pecl_http and 7.1http...8.5http
|
||||
// match 7.0zephir_parser...8.5zephir_parser
|
||||
case /^(5\.[3-6]|7\.[0-4]|8\.[0-5])blackfire(-\d+\.\d+\.\d+)?$/.test(
|
||||
version_extension
|
||||
):
|
||||
case /^ibm_db2$|^pdo_ibm$|^pdo_oci$|^oci8$|^pdo_firebird$/.test(
|
||||
extension
|
||||
):
|
||||
case /^(5\.[3-6]|7\.[0-4]|8\.[0-4])ioncube$/.test(version_extension):
|
||||
case /^(5\.[3-6]|7\.[0-4]|8\.[0-5])ioncube$/.test(version_extension):
|
||||
case /^7\.[0-3]phalcon3$|^7\.[2-4]phalcon4$|^(7\.4|8\.[0-4])phalcon5?$/.test(
|
||||
version_extension
|
||||
):
|
||||
case /^(7\.[1-4]|8\.1)(pecl_)?http/.test(version_extension):
|
||||
case /^(7\.[1-4]|8\.[0-5])(pecl_)?http/.test(version_extension):
|
||||
case /(?<!5\.[3-6])(pdo_)?sqlsrv$/.test(version_extension):
|
||||
case /^(7\.[0-4]|8\.[0-4])zephir_parser(-v?\d+\.\d+\.\d+)?$/.test(
|
||||
case /^(7\.[0-4]|8\.[0-5])zephir_parser(-v?\d+\.\d+\.\d+)?$/.test(
|
||||
version_extension
|
||||
):
|
||||
add_script += await utils.customPackage(
|
||||
@@ -272,9 +273,9 @@ export async function addExtensionLinux(
|
||||
// match 5.3blackfire-(semver)...8.5blackfire-(semver)
|
||||
// match 5.3pdo_cubrid...7.2php_cubrid, 5.3cubrid...7.4cubrid
|
||||
// match couchbase, geos, ibm_db2, pdo_ibm, pdo_oci, oci8, http, pecl_http
|
||||
// match 5.3ioncube...8.4ioncube
|
||||
// match 5.3ioncube...8.5ioncube
|
||||
// match 7.0phalcon3...7.3phalcon3, 7.2phalcon4...7.4phalcon4, 7.4phalcon5...8.4phalcon5
|
||||
// match 7.0zephir_parser...8.4zephir_parser
|
||||
// match 7.0zephir_parser...8.5zephir_parser
|
||||
case /^(7\.4|8\.[0-5])relay(-v?\d+\.\d+\.\d+|-nightly)?$/.test(
|
||||
version_extension
|
||||
):
|
||||
@@ -288,12 +289,12 @@ export async function addExtensionLinux(
|
||||
extension
|
||||
):
|
||||
case /(?<!5\.[3-5])intl-\d+\.\d+$/.test(version_extension):
|
||||
case /^(5\.[3-6]|7\.[0-4]|8\.[0-4])ioncube$/.test(version_extension):
|
||||
case /^(5\.[3-6]|7\.[0-4]|8\.[0-5])ioncube$/.test(version_extension):
|
||||
case /^7\.[0-3]phalcon3$|^7\.[2-4]phalcon4$|^(7\.4|8\.[0-4])phalcon5?$/.test(
|
||||
version_extension
|
||||
):
|
||||
case /(?<!5\.[3-6])(pdo_)?sqlsrv$/.test(version_extension):
|
||||
case /^(7\.[0-4]|8\.[0-4])zephir_parser(-v?\d+\.\d+\.\d+)?$/.test(
|
||||
case /^(7\.[0-4]|8\.[0-5])zephir_parser(-v?\d+\.\d+\.\d+)?$/.test(
|
||||
version_extension
|
||||
):
|
||||
add_script += await utils.customPackage(
|
||||
|
||||
70
src/fetch.ts
70
src/fetch.ts
@@ -1,9 +1,10 @@
|
||||
import {IncomingMessage, OutgoingHttpHeaders} from 'http';
|
||||
import * as https from 'https';
|
||||
import * as url from 'url';
|
||||
/**
|
||||
* Redirect status codes set for O(1) lookup
|
||||
*/
|
||||
const REDIRECT_CODES = new Set([301, 302, 303, 307, 308]);
|
||||
|
||||
/**
|
||||
* Function to fetch a URL
|
||||
* Function to fetch a URL using native fetch API (Node 24+)
|
||||
*
|
||||
* @param input_url
|
||||
* @param auth_token
|
||||
@@ -14,43 +15,28 @@ export async function fetch(
|
||||
auth_token?: string,
|
||||
redirect_count = 5
|
||||
): Promise<Record<string, string>> {
|
||||
const fetch_promise: Promise<Record<string, string>> = new Promise(
|
||||
resolve => {
|
||||
const url_object: url.UrlObject = new url.URL(input_url);
|
||||
const headers: OutgoingHttpHeaders = {
|
||||
'User-Agent': `Mozilla/5.0 (${process.platform} ${process.arch}) setup-php`
|
||||
};
|
||||
if (auth_token) {
|
||||
headers.authorization = 'Bearer ' + auth_token;
|
||||
}
|
||||
const options: https.RequestOptions = {
|
||||
hostname: url_object.hostname,
|
||||
path: url_object.pathname,
|
||||
headers: headers,
|
||||
agent: new https.Agent({keepAlive: false})
|
||||
};
|
||||
const req = https.get(options, (res: IncomingMessage) => {
|
||||
if (res.statusCode === 200) {
|
||||
let body = '';
|
||||
res.setEncoding('utf8');
|
||||
res.on('data', chunk => (body += chunk));
|
||||
res.on('end', () => resolve({data: `${body}`}));
|
||||
} else if (
|
||||
[301, 302, 303, 307, 308].includes(res.statusCode as number)
|
||||
) {
|
||||
if (redirect_count > 0 && res.headers.location) {
|
||||
fetch(res.headers.location, auth_token, redirect_count--).then(
|
||||
resolve
|
||||
);
|
||||
} else {
|
||||
resolve({error: `${res.statusCode}: Redirect error`});
|
||||
}
|
||||
} else {
|
||||
resolve({error: `${res.statusCode}: ${res.statusMessage}`});
|
||||
}
|
||||
});
|
||||
req.end();
|
||||
const headers: Record<string, string> = {
|
||||
'User-Agent': `Mozilla/5.0 (${process.platform} ${process.arch}) setup-php`
|
||||
};
|
||||
if (auth_token) {
|
||||
headers['Authorization'] = 'Bearer ' + auth_token;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await globalThis.fetch(input_url, {
|
||||
headers,
|
||||
redirect: redirect_count > 0 ? 'follow' : 'manual'
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const data = await response.text();
|
||||
return {data};
|
||||
} else if (REDIRECT_CODES.has(response.status) && redirect_count <= 0) {
|
||||
return {error: `${response.status}: Redirect error`};
|
||||
} else {
|
||||
return {error: `${response.status}: ${response.statusText}`};
|
||||
}
|
||||
);
|
||||
return await fetch_promise;
|
||||
} catch (error) {
|
||||
return {error: `Fetch error: ${(error as Error).message}`};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import {exec} from '@actions/exec';
|
||||
import * as core from '@actions/core';
|
||||
import * as config from './config';
|
||||
import * as core from './core';
|
||||
import * as coverage from './coverage';
|
||||
import * as extensions from './extensions';
|
||||
import * as tools from './tools';
|
||||
@@ -18,7 +18,10 @@ export async function getScript(os: string): Promise<string> {
|
||||
const filename = os + (await utils.scriptExtension(os));
|
||||
const script_path = path.join(__dirname, '../src/scripts', filename);
|
||||
const run_path = script_path.replace(os, 'run');
|
||||
const extension_csv: string = await utils.getInput('extensions', false);
|
||||
const extension_csv: string = utils.sanitizeShellInput(
|
||||
await utils.getInput('extensions', false),
|
||||
true
|
||||
);
|
||||
const ini_values_csv: string = await utils.getInput('ini-values', false);
|
||||
const coverage_driver: string = await utils.getInput('coverage', false);
|
||||
const tools_csv: string = await utils.getInput('tools', false);
|
||||
@@ -28,7 +31,7 @@ export async function getScript(os: string): Promise<string> {
|
||||
const ini_file: string = await utils.parseIniFile(
|
||||
await utils.getInput('ini-file', false)
|
||||
);
|
||||
let script = await utils.joins('.', script_path, version, ini_file);
|
||||
let script = await utils.joins('.', script_path, `'${version}'`, ini_file);
|
||||
if (extension_csv) {
|
||||
script += await extensions.addExtension(extension_csv, version, os);
|
||||
}
|
||||
|
||||
@@ -15,7 +15,9 @@ handle_dependency_extensions() {
|
||||
brew_opts=(-sf)
|
||||
patch_abstract_file >/dev/null 2>&1
|
||||
for dependency_extension in "${dependency_extensions[@]}"; do
|
||||
brew install "${brew_opts[@]}" "$ext_tap/$dependency_extension@$version" >/dev/null 2>&1 && copy_brew_extensions "$dependency_extension"
|
||||
safe_brew install --skip-link "${brew_opts[@]}" "$ext_tap/$dependency_extension@$version" >/dev/null 2>&1 &&
|
||||
brew link --overwrite --force "$dependency_extension@$version" >/dev/null 2>&1 &&
|
||||
copy_brew_extensions "$dependency_extension"
|
||||
done
|
||||
fi
|
||||
}
|
||||
@@ -83,7 +85,11 @@ add_brew_extension() {
|
||||
formula="$(get_renamed_formula "$formula")"
|
||||
update_dependencies >/dev/null 2>&1
|
||||
handle_dependency_extensions "$formula" "$extension" >/dev/null 2>&1
|
||||
(brew install "${brew_opts[@]}" "$ext_tap/$formula@$version" >/dev/null 2>&1 && copy_brew_extensions "$formula") || pecl_install "$extension" >/dev/null 2>&1
|
||||
(
|
||||
safe_brew install --skip-link "${brew_opts[@]}" "$ext_tap/$formula@$version" >/dev/null 2>&1 &&
|
||||
brew link --overwrite --force "$formula@$version" >/dev/null 2>&1 &&
|
||||
copy_brew_extensions "$formula"
|
||||
) || pecl_install "$extension" >/dev/null 2>&1
|
||||
add_extension_log "$extension" "Installed and enabled"
|
||||
fi
|
||||
}
|
||||
@@ -181,14 +187,14 @@ add_php() {
|
||||
fi
|
||||
if [[ "$existing_version" != "false" && -z "$suffix" ]]; then
|
||||
if [ "$action" = "upgrade" ]; then
|
||||
brew install --only-dependencies "$php_formula"
|
||||
brew upgrade -f --overwrite "$php_formula"
|
||||
safe_brew install --only-dependencies "$php_formula"
|
||||
safe_brew upgrade -f --overwrite "$php_formula"
|
||||
else
|
||||
brew unlink "$php_keg"
|
||||
fi
|
||||
else
|
||||
brew install --only-dependencies "$php_formula"
|
||||
brew install -f --overwrite "$php_formula" 2>/dev/null || brew upgrade -f --overwrite "$php_formula"
|
||||
safe_brew install --only-dependencies "$php_formula"
|
||||
safe_brew install --skip-link -f --overwrite "$php_formula" 2>/dev/null || safe_brew upgrade -f --overwrite "$php_formula"
|
||||
fi
|
||||
brew link --force --overwrite "$php_keg" || (sudo chown -R "$(id -un)":"$(id -gn)" "$brew_prefix" && brew link --force --overwrite "$php_keg")
|
||||
}
|
||||
|
||||
@@ -79,9 +79,20 @@ add_couchbase() {
|
||||
add_extension_log "couchbase" "Installed and enabled"
|
||||
fi
|
||||
else
|
||||
if [ -e "${ext_dir:?}"/libcouchbase_php_core.dylib ]; then
|
||||
sudo cp "${ext_dir:?}"/libcouchbase_php_core.dylib "${brew_prefix:?}"/lib
|
||||
if [ -e "${ext_dir:?}/couchbase.so" ]; then
|
||||
couchbase_rpath="$(otool -l "${ext_dir:?}/couchbase.so" 2>/dev/null | awk '$1 == "path" && $2 ~ /\/couchbase@'"${version:?}"'\// {print $2; exit}')"
|
||||
couchbase_rpath="${couchbase_rpath/@loader_path/${ext_dir:?}}"
|
||||
otool -L "${ext_dir:?}/couchbase.so" 2>/dev/null |
|
||||
awk -v rpath="$couchbase_rpath" '/libcouchbase_php.*\.dylib/ {if ($1 ~ /^@rpath\// && rpath != "") {sub(/^@rpath/, rpath, $1)}; print $1}' |
|
||||
while read -r dylib; do
|
||||
dylib="${dylib/@loader_path/${ext_dir:?}}"
|
||||
[ -e "${ext_dir:?}/$(basename "$dylib")" ] || continue
|
||||
sudo mkdir -p "$(dirname "$dylib")"
|
||||
sudo cp "${ext_dir:?}/$(basename "$dylib")" "$dylib"
|
||||
done
|
||||
fi
|
||||
add_brew_extension couchbase extension
|
||||
find "${brew_prefix:?}/lib" "${brew_prefix:?}/opt/couchbase@${version:?}" "${brew_prefix:?}/Cellar/couchbase@${version:?}" \
|
||||
-name 'libcouchbase_php*.dylib' -exec sudo cp {} "${ext_dir:?}" \; >/dev/null 2>&1
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -1,17 +1,3 @@
|
||||
add_firebird_client_darwin() {
|
||||
firebird_tag='v5.0.0'
|
||||
arch_name='x64'
|
||||
arch="$(uname -m)"
|
||||
[[ "$arch" = "arm64" || "$arch" = "aarch64" ]] && arch_name='arm64'
|
||||
pkg_name=$(get -s -n "" https://api.github.com/repos/FirebirdSQL/firebird/releases/tags/"$firebird_tag" | grep -Eo "Firebird-.*.-$arch_name.pkg" | head -n 1)
|
||||
[ -z "$pkg_name" ] && pkg_name=$(get -s -n "" https://github.com/FirebirdSQL/firebird/releases/expanded_assets/"$firebird_tag" | grep -Eo "Firebird-.*.-$arch_name.pkg" | head -n 1)
|
||||
get -q -e "/tmp/firebird.pkg" https://github.com/FirebirdSQL/firebird/releases/download/"$firebird_tag"/"$pkg_name"
|
||||
sudo installer -pkg /tmp/firebird.pkg -target /
|
||||
sudo mkdir -p /opt/firebird/include /opt/firebird/lib
|
||||
sudo cp -a /Library/Frameworks/Firebird.framework/Headers/* /opt/firebird/include/
|
||||
sudo find /Library/Frameworks/Firebird.framework -name '*.dylib' -exec cp "{}" /opt/firebird/lib \;
|
||||
}
|
||||
|
||||
add_firebird_helper() {
|
||||
firebird_dir=$1
|
||||
tag="$(php_src_tag)"
|
||||
@@ -23,22 +9,19 @@ add_firebird_helper() {
|
||||
}
|
||||
|
||||
add_firebird() {
|
||||
if [ "$(uname -s )" = "Darwin" ]; then
|
||||
add_firebird_client_darwin >/dev/null 2>&1
|
||||
fi
|
||||
enable_extension pdo_firebird extension
|
||||
status="Enabled"
|
||||
if ! check_extension pdo_firebird; then
|
||||
status="Installed and enabled"
|
||||
if check_extension pdo_firebird; then
|
||||
add_log "${tick:?}" pdo_firebird Enabled
|
||||
else
|
||||
if [ "$(uname -s)" = "Linux" ]; then
|
||||
if [[ "${version:?}" =~ 5.3|${nightly_versions:?} ]]; then
|
||||
if [[ "${version:?}" =~ 5.3|${php_builder_versions:?} ]]; then
|
||||
add_firebird_helper /usr >/dev/null 2>&1
|
||||
else
|
||||
add_pdo_extension firebird >/dev/null 2>&1
|
||||
fi
|
||||
else
|
||||
add_firebird_helper /opt/firebird >/dev/null 2>&1
|
||||
add_brew_extension pdo_firebird extension >/dev/null 2>&1
|
||||
fi
|
||||
add_extension_log pdo_firebird "Installed and enabled"
|
||||
fi
|
||||
add_extension_log pdo_firebird "$status"
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Helper function to add gearman extension.
|
||||
add_gearman_helper() {
|
||||
install_packages libgearman-dev
|
||||
enable_extension gearman extension
|
||||
if ! check_extension gearman; then
|
||||
status="Installed and enabled"
|
||||
install_packages libgearman-dev
|
||||
if [[ "${version:?}" =~ 5.[3-6] ]]; then
|
||||
pecl_install gearman-1.1.2
|
||||
elif [[ "${version:?}" =~ 7.0 ]]; then
|
||||
|
||||
@@ -10,13 +10,15 @@ Function Get-ICUUrl() {
|
||||
[ValidateNotNull()]
|
||||
$vs_version
|
||||
)
|
||||
$trunk = "https://windows.php.net"
|
||||
$urls=@("${trunk}/downloads/php-sdk/deps/${vs_version}/${arch}", "${trunk}/downloads/php-sdk/deps/archives/${vs_version}/${arch}")
|
||||
$trunk = "https://downloads.php.net"
|
||||
$urls=@("${trunk}/~windows/php-sdk/deps/${vs_version}/${arch}/", "${trunk}/~windows/php-sdk/deps/archives/${vs_version}/${arch}/")
|
||||
foreach ($url in $urls) {
|
||||
$web_content = Get-File -Url $url
|
||||
try {
|
||||
$web_content = Get-File -Url $url 2>$null
|
||||
} catch { continue }
|
||||
foreach ($link in $web_content.Links) {
|
||||
if ($link -match "/.*ICU-${icu_version}.*/") {
|
||||
return $trunk + $link.HREF
|
||||
if ($link.href -match ".*ICU-${icu_version}.*") {
|
||||
return $url + $link.HREF
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,26 +19,6 @@ Function Get-PhalconReleaseAssetUrl() {
|
||||
$match = (Get-File -Url "$github/$releases/expanded_assets/v$Semver").Links.href | Select-String -Pattern "(phalcon_${arch}_.*_php${version}_${extension_version}.*[0-9]${nts}.zip)"
|
||||
} catch { }
|
||||
}
|
||||
} else {
|
||||
$nts = if (!$installed.ThreadSafe) { "-nts" } else { "-ts" }
|
||||
try {
|
||||
$match = (Invoke-RestMethod -Uri "$domain/$releases/tags/v$Semver").assets | Select-String -Pattern "browser_download_url=.*(php_phalcon-php${version}${nts}-windows.*-x64.zip)"
|
||||
} catch { }
|
||||
if($null -eq $match) {
|
||||
try {
|
||||
$match = (Get-File -Url "$github/$releases/expanded_assets/v$Semver").Links.href | Select-String -Pattern "(php_phalcon-php${version}${nts}-windows.*-x64.zip)"
|
||||
} catch { }
|
||||
}
|
||||
if($null -eq $match) {
|
||||
try {
|
||||
$match = (Invoke-RestMethod -Uri "$domain/$releases/tags/v$Semver").assets | Select-String -Pattern "browser_download_url=.*(phalcon-php${version}${nts}-windows.*-x64.zip)"
|
||||
} catch { }
|
||||
}
|
||||
if($null -eq $match) {
|
||||
try {
|
||||
$match = (Get-File -Url "$github/$releases/expanded_assets/v$Semver").Links.href | Select-String -Pattern "(phalcon-php${version}${nts}-windows.*-x64.zip)"
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
if($NULL -ne $match) {
|
||||
return "$github/$releases/download/v$Semver/$($match.Matches[0].Groups[1].Value)"
|
||||
@@ -73,6 +53,8 @@ Function Get-PhalconSemver() {
|
||||
return '4.1.0'
|
||||
} elseif (($extension_version -eq '5') -and ($version -eq '7.4')) {
|
||||
return '5.4.0'
|
||||
} elseif (($extension_version -eq '5') -and ($version -eq '8.0')) {
|
||||
return '5.10.0'
|
||||
}
|
||||
return Get-PeclPackageVersion phalcon $extension_version stable stable | Select-Object -First 1
|
||||
}
|
||||
@@ -80,7 +62,7 @@ Function Get-PhalconSemver() {
|
||||
# Function to install phalcon
|
||||
Function Add-PhalconHelper() {
|
||||
$semver = Get-PhalconSemver
|
||||
if ($extension_version -eq '3') {
|
||||
if ($extension_version -match '[3-4]') {
|
||||
Add-PhalconFromGitHub $semver
|
||||
} else {
|
||||
Add-Extension -Extension phalcon -Stability stable -Extension_version $semver
|
||||
|
||||
@@ -3,6 +3,8 @@ get_phalcon_version() {
|
||||
if [ "$extension" = "phalcon5" ]; then
|
||||
if [ "${version:?}" = "7.4" ]; then
|
||||
echo '5.4.0'
|
||||
elif [ "${version:?}" = "8.0" ]; then
|
||||
echo '5.10.0'
|
||||
else
|
||||
get_pecl_version phalcon stable 5
|
||||
fi
|
||||
|
||||
@@ -36,7 +36,10 @@ get_openssl_suffix() {
|
||||
change_library_paths() {
|
||||
if [ "$os" = "Darwin" ]; then
|
||||
otool -L "${ext_dir:?}"/relay.so | grep -q 'ssl.1' && openssl_version='1.1' || openssl_version='3'
|
||||
[ -e "${brew_prefix:?}"/opt/openssl@"$openssl_version" ] || brew install openssl@"$openssl_version"
|
||||
[ -e "${brew_prefix:?}"/opt/openssl@"$openssl_version" ] || {
|
||||
safe_brew install --skip-link openssl@"$openssl_version" &&
|
||||
brew link --overwrite --force openssl@"$openssl_version"
|
||||
}
|
||||
dylibs="$(otool -L "${ext_dir:?}"/relay.so | grep -Eo '.*\.dylib' | cut -f1 -d ' ')"
|
||||
install_name_tool -change "$(echo "${dylibs}" | grep -E "libzstd.*dylib" | xargs)" "$brew_prefix"/opt/zstd/lib/libzstd.dylib "$ext_dir"/relay.so
|
||||
install_name_tool -change "$(echo "${dylibs}" | grep -E "liblz4.*dylib" | xargs)" "$brew_prefix"/opt/lz4/lib/liblz4.dylib "$ext_dir"/relay.so
|
||||
@@ -54,7 +57,7 @@ add_relay_dependencies() {
|
||||
if [ "$os" = "Darwin" ]; then
|
||||
. "${0%/*}"/tools/brew.sh
|
||||
configure_brew
|
||||
brew install lz4 hiredis zstd concurrencykit
|
||||
safe_brew install lz4 hiredis zstd concurrencykit
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
@@ -60,9 +60,11 @@ add_linux_libs() {
|
||||
add_darwin_libs() {
|
||||
local lib=$1
|
||||
if ! check_lib "$lib"; then
|
||||
brew install "$lib" >/dev/null 2>&1 || true
|
||||
if [[ "$lib" = *@* ]]; then
|
||||
safe_brew install --skip-link "$lib" >/dev/null 2>&1 || true
|
||||
brew link --overwrite --force "$lib" >/dev/null 2>&1 || true
|
||||
else
|
||||
safe_brew install "$lib" >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
add_lib_log "$lib"
|
||||
|
||||
@@ -9,6 +9,8 @@ Function Get-SqlsrvReleaseVersion() {
|
||||
return '5.10.1'
|
||||
} elseif ($version -eq '8.0') {
|
||||
return '5.11.1'
|
||||
} elseif ($version -match '8.[1-2]') {
|
||||
return '5.12.0'
|
||||
} else {
|
||||
return 'latest'
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ get_sqlsrv_version() {
|
||||
echo '5.10.1'
|
||||
elif [[ "${version:?}" =~ 8.0 ]]; then
|
||||
echo '5.11.1'
|
||||
elif [[ "${version:?}" =~ 8.[1-2] ]]; then
|
||||
echo '5.12.0'
|
||||
else
|
||||
# Return an empty string so that pecl will install the latest version.
|
||||
echo ''
|
||||
|
||||
@@ -127,6 +127,51 @@ setup_cached_versions() {
|
||||
run_script "php-ubuntu" "$version" "${debug:?}" "${ts:?}"
|
||||
}
|
||||
|
||||
# Function to get the link path for an alternative.
|
||||
alternative_link() {
|
||||
case "$1" in
|
||||
php-cgi-bin) echo "/usr/lib/cgi-bin/php" ;;
|
||||
php-fpm) echo "/usr/sbin/php-fpm" ;;
|
||||
php-fpm.sock) echo "/run/php/php-fpm.sock" ;;
|
||||
*) echo "/usr/bin/$1" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Function to get the target path for an alternative.
|
||||
alternative_target() {
|
||||
case "$1" in
|
||||
php-cgi-bin) echo "/usr/lib/cgi-bin/php$version" ;;
|
||||
php-fpm) echo "/usr/sbin/php-fpm$version" ;;
|
||||
php-fpm.sock) echo "/run/php/php$version-fpm.sock" ;;
|
||||
*) echo "/usr/bin/$1$version" ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Function to register an alternative if the versioned binary exists but is missing.
|
||||
register_alternative() {
|
||||
local tool=$1
|
||||
local link target priority state_file
|
||||
target="$(alternative_target "$tool")"
|
||||
[ -e "$target" ] || return 0
|
||||
state_file="/var/lib/dpkg/alternatives/$tool"
|
||||
if sudo test -r "$state_file" && sudo grep -Fxq "$target" "$state_file"; then
|
||||
return 0
|
||||
fi
|
||||
link="$(alternative_link "$tool")"
|
||||
priority="${version//./}"
|
||||
sudo update-alternatives --install "$link" "$tool" "$target" "$priority" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Function to register and switch an alternative.
|
||||
set_alternative() {
|
||||
local tool=$1
|
||||
local target
|
||||
target="$(alternative_target "$tool")"
|
||||
[ -e "$target" ] || return 0
|
||||
register_alternative "$tool" || return 1
|
||||
sudo update-alternatives --set "$tool" "$target" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
# Function to add PECL.
|
||||
add_pecl() {
|
||||
add_devtools phpize >/dev/null 2>&1
|
||||
@@ -143,16 +188,11 @@ switch_version() {
|
||||
tools=("$@")
|
||||
to_wait=()
|
||||
if ! (( ${#tools[@]} )); then
|
||||
tools+=(pear pecl php phar phar.phar php-cgi php-config phpize phpdbg)
|
||||
[ -e /usr/lib/cgi-bin/php"$version" ] && sudo update-alternatives --set php-cgi-bin /usr/lib/cgi-bin/php"$version" & to_wait+=($!)
|
||||
[ -e /usr/sbin/php-fpm"$version" ] && sudo update-alternatives --set php-fpm /usr/sbin/php-fpm"$version" & to_wait+=($!)
|
||||
[ -e /run/php/php"$version"-fpm.sock ] && sudo update-alternatives --set php-fpm.sock /run/php/php"$version"-fpm.sock & to_wait+=($!)
|
||||
tools+=(php-cgi-bin php-fpm php-fpm.sock pear pecl php phar phar.phar php-cgi php-config phpize phpdbg)
|
||||
fi
|
||||
for tool in "${tools[@]}"; do
|
||||
if [ -e "/usr/bin/$tool$version" ]; then
|
||||
sudo update-alternatives --set "$tool" /usr/bin/"$tool$version" &
|
||||
to_wait+=($!)
|
||||
fi
|
||||
set_alternative "$tool" &
|
||||
to_wait+=($!)
|
||||
done
|
||||
wait "${to_wait[@]}"
|
||||
}
|
||||
@@ -187,7 +227,7 @@ update_php() {
|
||||
# Function to install PHP.
|
||||
add_php() {
|
||||
if [ "${runner:?}" = "self-hosted" ] || [ "${use_package_cache:-true}" = "false" ]; then
|
||||
if [[ "$version" =~ ${nightly_versions:?} || "$ts" = "zts" ]]; then
|
||||
if [[ "$version" =~ ${php_builder_versions:?} || "$ts" = "zts" ]]; then
|
||||
setup_php_builder
|
||||
else
|
||||
add_packaged_php
|
||||
|
||||
@@ -3,6 +3,7 @@ $composer_home = "$env:APPDATA\Composer"
|
||||
$composer_bin = "$composer_home\vendor\bin"
|
||||
$composer_json = "$composer_home\composer.json"
|
||||
$composer_lock = "$composer_home\composer.lock"
|
||||
$skip_composer_github_auth = $false
|
||||
|
||||
# Function to configure composer.
|
||||
Function Edit-ComposerConfig() {
|
||||
@@ -23,6 +24,7 @@ Function Edit-ComposerConfig() {
|
||||
if (-not(Test-Path $composer_json)) {
|
||||
Set-Content -Path $composer_json -Value "{}"
|
||||
}
|
||||
Get-ToolVersion "composer" $null | Out-Null
|
||||
Set-ComposerEnv
|
||||
Add-Path $composer_bin
|
||||
Set-ComposerAuth
|
||||
@@ -74,8 +76,18 @@ function Test-GitHubPublicAccess {
|
||||
}
|
||||
}
|
||||
|
||||
Function Write-ComposerGhAuthNoOpWarning() {
|
||||
$message = (Get-Content (Join-Path $src 'configs\composer-gh-auth-warn') -Raw).Trim().Replace('%s', $composer_version)
|
||||
if($env:fail_fast -eq 'true') {
|
||||
Add-Log "$cross" "composer" $message
|
||||
} else {
|
||||
Write-Output "::warning::$message"
|
||||
}
|
||||
}
|
||||
|
||||
# Function to setup authentication in composer.
|
||||
Function Set-ComposerAuth() {
|
||||
$token = if ($env:COMPOSER_TOKEN) { $env:COMPOSER_TOKEN } else { $env:GITHUB_TOKEN }
|
||||
if(Test-Path env:COMPOSER_AUTH_JSON) {
|
||||
if(Test-Json -JSON $env:COMPOSER_AUTH_JSON) {
|
||||
Set-Content -Path $composer_home\auth.json -Value $env:COMPOSER_AUTH_JSON
|
||||
@@ -83,13 +95,18 @@ Function Set-ComposerAuth() {
|
||||
Add-Log "$cross" "composer" "Could not parse COMPOSER_AUTH_JSON as valid JSON"
|
||||
}
|
||||
}
|
||||
if($skip_composer_github_auth) {
|
||||
Write-ComposerGhAuthNoOpWarning
|
||||
}
|
||||
$composer_auth = @()
|
||||
if(Test-Path env:PACKAGIST_TOKEN) {
|
||||
$composer_auth += '"http-basic": {"repo.packagist.com": { "username": "token", "password": "' + $env:PACKAGIST_TOKEN + '"}}'
|
||||
}
|
||||
$write_token = $true
|
||||
$token = if ($env:COMPOSER_TOKEN) { $env:COMPOSER_TOKEN } else { $env:GITHUB_TOKEN }
|
||||
if ($token) {
|
||||
if ($skip_composer_github_auth) {
|
||||
$write_token = $false
|
||||
}
|
||||
if ($env:GITHUB_SERVER_URL -ne "https://github.com" -and -not(Test-GitHubPublicAccess $token)) {
|
||||
$write_token = $false
|
||||
}
|
||||
@@ -115,6 +132,18 @@ Function Set-ComposerEnv() {
|
||||
}
|
||||
}
|
||||
|
||||
# Function to identify latest-like URLs that should bypass the persistent cache.
|
||||
Function Test-MutableToolUrl() {
|
||||
Param(
|
||||
[Parameter(Position = 0, Mandatory = $true)]
|
||||
[string]
|
||||
$Url
|
||||
)
|
||||
$mutableUrlRegex = '(^|[/?#._=-])(latest|stable|preview|snapshot|nightly|master)([/?#._=-]|$)|/releases/latest/download/'
|
||||
$versionLikeRegex = '(^|[^0-9])[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)*'
|
||||
return ($Url -match $mutableUrlRegex) -or (($Url -match '\.phar([?#].*)?$') -and -not ($Url -match $versionLikeRegex))
|
||||
}
|
||||
|
||||
# Function to extract tool version.
|
||||
Function Get-ToolVersion() {
|
||||
Param (
|
||||
@@ -158,12 +187,7 @@ Function Add-ToolsHelper() {
|
||||
} elseif($tool -eq "cs2pr") {
|
||||
(Get-Content $bin_dir/cs2pr).replace('exit(9)', 'exit(0)') | Set-Content $bin_dir/cs2pr
|
||||
} elseif($tool -eq "deployer") {
|
||||
if(Test-Path $composer_bin\deployer.phar.bat) {
|
||||
Copy-Item $composer_bin\deployer.phar.bat -Destination $composer_bin\dep.bat
|
||||
}
|
||||
if(Test-Path $composer_bin\dep.bat) {
|
||||
Copy-Item $composer_bin\dep.bat -Destination $composer_bin\deployer.bat
|
||||
}
|
||||
Copy-Item $bin_dir\deployer.bat -Destination $bin_dir\dep.bat
|
||||
} elseif($tool -eq "phan") {
|
||||
$extensions += @('fileinfo', 'ast')
|
||||
} elseif($tool -eq "phinx") {
|
||||
@@ -203,32 +227,58 @@ Function Add-Tool() {
|
||||
[ValidateNotNull()]
|
||||
$tool,
|
||||
[Parameter(Position = 2, Mandatory = $false)]
|
||||
$ver_param
|
||||
$ver_param,
|
||||
[Parameter(Position = 3, Mandatory = $false)]
|
||||
$skip_composer_github_auth
|
||||
)
|
||||
if (Test-Path $bin_dir\$tool) {
|
||||
Copy-Item $bin_dir\$tool -Destination $bin_dir\$tool.old -Force
|
||||
if($tool -eq "composer") {
|
||||
$script:skip_composer_github_auth = $skip_composer_github_auth -eq 'true'
|
||||
}
|
||||
$urls = $urls -split ','
|
||||
$tool_path = "$bin_dir\$tool"
|
||||
foreach ($url in $urls){
|
||||
if (($url | Split-Path -Extension) -eq ".exe") {
|
||||
$tool_path = "$tool_path.exe"
|
||||
}
|
||||
try {
|
||||
$status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode
|
||||
} catch {
|
||||
if($url -match '.*github.com.*releases.*latest.*') {
|
||||
try {
|
||||
$url = $url.replace("releases/latest/download", "releases/download/" + ([regex]::match((Get-File -Url ($url.split('/release')[0] + "/releases")).Content, "([0-9]+\.[0-9]+\.[0-9]+)/" + ($url.Substring($url.LastIndexOf("/") + 1))).Groups[0].Value).split('/')[0])
|
||||
$status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode
|
||||
} catch { }
|
||||
$is_exe = ((($urls[0] | Split-Path -Extension).ToLowerInvariant()) -eq '.exe')
|
||||
if ($is_exe) { $tool_path = "$tool_path.exe" }
|
||||
$tool_ext = if ($is_exe) { '.exe' } else { '' }
|
||||
$url_stream = [System.IO.MemoryStream]::New([System.Text.Encoding]::UTF8.GetBytes($urls[0]))
|
||||
$cache_key = (Get-FileHash -InputStream $url_stream -Algorithm SHA256).Hash.Substring(0, 16)
|
||||
$cache_path = "$env:TEMP\$tool-$cache_key$tool_ext"
|
||||
$use_cache = -not (Test-MutableToolUrl $urls[0])
|
||||
$status_code = 200
|
||||
if ($use_cache -and (Test-Path $cache_path -PathType Leaf)) {
|
||||
Copy-Item $cache_path -Destination $tool_path -Force
|
||||
} else {
|
||||
$backup_path = "$tool_path.bak"
|
||||
if (Test-Path $tool_path) { Copy-Item $tool_path -Destination $backup_path -Force }
|
||||
foreach ($url in $urls){
|
||||
try {
|
||||
$status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode
|
||||
} catch {
|
||||
if($url -match '.*github.com.*releases.*latest.*') {
|
||||
try {
|
||||
$url = $url.replace("releases/latest/download", "releases/download/" + ([regex]::match((Get-File -Url ($url.split('/release')[0] + "/releases")).Content, "([0-9]+\.[0-9]+\.[0-9]+)/" + ($url.Substring($url.LastIndexOf("/") + 1))).Groups[0].Value).split('/')[0])
|
||||
$status_code = (Invoke-WebRequest -Passthru -Uri $url -OutFile $tool_path).StatusCode
|
||||
} catch {
|
||||
$status_code = 0
|
||||
}
|
||||
} else {
|
||||
$status_code = 0
|
||||
}
|
||||
}
|
||||
if($status_code -eq 200 -and (Test-Path $tool_path)) {
|
||||
if ($use_cache) {
|
||||
Copy-Item $tool_path -Destination $cache_path -Force
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
if($status_code -eq 200 -and (Test-Path $tool_path)) {
|
||||
break
|
||||
if ($status_code -ne 200 -and (Test-Path $backup_path)) {
|
||||
Copy-Item $backup_path -Destination $tool_path -Force
|
||||
}
|
||||
Remove-Item $backup_path -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
if (((Get-ChildItem -Path $bin_dir/* | Where-Object Name -Match "^$tool(.exe|.phar)*$").Count -gt 0)) {
|
||||
$escaped_tool = [regex]::Escape($tool)
|
||||
if (((Get-ChildItem -Path $bin_dir/* | Where-Object Name -Match "^$escaped_tool(\.exe|\.phar)?$").Count -gt 0)) {
|
||||
$bat_content = @()
|
||||
$bat_content += "@ECHO off"
|
||||
$bat_content += "setlocal DISABLEDELAYEDEXPANSION"
|
||||
@@ -242,8 +292,6 @@ Function Add-Tool() {
|
||||
} else {
|
||||
if($tool -eq "composer") {
|
||||
$env:fail_fast = 'true'
|
||||
} elseif (Test-Path $bin_dir\$tool.old) {
|
||||
Copy-Item $bin_dir\$tool.old -Destination $bin_dir\$tool -Force
|
||||
}
|
||||
Add-Log $cross $tool "Could not add $tool"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ export composer_home="$HOME/.composer"
|
||||
export composer_bin="$composer_home/vendor/bin"
|
||||
export composer_json="$composer_home/composer.json"
|
||||
export composer_lock="$composer_home/composer.lock"
|
||||
skip_composer_github_auth=false
|
||||
|
||||
# Function to extract tool version.
|
||||
get_tool_version() {
|
||||
@@ -41,6 +42,7 @@ configure_composer() {
|
||||
echo '{}' | tee "$composer_json" >/dev/null
|
||||
chmod 644 "$composer_json"
|
||||
fi
|
||||
get_tool_version composer >/dev/null
|
||||
set_composer_env
|
||||
add_path "$composer_bin"
|
||||
set_composer_auth
|
||||
@@ -70,22 +72,39 @@ can_access_public_github() {
|
||||
curl --fail -s -H "Authorization: token $1" 'https://api.github.com/' >/dev/null 2>&1
|
||||
}
|
||||
|
||||
composer_gh_auth_no_op() {
|
||||
local message
|
||||
message="$(<"${src:?}"/configs/composer-gh-auth-warn)"
|
||||
message="${message//%s/$composer_version}"
|
||||
if [ "${fail_fast:-false}" = "true" ]; then
|
||||
add_log "${cross:?}" "composer" "$message"
|
||||
else
|
||||
echo "::warning::$message"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to setup authentication in composer.
|
||||
set_composer_auth() {
|
||||
if [ -n "$COMPOSER_AUTH_JSON" ]; then
|
||||
if php -r "json_decode('$COMPOSER_AUTH_JSON'); if(json_last_error() !== JSON_ERROR_NONE) { throw new Exception('invalid json'); }"; then
|
||||
echo "$COMPOSER_AUTH_JSON" | tee "$composer_home/auth.json" >/dev/null
|
||||
token="${COMPOSER_TOKEN:-$GITHUB_TOKEN}"
|
||||
if [ -n "${COMPOSER_AUTH_JSON:-}" ]; then
|
||||
if printf '%s' "$COMPOSER_AUTH_JSON" | jq -e . >/dev/null; then
|
||||
printf '%s' "$COMPOSER_AUTH_JSON" | tee "$composer_home/auth.json" >/dev/null
|
||||
else
|
||||
add_log "${cross:?}" "composer" "Could not parse COMPOSER_AUTH_JSON as valid JSON"
|
||||
fi
|
||||
fi
|
||||
if [ "$skip_composer_github_auth" = "true" ]; then
|
||||
composer_gh_auth_no_op
|
||||
fi
|
||||
composer_auth=()
|
||||
if [ -n "$PACKAGIST_TOKEN" ]; then
|
||||
composer_auth+=( '"http-basic": {"repo.packagist.com": { "username": "token", "password": "'"$PACKAGIST_TOKEN"'"}}' )
|
||||
fi
|
||||
token="${COMPOSER_TOKEN:-$GITHUB_TOKEN}"
|
||||
if [ -n "$token" ]; then
|
||||
write_token=true
|
||||
if [ "$skip_composer_github_auth" = "true" ]; then
|
||||
write_token=false
|
||||
fi
|
||||
if [ "$GITHUB_SERVER_URL" != "https://github.com" ]; then
|
||||
can_access_public_github "$token" || write_token=false
|
||||
fi
|
||||
@@ -113,6 +132,16 @@ set_composer_env() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to identify latest-like URLs that should bypass the persistent cache.
|
||||
is_mutable_tool_url() {
|
||||
local tool_url=$1
|
||||
local mutable_url_regex='(^|[/?#._=-])(latest|stable|preview|snapshot|nightly|master)([/?#._=-]|$)|/releases/latest/download/'
|
||||
local version_like_regex='(^|[^0-9])[0-9]+\.[0-9]+([.-][0-9A-Za-z]+)*'
|
||||
[[ "$tool_url" =~ $mutable_url_regex ]] && return 0
|
||||
[[ "$tool_url" =~ \.phar([?#].*)?$ && ! "$tool_url" =~ $version_like_regex ]] && return 0
|
||||
return 1
|
||||
}
|
||||
|
||||
# Helper function to configure tools.
|
||||
add_tools_helper() {
|
||||
tool=$1
|
||||
@@ -123,19 +152,15 @@ add_tools_helper() {
|
||||
extensions+=(iconv mbstring phar sodium)
|
||||
elif [ "$tool" = "codeception" ]; then
|
||||
extensions+=(json mbstring)
|
||||
sudo ln -s "$scoped_dir"/vendor/bin/codecept "$scoped_dir"/vendor/bin/codeception
|
||||
sudo ln -s "$scoped_dir"/vendor/bin/codecept "$scoped_dir"/vendor/bin/codeception 2>/dev/null || true
|
||||
elif [ "$tool" = "composer" ]; then
|
||||
configure_composer "$tool_path"
|
||||
elif [ "$tool" = "cs2pr" ]; then
|
||||
sudo sed -i 's/\r$//; s/exit(9)/exit(0)/' "$tool_path" 2>/dev/null ||
|
||||
sudo sed -i '' 's/\r$//; s/exit(9)/exit(0)/' "$tool_path"
|
||||
elif [ "$tool" = "deployer" ]; then
|
||||
if [ -e "$composer_bin"/deployer.phar ]; then
|
||||
sudo ln -s "$composer_bin"/deployer.phar "$composer_bin"/dep
|
||||
fi
|
||||
if [ -e "$composer_bin"/dep ]; then
|
||||
sudo ln -s "$composer_bin"/dep "$composer_bin"/deployer
|
||||
fi
|
||||
sudo ln -s "$tool_path" "$tool_path_dir"/deployer 2>/dev/null || true
|
||||
sudo ln -s "$tool_path" "$tool_path_dir"/dep 2>/dev/null || true
|
||||
elif [ "$tool" = "phan" ]; then
|
||||
extensions+=(fileinfo ast)
|
||||
elif [ "$tool" = "phinx" ]; then
|
||||
@@ -151,7 +176,7 @@ add_tools_helper() {
|
||||
elif [ "$tool" = "phpDocumentor" ]; then
|
||||
extensions+=(ctype hash json fileinfo iconv mbstring simplexml xml)
|
||||
sudo ln -s "$tool_path" "$tool_path_dir"/phpdocumentor 2>/dev/null || true
|
||||
sudo ln -s "$tool_path" "$tool_path_dir"/phpdoc
|
||||
sudo ln -s "$tool_path" "$tool_path_dir"/phpdoc 2>/dev/null || true
|
||||
elif [ "$tool" = "phpunit" ]; then
|
||||
extensions+=(dom json libxml mbstring xml xmlwriter)
|
||||
elif [ "$tool" = "phpunit-bridge" ]; then
|
||||
@@ -162,9 +187,9 @@ add_tools_helper() {
|
||||
fi
|
||||
elif [ "$tool" = "vapor-cli" ]; then
|
||||
extensions+=(fileinfo json mbstring zip simplexml)
|
||||
sudo ln -s "$scoped_dir"/vendor/bin/vapor "$scoped_dir"/vendor/bin/vapor-cli
|
||||
sudo ln -s "$scoped_dir"/vendor/bin/vapor "$scoped_dir"/vendor/bin/vapor-cli 2>/dev/null || true
|
||||
elif [ "$tool" = wp-cli ]; then
|
||||
sudo ln -s "$tool_path" "$tool_path_dir"/"${tool%-*}"
|
||||
sudo ln -s "$tool_path" "$tool_path_dir"/"${tool%-*}" 2>/dev/null || true
|
||||
fi
|
||||
for extension in "${extensions[@]}"; do
|
||||
add_extension "$extension" extension >/dev/null 2>&1
|
||||
@@ -176,29 +201,48 @@ add_tool() {
|
||||
url=$1
|
||||
tool=$2
|
||||
ver_param=$3
|
||||
if [ "$tool" = "composer" ]; then
|
||||
skip_composer_github_auth="${4:-false}"
|
||||
fi
|
||||
tool_path="$tool_path_dir/$tool"
|
||||
if ! [ -d "$tool_path_dir" ]; then
|
||||
sudo mkdir -p "$tool_path_dir"
|
||||
fi
|
||||
add_path "$tool_path_dir"
|
||||
if [ -e "$tool_path" ]; then
|
||||
sudo cp -aL "$tool_path" /tmp/"$tool"
|
||||
if ! [ -d "$tool_cache_path_dir" ]; then
|
||||
sudo mkdir -p "$tool_cache_path_dir"
|
||||
fi
|
||||
add_path "$tool_path_dir" verify
|
||||
add_path "$tool_cache_path_dir"
|
||||
IFS="," read -r -a url <<<"$url"
|
||||
status_code=$(get -v -e "$tool_path" "${url[@]}")
|
||||
if [ "$status_code" != "200" ] && [[ "${url[0]}" =~ .*github.com.*releases.*latest.* ]]; then
|
||||
url[0]="${url[0]//releases\/latest\/download/releases/download/$(get -s -n "" "$(echo "${url[0]}" | cut -d '/' -f '1-5')/releases" | grep -Eo -m 1 "([0-9]+\.[0-9]+\.[0-9]+)/$(echo "${url[0]}" | sed -e "s/.*\///")" | cut -d '/' -f 1)}"
|
||||
status_code=$(get -v -e "$tool_path" "${url[0]}")
|
||||
cache_key=$(get_sha256 "${url[0]}" | head -c 16)
|
||||
cache_path="$tool_cache_path_dir/${tool}-${cache_key}"
|
||||
use_cache=true
|
||||
is_mutable_tool_url "${url[0]}" && use_cache=false
|
||||
status_code="200"
|
||||
if [ "$use_cache" = "true" ] && [ -f "$cache_path" ]; then
|
||||
sudo cp -a "$cache_path" "$tool_path"
|
||||
else
|
||||
[ -f "$tool_path" ] && sudo cp -a "$tool_path" "$tool_path.bak"
|
||||
status_code=$(get -v -e "$tool_path" "${url[@]}")
|
||||
if [ "$status_code" != "200" ] && [[ "${url[0]}" =~ .*github.com.*releases.*latest.* ]]; then
|
||||
url[0]="${url[0]//releases\/latest\/download/releases/download/$(get -s -n "" "$(echo "${url[0]}" | cut -d '/' -f '1-5')/releases" | grep -Eo -m 1 "([0-9]+\.[0-9]+\.[0-9]+)/$(echo "${url[0]}" | sed -e "s/.*\///")" | cut -d '/' -f 1)}"
|
||||
status_code=$(get -v -e "$tool_path" "${url[0]}")
|
||||
fi
|
||||
if [ "$status_code" = "200" ]; then
|
||||
[ "$use_cache" = "true" ] && sudo cp -a "$tool_path" "$cache_path"
|
||||
elif [ -f "$tool_path.bak" ]; then
|
||||
sudo mv "$tool_path.bak" "$tool_path"
|
||||
fi
|
||||
sudo rm -f "$tool_path.bak"
|
||||
fi
|
||||
if [ "$status_code" = "200" ]; then
|
||||
add_tools_helper "$tool"
|
||||
tool_version=$(get_tool_version "$tool" "$ver_param")
|
||||
sudo ln -sfn "$tool_path" "$tool_cache_path_dir/$tool" 2>/dev/null || true
|
||||
add_log "${tick:?}" "$tool" "Added $tool $tool_version"
|
||||
else
|
||||
if [ "$tool" = "composer" ]; then
|
||||
export fail_fast=true
|
||||
elif [ -e /tmp/"$tool" ]; then
|
||||
sudo cp -a /tmp/"$tool" "$tool_path"
|
||||
fi
|
||||
if [ "$status_code" = "404" ]; then
|
||||
add_log "$cross" "$tool" "Failed to download $tool from ${url[*]}"
|
||||
|
||||
@@ -8,7 +8,7 @@ add_blackfire_linux() {
|
||||
add_blackfire_darwin() {
|
||||
sudo mkdir -p /usr/local/var/run
|
||||
add_brew_tap blackfireio/homebrew-blackfire
|
||||
brew install blackfire
|
||||
safe_brew install blackfire
|
||||
}
|
||||
|
||||
blackfire_config() {
|
||||
|
||||
@@ -44,6 +44,135 @@ add_brew_bins_to_path() {
|
||||
add_path "$brew_prefix"/sbin
|
||||
}
|
||||
|
||||
# Function to get file modification time.
|
||||
get_file_mtime() {
|
||||
local file=$1
|
||||
if [ "$(uname -s)" = "Darwin" ]; then
|
||||
stat -f "%m" "$file" 2>/dev/null || echo 0
|
||||
else
|
||||
stat -c "%Y" "$file" 2>/dev/null || echo 0
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to terminate a process and its direct children.
|
||||
terminate_process_tree() {
|
||||
local pid=$1
|
||||
local children child
|
||||
children=$(pgrep -P "$pid" 2>/dev/null || true)
|
||||
kill -TERM "$pid" >/dev/null 2>&1 || true
|
||||
for child in $children; do
|
||||
terminate_process_tree "$child"
|
||||
done
|
||||
sleep 2
|
||||
kill -KILL "$pid" >/dev/null 2>&1 || true
|
||||
for child in $children; do
|
||||
terminate_process_tree "$child"
|
||||
done
|
||||
}
|
||||
|
||||
# Function to run a command with an inactivity watchdog.
|
||||
run_with_inactivity_watchdog() {
|
||||
local timeout_secs="${SETUP_PHP_BREW_INACTIVITY_TIMEOUT:-180}"
|
||||
local poll_secs="${SETUP_PHP_BREW_WATCHDOG_POLL:-5}"
|
||||
local tmp_dir stdout_fifo stderr_fifo stdout_log stderr_log timeout_file
|
||||
local command_pid stdout_reader_pid stderr_reader_pid monitor_pid exit_code
|
||||
tmp_dir="$(mktemp -d "${TMPDIR:-/tmp}/setup-php-brew.XXXXXX")" || return 1
|
||||
stdout_fifo="$tmp_dir/stdout.fifo"
|
||||
stderr_fifo="$tmp_dir/stderr.fifo"
|
||||
stdout_log="$tmp_dir/stdout.log"
|
||||
stderr_log="$tmp_dir/stderr.log"
|
||||
timeout_file="$tmp_dir/timed_out"
|
||||
mkfifo "$stdout_fifo" "$stderr_fifo" || {
|
||||
rm -rf "$tmp_dir"
|
||||
return 1
|
||||
}
|
||||
: >"$stdout_log"
|
||||
: >"$stderr_log"
|
||||
|
||||
("$@" >"$stdout_fifo" 2>"$stderr_fifo") &
|
||||
command_pid=$!
|
||||
|
||||
(
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
printf '%s\n' "$line"
|
||||
printf '%s\n' "$line" >>"$stdout_log"
|
||||
done <"$stdout_fifo"
|
||||
) &
|
||||
stdout_reader_pid=$!
|
||||
|
||||
(
|
||||
while IFS= read -r line || [ -n "$line" ]; do
|
||||
printf '%s\n' "$line" >&2
|
||||
printf '%s\n' "$line" >>"$stderr_log"
|
||||
done <"$stderr_fifo"
|
||||
) &
|
||||
stderr_reader_pid=$!
|
||||
|
||||
(
|
||||
local last_activity current_activity current_err_activity now
|
||||
last_activity=$(get_file_mtime "$stdout_log")
|
||||
current_err_activity=$(get_file_mtime "$stderr_log")
|
||||
[ "$current_err_activity" -gt "$last_activity" ] && last_activity="$current_err_activity"
|
||||
while kill -0 "$command_pid" >/dev/null 2>&1; do
|
||||
sleep "$poll_secs"
|
||||
current_activity=$(get_file_mtime "$stdout_log")
|
||||
[ "$current_activity" -gt "$last_activity" ] && last_activity="$current_activity"
|
||||
current_err_activity=$(get_file_mtime "$stderr_log")
|
||||
[ "$current_err_activity" -gt "$last_activity" ] && last_activity="$current_err_activity"
|
||||
now=$(date +%s)
|
||||
if [ $((now - last_activity)) -ge "$timeout_secs" ]; then
|
||||
printf "\nsetup-php: brew produced no output for %ss; terminating and retrying...\n" "$timeout_secs" >&2
|
||||
: >"$timeout_file"
|
||||
terminate_process_tree "$command_pid"
|
||||
break
|
||||
fi
|
||||
done
|
||||
) &
|
||||
monitor_pid=$!
|
||||
|
||||
wait "$command_pid"
|
||||
exit_code=$?
|
||||
wait "$stdout_reader_pid" 2>/dev/null || true
|
||||
wait "$stderr_reader_pid" 2>/dev/null || true
|
||||
kill "$monitor_pid" >/dev/null 2>&1 || true
|
||||
wait "$monitor_pid" 2>/dev/null || true
|
||||
|
||||
if [ -e "$timeout_file" ]; then
|
||||
rm -rf "$tmp_dir"
|
||||
return 124
|
||||
fi
|
||||
|
||||
rm -rf "$tmp_dir"
|
||||
return "$exit_code"
|
||||
}
|
||||
|
||||
# Function to run brew with retries and an inactivity watchdog.
|
||||
safe_brew() {
|
||||
local max_attempts="${SETUP_PHP_BREW_RETRY_ATTEMPTS:-3}"
|
||||
local attempt=1
|
||||
local exit_code=0
|
||||
|
||||
if [ "${SETUP_PHP_BREW_WATCHDOG:-true}" = "false" ]; then
|
||||
brew "$@"
|
||||
return $?
|
||||
fi
|
||||
|
||||
while [ "$attempt" -le "$max_attempts" ]; do
|
||||
run_with_inactivity_watchdog brew "$@" && return 0
|
||||
exit_code=$?
|
||||
|
||||
if [ "$attempt" -ge "$max_attempts" ]; then
|
||||
return "$exit_code"
|
||||
fi
|
||||
|
||||
printf "setup-php: retrying brew command (attempt %s/%s, exit %s)\n" "$((attempt + 1))" "$max_attempts" "$exit_code" >&2
|
||||
sleep "$((attempt * 5))"
|
||||
attempt=$((attempt + 1))
|
||||
done
|
||||
|
||||
return "$exit_code"
|
||||
}
|
||||
|
||||
# Function to add brew.
|
||||
add_brew() {
|
||||
brew_prefix="$(get_brew_prefix)"
|
||||
@@ -74,6 +203,7 @@ configure_brew() {
|
||||
export HOMEBREW_NO_ENV_HINTS=1
|
||||
export HOMEBREW_NO_INSTALL_CLEANUP=1
|
||||
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
|
||||
export HOMEBREW_DOWNLOAD_CONCURRENCY="${HOMEBREW_DOWNLOAD_CONCURRENCY:-6}"
|
||||
export brew_opts
|
||||
export brew_path
|
||||
export brew_path_dir
|
||||
|
||||
@@ -4,7 +4,7 @@ add_bazel() {
|
||||
add_list bazel/apt https://storage.googleapis.com/bazel-apt https://bazel.build/bazel-release.pub.gpg stable jdk1.8
|
||||
install_packages bazel
|
||||
else
|
||||
brew install bazel
|
||||
safe_brew install bazel
|
||||
fi
|
||||
fi
|
||||
}
|
||||
@@ -25,7 +25,7 @@ add_grpc_php_plugin_brew() {
|
||||
. "${0%/*}"/tools/brew.sh
|
||||
configure_brew
|
||||
[ -e /usr/local/bin/protoc ] && sudo mv /usr/local/bin/protoc /tmp/protoc && sudo mv /usr/local/include/google /tmp
|
||||
brew install grpc
|
||||
safe_brew install grpc
|
||||
brew link --force --overwrite grpc >/dev/null 2>&1
|
||||
[ -e /tmp/protoc ] && sudo mv /tmp/protoc /usr/local/bin/protoc && sudo mv /tmp/google /usr/local/include/
|
||||
grpc_tag="v$(brew info grpc | grep "grpc:" | grep -Eo "[0-9]+\.[0-9]+\.[0-9]+")"
|
||||
|
||||
@@ -4,7 +4,8 @@ export cross="✗"
|
||||
export curl_opts=(-sL)
|
||||
export old_versions="5.[3-5]"
|
||||
export jit_versions="8.[0-9]"
|
||||
export nightly_versions="8.[3-9]"
|
||||
export php_builder_versions="8.[3-9]"
|
||||
export nightly_versions="8.[6-9]"
|
||||
export xdebug3_versions="7.[2-4]|8.[0-9]"
|
||||
export latest="releases/latest/download"
|
||||
export github="https://github.com/shivammathur"
|
||||
@@ -58,6 +59,7 @@ read_env() {
|
||||
-n "$ACT" || -n "$CONTAINER" ]] && _runner=self-hosted || _runner=github
|
||||
runner="${runner:-${RUNNER:-$_runner}}"
|
||||
tool_path_dir="${setup_php_tools_dir:-${SETUP_PHP_TOOLS_DIR:-/usr/local/bin}}"
|
||||
tool_cache_path_dir="${setup_php_tool_cache_dir:-${SETUP_PHP_TOOL_CACHE_DIR:-${RUNNER_TOOL_CACHE:-/opt/hostedtoolcache}/setup-php/tools}}"
|
||||
|
||||
if [[ "$runner" = "github" && $_runner = "self-hosted" ]]; then
|
||||
fail_fast=true
|
||||
@@ -79,6 +81,7 @@ read_env() {
|
||||
export update
|
||||
export ts
|
||||
export tool_path_dir
|
||||
export tool_cache_path_dir
|
||||
}
|
||||
|
||||
# Function to create a lock.
|
||||
@@ -169,14 +172,15 @@ get_shell_profile() {
|
||||
# Function to add a path to the PATH variable.
|
||||
add_path() {
|
||||
path_to_add=$1
|
||||
[[ ":$PATH:" == *":$path_to_add:"* ]] && return
|
||||
action=$2
|
||||
[[ "$action" == "verify" && ":$PATH:" == *":$path_to_add:"* ]] && return
|
||||
if [[ -n "$GITHUB_PATH" ]]; then
|
||||
echo "$path_to_add" | tee -a "$GITHUB_PATH" >/dev/null 2>&1
|
||||
printf '%s\n%s' "$path_to_add" "$(grep -v "^${path_to_add}$" "$GITHUB_PATH" 2>/dev/null)" > "$GITHUB_PATH"
|
||||
else
|
||||
profile=$(get_shell_profile)
|
||||
([ -e "$profile" ] && grep -q ":$path_to_add\"" "$profile" 2>/dev/null) || echo "export PATH=\"\${PATH:+\${PATH}:}\"$path_to_add" | sudo tee -a "$profile" >/dev/null 2>&1
|
||||
fi
|
||||
export PATH="${PATH:+${PATH}:}$path_to_add"
|
||||
[[ ":$PATH:" == *":$path_to_add:"* ]] || export PATH="${PATH:+${PATH}:}$path_to_add"
|
||||
}
|
||||
|
||||
# Function to add environment variables using a PATH.
|
||||
|
||||
@@ -81,9 +81,10 @@ Function Get-PathFromRegistry {
|
||||
# Function to add a location to PATH.
|
||||
Function Add-Path {
|
||||
param(
|
||||
[string]$PathItem
|
||||
[string]$PathItem,
|
||||
[switch]$Force
|
||||
)
|
||||
if("$env:PATH;".contains("$PathItem;")) {
|
||||
if(-not($Force) -and "$env:PATH;".contains("$PathItem;")) {
|
||||
return
|
||||
}
|
||||
if ($env:GITHUB_PATH) {
|
||||
@@ -202,16 +203,20 @@ Function Install-PSPackage() {
|
||||
$cmdlet
|
||||
)
|
||||
$module_path = "$bin_dir\$psm1_path.psm1"
|
||||
if(-not (Test-Path $module_path -PathType Leaf)) {
|
||||
$zip_file = "$bin_dir\$package.zip"
|
||||
Get-File -Url $url -OutFile $zip_file
|
||||
Expand-Archive -Path $zip_file -DestinationPath $bin_dir -Force
|
||||
}
|
||||
Import-Module $module_path
|
||||
if($null -eq (Get-Command $cmdlet -ErrorAction SilentlyContinue)) {
|
||||
Install-Module -Name $package -Force
|
||||
} else {
|
||||
$imported = $false
|
||||
try {
|
||||
if(-not (Test-Path $module_path -PathType Leaf)) {
|
||||
$zip_file = "$bin_dir\$package.zip"
|
||||
Get-File -Url $url -OutFile $zip_file
|
||||
Expand-Archive -Path $zip_file -DestinationPath $bin_dir -Force -ErrorAction Stop
|
||||
}
|
||||
Import-Module $module_path -ErrorAction Stop
|
||||
$imported = $null -ne (Get-Command $cmdlet -ErrorAction SilentlyContinue)
|
||||
} catch { }
|
||||
if($imported) {
|
||||
Add-ToProfile $current_profile "$package-search" "Import-Module $module_path"
|
||||
} else {
|
||||
Install-Module -Name $package -Force
|
||||
}
|
||||
}
|
||||
|
||||
@@ -375,6 +380,7 @@ if(-not($env:ImageOS) -and -not($env:ImageVersion)) {
|
||||
if(-not(Test-Path -LiteralPath $current_profile)) {
|
||||
New-Item -Path $current_profile -ItemType "file" -Force >$null 2>&1
|
||||
}
|
||||
Add-Path -PathItem $bin_dir -Force
|
||||
}
|
||||
|
||||
$src = Join-Path -Path $PSScriptRoot -ChildPath \..
|
||||
|
||||
552
src/tools.ts
552
src/tools.ts
@@ -5,14 +5,130 @@ import * as fetch from './fetch';
|
||||
import * as packagist from './packagist';
|
||||
import * as utils from './utils';
|
||||
|
||||
type RS = Record<string, string>;
|
||||
type RSRS = Record<string, RS>;
|
||||
/**
|
||||
* Valid function names for custom tool handlers
|
||||
*/
|
||||
type ToolFunction =
|
||||
| 'castor'
|
||||
| 'composer'
|
||||
| 'deployer'
|
||||
| 'dev_tools'
|
||||
| 'phive'
|
||||
| 'blackfire_player'
|
||||
| 'pecl'
|
||||
| 'phing'
|
||||
| 'phpunit'
|
||||
| 'phpcpd'
|
||||
| 'wp_cli';
|
||||
|
||||
interface IRef {
|
||||
/**
|
||||
* Tool data interface containing all properties for tool installation
|
||||
*/
|
||||
export interface ToolData {
|
||||
tool: string;
|
||||
version: string;
|
||||
os: string;
|
||||
php_version: string;
|
||||
github: string;
|
||||
domain: string;
|
||||
extension: string;
|
||||
repository: string;
|
||||
prefix: string;
|
||||
verb: string;
|
||||
fetch_latest: 'true' | 'false';
|
||||
scope: string;
|
||||
version_parameter: string;
|
||||
version_prefix: string;
|
||||
release: string;
|
||||
packagist: string;
|
||||
type?: string;
|
||||
function?: ToolFunction;
|
||||
alias?: string;
|
||||
url: string;
|
||||
uri?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Input type for functions that may receive partial/unresolved tool data
|
||||
* Used by getUrl, getLatestVersion etc. before version is fully resolved
|
||||
*/
|
||||
export type ToolInput = Omit<ToolData, 'version' | 'url'> & {version?: string};
|
||||
|
||||
/**
|
||||
* Partial tool data from tools.json configuration
|
||||
*/
|
||||
interface ToolConfig {
|
||||
tool?: string;
|
||||
repository?: string;
|
||||
type?: string;
|
||||
function?: ToolFunction;
|
||||
alias?: string;
|
||||
domain?: string;
|
||||
extension?: string;
|
||||
fetch_latest?: 'true' | 'false';
|
||||
scope?: string;
|
||||
version_parameter?: string;
|
||||
version_prefix?: string;
|
||||
packagist?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* GitHub reference object from API response
|
||||
*/
|
||||
interface GitHubRef {
|
||||
ref: string;
|
||||
node_id: string;
|
||||
url: string;
|
||||
object: RS;
|
||||
object: {
|
||||
sha: string;
|
||||
type: string;
|
||||
url: string;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Deployer manifest entry
|
||||
*/
|
||||
interface DeployerManifestEntry {
|
||||
version: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export function skipGitHubAuthForComposerVersion(version: string): boolean {
|
||||
if (!/^\d+\.\d+\.\d+(?:-[\w-]+)?$/.test(version)) {
|
||||
return false;
|
||||
}
|
||||
return fs
|
||||
.readFileSync(
|
||||
path.join(__dirname, '../src/configs/composer-gh-auth-no-op'),
|
||||
'utf8'
|
||||
)
|
||||
.trim()
|
||||
.split(/\r?\n/)
|
||||
.some(range => {
|
||||
const [min, max] = range.trim().split(/\s+/);
|
||||
return (
|
||||
cv.compareVersions(version, min) >= 0 &&
|
||||
cv.compareVersions(version, max) < 0
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function cleanComposerAuthJson(): void {
|
||||
try {
|
||||
const auth_json = process.env['COMPOSER_AUTH_JSON'] || '';
|
||||
if (!auth_json.includes('github-oauth')) return;
|
||||
const auth = JSON.parse(auth_json);
|
||||
delete auth['github-oauth'];
|
||||
if (!Object.keys(auth).length) {
|
||||
delete process.env['COMPOSER_AUTH_JSON'];
|
||||
} else {
|
||||
process.env['COMPOSER_AUTH_JSON'] = JSON.stringify(auth);
|
||||
}
|
||||
} catch {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,7 +136,7 @@ interface IRef {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function getSemverVersion(data: RS): Promise<string> {
|
||||
export async function getSemverVersion(data: ToolData): Promise<string> {
|
||||
const fixSemver = (t: string): string => {
|
||||
if (/^\d+\.\d+\.\d+(-|$)/.test(t)) return t;
|
||||
const m = t.match(/^(\d+\.\d+\.\d+)([A-Za-z]+[0-9A-Za-z.]+)$/);
|
||||
@@ -31,14 +147,16 @@ export async function getSemverVersion(data: RS): Promise<string> {
|
||||
const github_token: string =
|
||||
(await utils.readEnv('GITHUB_TOKEN')) ||
|
||||
(await utils.readEnv('COMPOSER_TOKEN'));
|
||||
const response: RS = await fetch.fetch(url, github_token);
|
||||
const response = await fetch.fetch(url, github_token);
|
||||
if (response.error || response.data === '[]') {
|
||||
data['error'] = response.error ?? `No version found with prefix ${search}.`;
|
||||
return data['version'];
|
||||
data.error = response.error ?? `No version found with prefix ${search}.`;
|
||||
return data.version;
|
||||
} else {
|
||||
const refs: IRef[] = JSON.parse(response['data']);
|
||||
const refs: GitHubRef[] = JSON.parse(response.data);
|
||||
const tags = refs
|
||||
.map((i: IRef) => (i.ref?.split('/').pop() ?? '').replace(/^v(?=\d)/, ''))
|
||||
.map((i: GitHubRef) =>
|
||||
(i.ref?.split('/').pop() ?? '').replace(/^v(?=\d)/, '')
|
||||
)
|
||||
.filter((t: string) => t.length > 0);
|
||||
const fixedToOriginal = new Map<string, string>();
|
||||
const fixed = tags.map(t => {
|
||||
@@ -46,14 +164,14 @@ export async function getSemverVersion(data: RS): Promise<string> {
|
||||
fixedToOriginal.set(f, t);
|
||||
return f;
|
||||
});
|
||||
fixed.sort((a, b) => {
|
||||
const sorted = fixed.toSorted((a, b) => {
|
||||
try {
|
||||
return cv.compareVersions(b, a);
|
||||
} catch {
|
||||
return b.localeCompare(a, 'en', {numeric: true, sensitivity: 'base'});
|
||||
}
|
||||
});
|
||||
return fixedToOriginal.get(fixed[0]) ?? fixed[0];
|
||||
return fixedToOriginal.get(sorted[0]) ?? sorted[0];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,25 +180,25 @@ export async function getSemverVersion(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function getLatestVersion(data: RS): Promise<string> {
|
||||
if (!data['version'] && data['fetch_latest'] === 'false') {
|
||||
export async function getLatestVersion(data: ToolInput): Promise<string> {
|
||||
if (!data.version && data.fetch_latest === 'false') {
|
||||
return 'latest';
|
||||
}
|
||||
const resp: Record<string, string> = await fetch.fetch(
|
||||
`${data['github']}/${data['repository']}/releases.atom`
|
||||
if (data.fetch_latest === 'true' && !data.repository) {
|
||||
return 'latest';
|
||||
}
|
||||
const resp = await fetch.fetch(
|
||||
`${data.github}/${data.repository}/releases.atom`
|
||||
);
|
||||
if (resp['data']) {
|
||||
if (resp.data) {
|
||||
const releases: string[] = [
|
||||
...resp['data'].matchAll(/releases\/tag\/([a-zA-Z]*)?(\d+.\d+.\d+)"/g)
|
||||
...resp.data.matchAll(/releases\/tag\/([a-zA-Z]*)?(\d+\.\d+\.\d+)"/g)
|
||||
].map(match => match[2]);
|
||||
|
||||
return (
|
||||
releases
|
||||
.sort((a: string, b: string) =>
|
||||
a.localeCompare(b, undefined, {numeric: true})
|
||||
)
|
||||
.pop() || 'latest'
|
||||
const sorted = releases.toSorted((a: string, b: string) =>
|
||||
a.localeCompare(b, undefined, {numeric: true})
|
||||
);
|
||||
return sorted.at(-1) || 'latest';
|
||||
}
|
||||
return 'latest';
|
||||
}
|
||||
@@ -91,26 +209,29 @@ export async function getLatestVersion(data: RS): Promise<string> {
|
||||
* @param version
|
||||
* @param data
|
||||
*/
|
||||
export async function getVersion(version: string, data: RS): Promise<string> {
|
||||
export async function getVersion(
|
||||
version: string,
|
||||
data: ToolData
|
||||
): Promise<string> {
|
||||
// semver_regex - https://semver.org/
|
||||
const semver_regex =
|
||||
/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
|
||||
const composer_regex = /^composer:(stable|preview|snapshot|[1|2])$/;
|
||||
const composer_regex = /^composer:(stable|preview|snapshot|[12])$/;
|
||||
const constraint_regex = /[><=^~]+.*/;
|
||||
const major_minor_regex = /^\d+(\.\d+)?$/;
|
||||
data['version'] = version.replace(/v?(\d)/, '$1').replace(/\.x/, '');
|
||||
data.version = version.replace(/v?(\d)/, '$1').replace(/\.x/, '');
|
||||
switch (true) {
|
||||
case composer_regex.test(data['release']):
|
||||
case semver_regex.test(data['version']):
|
||||
case constraint_regex.test(data['version']) && data['type'] === 'composer':
|
||||
return data['version'];
|
||||
case major_minor_regex.test(data['version']) && data['type'] === 'composer':
|
||||
data['release'] = `${data['tool']}:${data['version']}.*`;
|
||||
return `${data['version']}.*`;
|
||||
case data['repository'] && major_minor_regex.test(data['version']):
|
||||
case composer_regex.test(data.release):
|
||||
case semver_regex.test(data.version):
|
||||
case constraint_regex.test(data.version) && data.type === 'composer':
|
||||
return data.version;
|
||||
case major_minor_regex.test(data.version) && data.type === 'composer':
|
||||
data.release = `${data.tool}:${data.version}.*`;
|
||||
return `${data.version}.*`;
|
||||
case !!data.repository && major_minor_regex.test(data.version):
|
||||
return await getSemverVersion(data);
|
||||
default:
|
||||
return data['version'].replace(/[><=^~]*/, '');
|
||||
return data.version.replace(/[^a-zA-Z0-9_.:@+,/-]/g, '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,11 +241,14 @@ export async function getVersion(version: string, data: RS): Promise<string> {
|
||||
* @param release
|
||||
* @param data
|
||||
*/
|
||||
export async function getRelease(release: string, data: RS): Promise<string> {
|
||||
export async function getRelease(
|
||||
release: string,
|
||||
data: ToolData
|
||||
): Promise<string> {
|
||||
release = release.includes('/') ? release.split('/')[1] : release;
|
||||
return release.includes(':')
|
||||
? [data['tool'], release.split(':')[1]].join(':')
|
||||
: data['tool'];
|
||||
? [data.tool, release.split(':')[1]].join(':')
|
||||
: data.tool;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -143,7 +267,7 @@ export async function filterList(tools_list: string[]): Promise<string[]> {
|
||||
case matches[0] == undefined:
|
||||
break;
|
||||
default:
|
||||
composer = matches[matches.length - 1].replace(/v(\d\S*)/, '$1');
|
||||
composer = matches.at(-1)!.replace(/v(\d\S*)/, '$1');
|
||||
break;
|
||||
}
|
||||
tools_list.unshift(composer);
|
||||
@@ -155,26 +279,27 @@ export async function filterList(tools_list: string[]): Promise<string[]> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function getUrl(data: RS): Promise<string> {
|
||||
if ((data['version'] ?? 'latest') === 'latest') {
|
||||
export async function getUrl(data: ToolInput): Promise<string> {
|
||||
const version = data.version ?? 'latest';
|
||||
if (version === 'latest' || version === '') {
|
||||
return [
|
||||
data['domain'],
|
||||
data['repository'],
|
||||
data['prefix'],
|
||||
data['version'],
|
||||
data['verb'],
|
||||
data['tool'] + data['extension']
|
||||
data.domain,
|
||||
data.repository,
|
||||
data.prefix,
|
||||
'latest',
|
||||
data.verb,
|
||||
data.tool + data.extension
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('/');
|
||||
} else {
|
||||
return [
|
||||
data['domain'],
|
||||
data['repository'],
|
||||
data['prefix'],
|
||||
data['verb'],
|
||||
data['version_prefix'] + data['version'],
|
||||
data['tool'] + data['extension']
|
||||
data.domain,
|
||||
data.repository,
|
||||
data.prefix,
|
||||
data.verb,
|
||||
data.version_prefix + data.version,
|
||||
data.tool + data.extension
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join('/');
|
||||
@@ -186,17 +311,17 @@ export async function getUrl(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function getPharUrl(data: RS): Promise<string> {
|
||||
if (data['version'] === 'latest') {
|
||||
return data['domain'] + '/' + data['tool'] + '.phar';
|
||||
export async function getPharUrl(data: ToolData): Promise<string> {
|
||||
if (data.version === 'latest') {
|
||||
return data.domain + '/' + data.tool + '.phar';
|
||||
} else {
|
||||
return (
|
||||
data['domain'] +
|
||||
data.domain +
|
||||
'/' +
|
||||
data['tool'] +
|
||||
data.tool +
|
||||
'-' +
|
||||
data['version_prefix'] +
|
||||
data['version'] +
|
||||
data.version_prefix +
|
||||
data.version +
|
||||
'.phar'
|
||||
);
|
||||
}
|
||||
@@ -207,10 +332,10 @@ export async function getPharUrl(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addArchive(data: RS): Promise<string> {
|
||||
export async function addArchive(data: ToolData): Promise<string> {
|
||||
return (
|
||||
(await utils.getCommand(data['os'], 'tool')) +
|
||||
(await utils.joins(data['url'], data['tool'], data['version_parameter']))
|
||||
(await utils.getCommand(data.os, 'tool')) +
|
||||
(await utils.joins(data.url, data.tool, data.version_parameter))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -219,15 +344,12 @@ export async function addArchive(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addPackage(data: RS): Promise<string> {
|
||||
const command = await utils.getCommand(data['os'], 'composer_tool');
|
||||
const parts: string[] = data['repository'].split('/');
|
||||
const args: string = await utils.joins(
|
||||
parts[1],
|
||||
data['release'],
|
||||
parts[0] + '/',
|
||||
data['scope']
|
||||
);
|
||||
export async function addPackage(data: ToolData): Promise<string> {
|
||||
const command = await utils.getCommand(data.os, 'composer_tool');
|
||||
const parts: string[] = data.repository.split('/');
|
||||
const args = [parts[1], data.release, parts[0] + '/', data.scope]
|
||||
.map(a => utils.safeArg(a, data.os))
|
||||
.join(' ');
|
||||
return command + args;
|
||||
}
|
||||
|
||||
@@ -236,24 +358,24 @@ export async function addPackage(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addBlackfirePlayer(data: RS): Promise<string> {
|
||||
switch (data['os']) {
|
||||
export async function addBlackfirePlayer(data: ToolData): Promise<string> {
|
||||
switch (data.os) {
|
||||
case 'win32':
|
||||
return await utils.addLog(
|
||||
'$cross',
|
||||
data['tool'],
|
||||
data['tool'] + ' is not a windows tool',
|
||||
data.tool,
|
||||
data.tool + ' is not a windows tool',
|
||||
'win32'
|
||||
);
|
||||
default:
|
||||
if (data['version'] == 'latest') {
|
||||
if (/5\.[5-6]|7\.0/.test(data['php_version'])) {
|
||||
data['version'] = '1.9.3';
|
||||
} else if (/7\.[1-4]|8\.0/.test(data['php_version'])) {
|
||||
data['version'] = '1.22.0';
|
||||
if (data.version == 'latest') {
|
||||
if (/5\.[5-6]|7\.0/.test(data.php_version)) {
|
||||
data.version = '1.9.3';
|
||||
} else if (/7\.[1-4]|8\.0/.test(data.php_version)) {
|
||||
data.version = '1.22.0';
|
||||
}
|
||||
}
|
||||
data['url'] = await getPharUrl(data);
|
||||
data.url = await getPharUrl(data);
|
||||
return addArchive(data);
|
||||
}
|
||||
}
|
||||
@@ -263,12 +385,12 @@ export async function addBlackfirePlayer(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addCastor(data: RS): Promise<string> {
|
||||
data['tool'] = 'castor.' + data['os'].replace('win32', 'windows') + '-amd64';
|
||||
data['url'] = await getUrl(data);
|
||||
data['tool'] = 'castor';
|
||||
data['version_parameter'] = fs.existsSync('castor.php')
|
||||
? data['version_parameter']
|
||||
export async function addCastor(data: ToolData): Promise<string> {
|
||||
data.tool = 'castor.' + data.os.replace('win32', 'windows') + '-amd64';
|
||||
data.url = await getUrl(data);
|
||||
data.tool = 'castor';
|
||||
data.version_parameter = fs.existsSync('castor.php')
|
||||
? data.version_parameter
|
||||
: '';
|
||||
return await addArchive(data);
|
||||
}
|
||||
@@ -278,22 +400,23 @@ export async function addCastor(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addComposer(data: RS): Promise<string> {
|
||||
const channel = data['version'].replace('latest', 'stable');
|
||||
const github = data['github'];
|
||||
const getcomposer = data['domain'];
|
||||
export async function addComposer(data: ToolData): Promise<string> {
|
||||
const channel = data.version.replace('latest', 'stable');
|
||||
const github = data.github;
|
||||
const getcomposer = data.domain;
|
||||
const cds = 'https://dl.cloudsmith.io';
|
||||
const spc = 'https://artifacts.setup-php.com';
|
||||
const filename = `composer-${data['php_version']}-${channel}.phar`;
|
||||
const filename = `composer-${data.php_version}-${channel}.phar`;
|
||||
const releases_url = `${github}/shivammathur/composer-cache/releases/latest/download/${filename}`;
|
||||
const cds_url = `${cds}/public/shivammathur/composer-cache/raw/files/${filename}`;
|
||||
const spc_url = `${spc}/composer/${filename}`;
|
||||
const lts_url = `${getcomposer}/download/latest-2.2.x/composer.phar`;
|
||||
const is_lts = /^5\.[3-6]$|^7\.[0-1]$/.test(data['php_version']);
|
||||
const is_lts = /^5\.[3-6]$|^7\.[0-1]$/.test(data.php_version);
|
||||
const channel_source_url = `${getcomposer}/composer-${channel}.phar`;
|
||||
const version_source_url = `${getcomposer}/download/${channel}/composer.phar`;
|
||||
let cache_url = `${releases_url},${spc_url},${cds_url}`;
|
||||
let source_url = `${getcomposer}/composer.phar`;
|
||||
let skip_composer_github_auth = '';
|
||||
switch (true) {
|
||||
case /^snapshot$/.test(channel):
|
||||
source_url = is_lts ? lts_url : source_url;
|
||||
@@ -304,16 +427,20 @@ export async function addComposer(data: RS): Promise<string> {
|
||||
case /^1$/.test(channel):
|
||||
source_url = channel_source_url;
|
||||
break;
|
||||
case /^\d+\.\d+\.\d+[\w-]*$/.test(data['version']):
|
||||
cache_url = `${github}/${data['repository']}/releases/download/${data['version']}/composer.phar`;
|
||||
case /^\d+\.\d+\.\d+(?:-[\w-]+)?$/.test(data.version):
|
||||
if (skipGitHubAuthForComposerVersion(data.version)) {
|
||||
cleanComposerAuthJson();
|
||||
skip_composer_github_auth = ' true';
|
||||
}
|
||||
cache_url = `${github}/${data.repository}/releases/download/${data.version}/composer.phar`;
|
||||
source_url = version_source_url;
|
||||
break;
|
||||
default:
|
||||
source_url = is_lts ? lts_url : channel_source_url;
|
||||
}
|
||||
const use_cache: boolean = (await utils.readEnv('NO_TOOLS_CACHE')) !== 'true';
|
||||
data['url'] = use_cache ? `${cache_url},${source_url}` : source_url;
|
||||
data['version_parameter'] = data['version'];
|
||||
data.url = use_cache ? `${cache_url},${source_url}` : source_url;
|
||||
data.version_parameter = data.version + skip_composer_github_auth;
|
||||
return await addArchive(data);
|
||||
}
|
||||
|
||||
@@ -322,27 +449,27 @@ export async function addComposer(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addDeployer(data: RS): Promise<string> {
|
||||
if (data['version'] === 'latest') {
|
||||
data['url'] = data['domain'] + '/deployer.phar';
|
||||
export async function addDeployer(data: ToolData): Promise<string> {
|
||||
if (data.version === 'latest') {
|
||||
data.url = data.domain + '/deployer.phar';
|
||||
} else {
|
||||
const manifest: RS = await fetch.fetch(
|
||||
'https://deployer.org/manifest.json'
|
||||
const manifest = await fetch.fetch('https://deployer.org/manifest.json');
|
||||
const version_data: Record<string, DeployerManifestEntry> = JSON.parse(
|
||||
manifest.data
|
||||
);
|
||||
const version_data: RSRS = JSON.parse(manifest.data);
|
||||
const version_key: string | undefined = Object.keys(version_data).find(
|
||||
(key: string) => {
|
||||
return version_data[key]['version'] === data['version'];
|
||||
return version_data[key].version === data.version;
|
||||
}
|
||||
);
|
||||
if (version_key) {
|
||||
data['url'] = version_data[version_key]['url'];
|
||||
data.url = version_data[version_key].url;
|
||||
} else {
|
||||
return await utils.addLog(
|
||||
'$cross',
|
||||
'deployer',
|
||||
'Version missing in deployer manifest',
|
||||
data['os']
|
||||
data.os
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -354,22 +481,22 @@ export async function addDeployer(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addDevTools(data: RS): Promise<string> {
|
||||
switch (data['os']) {
|
||||
export async function addDevTools(data: ToolData): Promise<string> {
|
||||
switch (data.os) {
|
||||
case 'linux':
|
||||
case 'darwin':
|
||||
return 'add_devtools ' + data['tool'];
|
||||
return 'add_devtools ' + data.tool;
|
||||
case 'win32':
|
||||
return await utils.addLog(
|
||||
'$tick',
|
||||
data['tool'],
|
||||
data['tool'] + ' is not a windows tool',
|
||||
data.tool,
|
||||
data.tool + ' is not a windows tool',
|
||||
'win32'
|
||||
);
|
||||
default:
|
||||
return await utils.log(
|
||||
'Platform ' + data['os'] + ' is not supported',
|
||||
data['os'],
|
||||
'Platform ' + data.os + ' is not supported',
|
||||
data.os,
|
||||
'error'
|
||||
);
|
||||
}
|
||||
@@ -380,8 +507,8 @@ export async function addDevTools(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addPECL(data: RS): Promise<string> {
|
||||
return await utils.getCommand(data['os'], 'pecl');
|
||||
export async function addPECL(data: ToolData): Promise<string> {
|
||||
return await utils.getCommand(data.os, 'pecl');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -389,14 +516,13 @@ export async function addPECL(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addPhing(data: RS): Promise<string> {
|
||||
data['url'] =
|
||||
data['domain'] + '/get/phing-' + data['version'] + data['extension'];
|
||||
if (data['version'] != 'latest') {
|
||||
[data['prefix'], data['verb']] = ['releases', 'download'];
|
||||
data['domain'] = data['github'];
|
||||
data['extension'] = '-' + data['version'] + data['extension'];
|
||||
data['url'] += ',' + (await getUrl(data));
|
||||
export async function addPhing(data: ToolData): Promise<string> {
|
||||
data.url = data.domain + '/get/phing-' + data.version + data.extension;
|
||||
if (data.version != 'latest') {
|
||||
[data.prefix, data.verb] = ['releases', 'download'];
|
||||
data.domain = data.github;
|
||||
data.extension = '-' + data.version + data.extension;
|
||||
data.url += ',' + (await getUrl(data));
|
||||
}
|
||||
return await addArchive(data);
|
||||
}
|
||||
@@ -406,33 +532,33 @@ export async function addPhing(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addPhive(data: RS): Promise<string> {
|
||||
export async function addPhive(data: ToolData): Promise<string> {
|
||||
switch (true) {
|
||||
case /5\.[3-5]/.test(data['php_version']):
|
||||
case /5\.[3-5]/.test(data.php_version):
|
||||
return await utils.addLog(
|
||||
'$cross',
|
||||
'phive',
|
||||
'Phive is not supported on PHP ' + data['php_version'],
|
||||
data['os']
|
||||
'Phive is not supported on PHP ' + data.php_version,
|
||||
data.os
|
||||
);
|
||||
case /5\.6|7\.0/.test(data['php_version']):
|
||||
data['version'] = '0.12.1';
|
||||
case /5\.6|7\.0/.test(data.php_version):
|
||||
data.version = '0.12.1';
|
||||
break;
|
||||
case /7\.1/.test(data['php_version']):
|
||||
data['version'] = '0.13.5';
|
||||
case /7\.1/.test(data.php_version):
|
||||
data.version = '0.13.5';
|
||||
break;
|
||||
case /7\.2/.test(data['php_version']):
|
||||
data['version'] = '0.14.5';
|
||||
case /7\.2/.test(data.php_version):
|
||||
data.version = '0.14.5';
|
||||
break;
|
||||
case /7\.3|7\.4/.test(data['php_version']):
|
||||
data['version'] = '0.15.3';
|
||||
case /7\.3|7\.4/.test(data.php_version):
|
||||
data.version = '0.15.3';
|
||||
break;
|
||||
case /^latest$/.test(data['version']):
|
||||
data['version'] = await getLatestVersion(data);
|
||||
case /^latest$/.test(data.version):
|
||||
data.version = await getLatestVersion(data);
|
||||
break;
|
||||
}
|
||||
data['extension'] = '-' + data['version'] + data['extension'];
|
||||
data['url'] = await getUrl(data);
|
||||
data.extension = '-' + data.version + data.extension;
|
||||
data.url = await getUrl(data);
|
||||
return await addArchive(data);
|
||||
}
|
||||
|
||||
@@ -441,16 +567,15 @@ export async function addPhive(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addPHPUnitTools(data: RS): Promise<string> {
|
||||
export async function addPHPUnitTools(data: ToolData): Promise<string> {
|
||||
/* istanbul ignore next */
|
||||
if (data['version'] === 'latest') {
|
||||
data['version'] =
|
||||
(await packagist.search(data['packagist'], data['php_version'])) ??
|
||||
'latest';
|
||||
if (data.version === 'latest') {
|
||||
data.version =
|
||||
(await packagist.search(data.packagist, data.php_version)) ?? 'latest';
|
||||
}
|
||||
data['url'] = await getPharUrl(data);
|
||||
if (data['url'].match(/-\d+/)) {
|
||||
data['url'] += ',' + data['url'].replace(/-(\d+)\.\d+\.\d+/, '-$1');
|
||||
data.url = await getPharUrl(data);
|
||||
if (data.url.match(/-\d+/)) {
|
||||
data.url += ',' + data.url.replace(/-(\d+)\.\d+\.\d+/, '-$1');
|
||||
}
|
||||
return await addArchive(data);
|
||||
}
|
||||
@@ -460,13 +585,13 @@ export async function addPHPUnitTools(data: RS): Promise<string> {
|
||||
*
|
||||
* @param data
|
||||
*/
|
||||
export async function addWPCLI(data: RS): Promise<string> {
|
||||
if (data['version'] === 'latest') {
|
||||
data['uri'] = 'wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true';
|
||||
data['url'] = [data['domain'], data['uri']].join('/');
|
||||
export async function addWPCLI(data: ToolData): Promise<string> {
|
||||
if (data.version === 'latest') {
|
||||
data.uri = 'wp-cli/builds/blob/gh-pages/phar/wp-cli.phar?raw=true';
|
||||
data.url = [data.domain, data.uri].join('/');
|
||||
} else {
|
||||
data['extension'] = '-' + data['version'] + data['extension'];
|
||||
data['url'] = await getUrl(data);
|
||||
data.extension = '-' + data.version + data.extension;
|
||||
data.url = await getUrl(data);
|
||||
}
|
||||
return await addArchive(data);
|
||||
}
|
||||
@@ -482,56 +607,74 @@ export async function getData(
|
||||
release: string,
|
||||
php_version: string,
|
||||
os: string
|
||||
): Promise<RS> {
|
||||
): Promise<ToolData> {
|
||||
const json_file_path = path.join(__dirname, '../src/configs/tools.json');
|
||||
const json_file: string = fs.readFileSync(json_file_path, 'utf8');
|
||||
const json_objects: RSRS = JSON.parse(json_file);
|
||||
const json_objects: Record<string, ToolConfig> = JSON.parse(json_file);
|
||||
release = release.replace(/\s+/g, '');
|
||||
const parts: string[] = release.split(':');
|
||||
const tool = parts[0];
|
||||
const version = parts[1];
|
||||
let data: RS;
|
||||
if (Object.keys(json_objects).includes(tool)) {
|
||||
data = json_objects[tool];
|
||||
data['tool'] = tool;
|
||||
let config: ToolConfig & {tool: string};
|
||||
if (Object.hasOwn(json_objects, tool)) {
|
||||
config = {...json_objects[tool], tool};
|
||||
} else {
|
||||
const key: string | undefined = Object.keys(json_objects).find(
|
||||
(key: string) => {
|
||||
return json_objects[key]['alias'] == tool;
|
||||
return json_objects[key].alias == tool;
|
||||
}
|
||||
);
|
||||
if (key) {
|
||||
data = json_objects[key];
|
||||
data['tool'] = key;
|
||||
} else {
|
||||
data = {
|
||||
config = {...json_objects[key], tool: key};
|
||||
} else if (tool.includes('/')) {
|
||||
config = {
|
||||
tool: tool.split('/')[1],
|
||||
repository: tool,
|
||||
type: 'composer'
|
||||
};
|
||||
data = !tool.includes('/') ? {tool: tool} : data;
|
||||
} else {
|
||||
config = {tool};
|
||||
}
|
||||
}
|
||||
data['github'] = 'https://github.com';
|
||||
data['domain'] ??= data['github'];
|
||||
data['extension'] ??= '.phar';
|
||||
data['os'] = os;
|
||||
data['php_version'] = php_version;
|
||||
data['packagist'] ??= data['repository'];
|
||||
data['prefix'] = data['github'] === data['domain'] ? 'releases' : '';
|
||||
data['verb'] = data['github'] === data['domain'] ? 'download' : '';
|
||||
data['fetch_latest'] ??= 'false';
|
||||
data['scope'] ??= 'global';
|
||||
data['version_parameter'] = JSON.stringify(data['version_parameter']) || '';
|
||||
data['version_prefix'] ??= '';
|
||||
data['release'] = await getRelease(release, data);
|
||||
data['version'] = version
|
||||
const github = 'https://github.com';
|
||||
const domain = config.domain ?? github;
|
||||
const data: ToolData = {
|
||||
tool: config.tool,
|
||||
version: '',
|
||||
url: '',
|
||||
os,
|
||||
php_version,
|
||||
github,
|
||||
domain,
|
||||
extension: config.extension ?? '.phar',
|
||||
repository: config.repository ?? '',
|
||||
prefix: domain === github ? 'releases' : '',
|
||||
verb: domain === github ? 'download' : '',
|
||||
fetch_latest: config.fetch_latest ?? 'false',
|
||||
scope: config.scope ?? 'global',
|
||||
version_parameter:
|
||||
config.version_parameter != null
|
||||
? JSON.stringify(config.version_parameter)
|
||||
: '',
|
||||
version_prefix: config.version_prefix ?? '',
|
||||
release: '',
|
||||
packagist: config.packagist ?? config.repository ?? '',
|
||||
type: config.type,
|
||||
function: config.function,
|
||||
alias: config.alias
|
||||
};
|
||||
data.release = await getRelease(release, data);
|
||||
data.version = version
|
||||
? await getVersion(version, data)
|
||||
: await getLatestVersion(data);
|
||||
data.url = await getUrl(data);
|
||||
return data;
|
||||
}
|
||||
|
||||
export const functionRecord: Record<string, (data: RS) => Promise<string>> = {
|
||||
export const functionRecord: Record<
|
||||
ToolFunction,
|
||||
(data: ToolData) => Promise<string>
|
||||
> = {
|
||||
castor: addCastor,
|
||||
composer: addComposer,
|
||||
deployer: addDeployer,
|
||||
@@ -565,43 +708,46 @@ export async function addTools(
|
||||
}
|
||||
const tools_list = await filterList(await utils.CSVArray(tools_csv));
|
||||
await utils.asyncForEach(tools_list, async function (release: string) {
|
||||
const data: RS = await getData(release, php_version, os);
|
||||
const data: ToolData = await getData(release, php_version, os);
|
||||
script += '\n';
|
||||
switch (true) {
|
||||
case data['error'] !== undefined:
|
||||
script += await utils.addLog(
|
||||
'$cross',
|
||||
data['tool'],
|
||||
data['error'],
|
||||
data['os']
|
||||
);
|
||||
case data.error !== undefined:
|
||||
script += await utils.addLog('$cross', data.tool, data.error, data.os);
|
||||
break;
|
||||
case 'phar' === data['type']:
|
||||
data['url'] = await getUrl(data);
|
||||
case 'phar' === data.type:
|
||||
script += await addArchive(data);
|
||||
break;
|
||||
case 'composer' === data['type']:
|
||||
case 'composer' === data.type:
|
||||
script += await addPackage(data);
|
||||
break;
|
||||
case 'custom-package' === data['type']:
|
||||
case 'custom-package' === data.type:
|
||||
script += await utils.customPackage(
|
||||
data['tool'].split('-')[0],
|
||||
data.tool.split('-')[0],
|
||||
'tools',
|
||||
data['version'],
|
||||
data['os']
|
||||
data.version,
|
||||
data.os
|
||||
);
|
||||
break;
|
||||
case 'custom-function' === data['type']:
|
||||
script += await functionRecord[data['function']](data);
|
||||
case 'custom-function' === data.type:
|
||||
if (!data.function) {
|
||||
script += await utils.addLog(
|
||||
'$cross',
|
||||
data.tool,
|
||||
data.tool + ' has no function defined. Please report this issue.',
|
||||
data.os
|
||||
);
|
||||
} else {
|
||||
script += await functionRecord[data.function](data);
|
||||
}
|
||||
break;
|
||||
case /^none$/.test(data['tool']):
|
||||
case /^none$/.test(data.tool):
|
||||
break;
|
||||
default:
|
||||
script += await utils.addLog(
|
||||
'$cross',
|
||||
data['tool'],
|
||||
'Tool ' + data['tool'] + ' is not supported',
|
||||
data['os']
|
||||
data.tool,
|
||||
'Tool ' + data.tool + ' is not supported',
|
||||
data.os
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
115
src/utils.ts
115
src/utils.ts
@@ -1,6 +1,6 @@
|
||||
import fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import * as core from '@actions/core';
|
||||
import * as core from './core';
|
||||
import * as fetch from './fetch';
|
||||
|
||||
/**
|
||||
@@ -62,15 +62,31 @@ export async function getManifestURLS(): Promise<string[]> {
|
||||
*/
|
||||
export async function parseVersion(version: string): Promise<string> {
|
||||
switch (true) {
|
||||
case /^(latest|lowest|highest|nightly|\d+\.x)$/.test(version):
|
||||
case /^pre(-installed)?$/.test(version):
|
||||
return 'pre';
|
||||
case /^(latest|lowest|highest|nightly|master|\d+\.x)$/.test(version):
|
||||
for (const manifestURL of await getManifestURLS()) {
|
||||
const fetchResult = await fetch.fetch(manifestURL);
|
||||
if (fetchResult['data'] ?? false) {
|
||||
return JSON.parse(fetchResult['data'])[version];
|
||||
const resolved: string | undefined = JSON.parse(fetchResult['data'])[
|
||||
version
|
||||
];
|
||||
if (resolved === undefined) {
|
||||
throw new Error(`Invalid PHP version: ${version.slice(0, 20)}`);
|
||||
}
|
||||
if (!/^\d+\.\d+$/.test(resolved)) {
|
||||
throw new Error(
|
||||
`Invalid PHP version in manifest: ${resolved.slice(0, 10)}`
|
||||
);
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
}
|
||||
throw new Error(`Could not fetch the PHP version manifest.`);
|
||||
default:
|
||||
if (!/^\d+(\.\d+){0,2}$/.test(version)) {
|
||||
throw new Error(`Invalid PHP version: ${version.slice(0, 20)}`);
|
||||
}
|
||||
switch (true) {
|
||||
case version.length > 1:
|
||||
return version.slice(0, 3);
|
||||
@@ -86,20 +102,16 @@ export async function parseVersion(version: string): Promise<string> {
|
||||
* @param ini_file
|
||||
*/
|
||||
export async function parseIniFile(ini_file: string): Promise<string> {
|
||||
switch (true) {
|
||||
case /^(production|development|none)$/.test(ini_file):
|
||||
return ini_file;
|
||||
case /php\.ini-(production|development)$/.test(ini_file):
|
||||
return ini_file.split('-')[1];
|
||||
default:
|
||||
return 'production';
|
||||
if (/^(production|development|none)$/.test(ini_file)) {
|
||||
return ini_file;
|
||||
}
|
||||
const match = ini_file.match(/php\.ini-(production|development)$/);
|
||||
return match ? match[1] : 'production';
|
||||
}
|
||||
|
||||
/**
|
||||
* Async foreach loop
|
||||
* Async foreach loop using modern for...of pattern
|
||||
*
|
||||
* @author https://github.com/Atinux
|
||||
* @param array
|
||||
* @param callback
|
||||
*/
|
||||
@@ -111,8 +123,8 @@ export async function asyncForEach(
|
||||
array: Array<string>
|
||||
) => Promise<void>
|
||||
): Promise<void> {
|
||||
for (let index = 0; index < array.length; index++) {
|
||||
await callback(array[index], index, array);
|
||||
for (const [index, element] of array.entries()) {
|
||||
await callback(element, index, array);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,10 +185,10 @@ export async function log(
|
||||
export async function stepLog(message: string, os: string): Promise<string> {
|
||||
switch (os) {
|
||||
case 'win32':
|
||||
return 'Step-Log "' + message + '"';
|
||||
return 'Step-Log "' + escapeForShell(message, os) + '"';
|
||||
case 'linux':
|
||||
case 'darwin':
|
||||
return 'step_log "' + message + '"';
|
||||
return 'step_log "' + escapeForShell(message, os) + '"';
|
||||
default:
|
||||
return await log('Platform ' + os + ' is not supported', os, 'error');
|
||||
}
|
||||
@@ -195,17 +207,40 @@ export async function addLog(
|
||||
message: string,
|
||||
os: string
|
||||
): Promise<string> {
|
||||
const sub = escapeForShell(subject, os);
|
||||
const msg = escapeForShell(message, os);
|
||||
switch (os) {
|
||||
case 'win32':
|
||||
return 'Add-Log "' + mark + '" "' + subject + '" "' + message + '"';
|
||||
return `Add-Log "${mark}" "${sub}" "${msg}"`;
|
||||
case 'linux':
|
||||
case 'darwin':
|
||||
return 'add_log "' + mark + '" "' + subject + '" "' + message + '"';
|
||||
return `add_log "${mark}" "${sub}" "${msg}"`;
|
||||
default:
|
||||
return await log('Platform ' + os + ' is not supported', os, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
export function escapeForShell(value: string, os: string): string {
|
||||
if (os === 'win32') {
|
||||
return value.replace(/[`$"]/g, '`$&');
|
||||
}
|
||||
return value.replace(/[\\`$"]/g, '\\$&');
|
||||
}
|
||||
|
||||
export function safeArg(value: string, os: string): string {
|
||||
if (!/^[a-zA-Z0-9_./:@+,~^-]*$/.test(value)) {
|
||||
return '"' + escapeForShell(value, os) + '"';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function sanitizeShellInput(value: string, strict = false): string {
|
||||
const pattern = strict
|
||||
? /[$`"';|&(){}[\]\\<>*?\n\r\t]/g
|
||||
: /[$`"';|&(){}[\]\\\n\r\t]/g;
|
||||
return value.replace(pattern, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to break extension csv into an array
|
||||
*
|
||||
@@ -225,11 +260,11 @@ export async function extensionArray(
|
||||
.split(',')
|
||||
|
||||
.map(function (extension: string) {
|
||||
extension = extension.trim().replace(/^\\\s*/, '');
|
||||
if (/.+-.+\/.+@.+/.test(extension)) {
|
||||
return extension;
|
||||
}
|
||||
return extension
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.replace(/^(:)?(php[-_]|none|zend )|(-[^-]*)-/, '$1$3');
|
||||
})
|
||||
@@ -432,22 +467,35 @@ export async function parseExtensionSource(
|
||||
);
|
||||
}
|
||||
|
||||
const VERSION_INPUT_REGEX =
|
||||
/^(latest|lowest|highest|nightly|master|pre|pre-installed|\d+\.x|\d+(\.\d+){0,2})$/;
|
||||
|
||||
function validatePHPVersionInput(version: string, source: string): string {
|
||||
if (!VERSION_INPUT_REGEX.test(version)) {
|
||||
throw new Error(
|
||||
`Invalid PHP version in ${source}: ${version.slice(0, 20)}`
|
||||
);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read php version from input or file
|
||||
*/
|
||||
export async function readPHPVersion(): Promise<string> {
|
||||
const version = await getInput('php-version', false);
|
||||
if (version) {
|
||||
return version;
|
||||
return validatePHPVersionInput(version, 'php-version input');
|
||||
}
|
||||
const versionFile =
|
||||
(await getInput('php-version-file', false)) || '.php-version';
|
||||
if (fs.existsSync(versionFile)) {
|
||||
const contents: string = fs.readFileSync(versionFile, 'utf8');
|
||||
const match: RegExpMatchArray | null = contents.match(
|
||||
/^(?:php\s)?(\d+\.\d+\.\d+)$/m
|
||||
const match = contents.match(/^(?:php\s)?(\d+\.\d+\.\d+)$/m);
|
||||
return validatePHPVersionInput(
|
||||
match ? match[1] : contents.trim(),
|
||||
versionFile
|
||||
);
|
||||
return match ? match[1] : contents.trim();
|
||||
} else if (versionFile !== '.php-version') {
|
||||
throw new Error(`Could not find '${versionFile}' file.`);
|
||||
}
|
||||
@@ -457,11 +505,11 @@ export async function readPHPVersion(): Promise<string> {
|
||||
if (fs.existsSync(composerLock)) {
|
||||
const lockFileContents = JSON.parse(fs.readFileSync(composerLock, 'utf8'));
|
||||
/* istanbul ignore next */
|
||||
if (
|
||||
lockFileContents['platform-overrides'] &&
|
||||
lockFileContents['platform-overrides']['php']
|
||||
) {
|
||||
return lockFileContents['platform-overrides']['php'];
|
||||
if (lockFileContents['platform-overrides']?.['php']) {
|
||||
return validatePHPVersionInput(
|
||||
lockFileContents['platform-overrides']['php'],
|
||||
'composer.lock platform-overrides.php'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,12 +519,11 @@ export async function readPHPVersion(): Promise<string> {
|
||||
fs.readFileSync(composerJson, 'utf8')
|
||||
);
|
||||
/* istanbul ignore next */
|
||||
if (
|
||||
composerFileContents['config'] &&
|
||||
composerFileContents['config']['platform'] &&
|
||||
composerFileContents['config']['platform']['php']
|
||||
) {
|
||||
return composerFileContents['config']['platform']['php'];
|
||||
if (composerFileContents['config']?.['platform']?.['php']) {
|
||||
return validatePHPVersionInput(
|
||||
composerFileContents['config']['platform']['php'],
|
||||
'composer.json config.platform.php'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"declaration": true,
|
||||
"esModuleInterop": true,
|
||||
"lib": [
|
||||
"ES2021"
|
||||
"ES2024"
|
||||
],
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
@@ -13,7 +13,7 @@
|
||||
"rootDir": "./src",
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"target": "ES2021"
|
||||
"target": "ES2024"
|
||||
},
|
||||
"exclude": ["__tests__", "lib", "node_modules"]
|
||||
}
|
||||
Reference in New Issue
Block a user