Improve support for composer authenticating private respositories

This commit is contained in:
Shivam Mathur 2022-07-06 12:19:55 +05:30
parent cdb037c2a4
commit cf5cd90b4c
No known key found for this signature in database
GPG Key ID: 3E13E4C8591ACC2A
6 changed files with 115 additions and 17 deletions

View File

@ -51,7 +51,9 @@ Setup PHP with required extensions, php.ini configuration, code-coverage support
- [JIT Configuration](#jit-configuration) - [JIT Configuration](#jit-configuration)
- [Cache Extensions](#cache-extensions) - [Cache Extensions](#cache-extensions)
- [Cache Composer Dependencies](#cache-composer-dependencies) - [Cache Composer Dependencies](#cache-composer-dependencies)
- [Composer GitHub OAuth](#composer-github-oauth) - [GitHub Composer Authentication](#github-composer-authentication)
- [Private Packagist Authentication](#private-packagist-authentication)
- [Manual Composer Authentication](#manual-composer-authentication)
- [Inline PHP Scripts](#inline-php-scripts) - [Inline PHP Scripts](#inline-php-scripts)
- [Problem Matchers](#problem-matchers) - [Problem Matchers](#problem-matchers)
- [Examples](#examples) - [Examples](#examples)
@ -252,7 +254,7 @@ These tools can be set up globally using the `tools` input. It accepts a string
When you specify just the major version or the version in `major.minor` format, the latest patch version matching the input will be setup. When you specify just the major version or the version in `major.minor` format, the latest patch version matching the input will be setup.
Except for major versions of `composer`, For other tools when you specify only the `major` version or the version in `major.minor` format for any tool you can get rate limited by GitHub's API. To avoid this, it is recommended to provide a [`GitHub` OAuth token](https://github.com/shivammathur/setup-php#composer-github-oauth "Composer GitHub OAuth"). You can do that by setting `COMPOSER_TOKEN` environment variable. Except for major versions of `composer`, For other tools when you specify only the `major` version or the version in `major.minor` format for any tool you can get rate limited by GitHub's API. To avoid this, it is recommended to provide a [`GitHub` OAuth token](https://github.com/shivammathur/setup-php#composer-github-oauth "Composer GitHub OAuth"). You can do that by setting `GITHUB_TOKEN` environment variable. The `COMPOSER_TOKEN` environment variable has been deprecated in favor of `GITHUB_TOKEN` and will be removed in a future release.
```yaml ```yaml
- name: Setup PHP with tools - name: Setup PHP with tools
@ -261,7 +263,7 @@ These tools can be set up globally using the `tools` input. It accepts a string
php-version: '8.1' php-version: '8.1'
tools: php-cs-fixer:3.5, phpunit:9.5 tools: php-cs-fixer:3.5, phpunit:9.5
env: env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
``` ```
- The latest stable version of `composer` is set up by default. You can set up the required `composer` version by specifying the major version `v1` or `v2`, or the version in `major.minor` or `semver` format. Additionally for composer `snapshot` and `preview` can also be specified to set up the respective releases. - The latest stable version of `composer` is set up by default. You can set up the required `composer` version by specifying the major version `v1` or `v2`, or the version in `major.minor` or `semver` format. Additionally for composer `snapshot` and `preview` can also be specified to set up the respective releases.
@ -736,9 +738,10 @@ key: ${{ runner.os }}-composer-${{ matrix.prefer }}-${{ hashFiles('**/composer.l
restore-keys: ${{ runner.os }}-composer-${{ matrix.prefer }}- restore-keys: ${{ runner.os }}-composer-${{ matrix.prefer }}-
``` ```
### Composer GitHub OAuth ### GitHub Composer Authentication
If you have a number of workflows which set up multiple tools or have many composer dependencies, you might hit the GitHub's rate limit for composer. Also, if you specify only the major version or the version in `major.minor` format, you can hit the rate limit. To avoid this you can specify an `OAuth` token by setting `COMPOSER_TOKEN` environment variable. You can use [`GITHUB_TOKEN`](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token "GITHUB_TOKEN documentation") secret for this purpose. If you have a number of workflows which set up multiple tools or have many composer dependencies, you might hit the GitHub's rate limit for composer. Also, if you specify only the major version or the version in `major.minor` format, you can hit the rate limit. To avoid this you can specify an `OAuth` token by setting `GITHUB_TOKEN` environment variable. You can use [`GITHUB_TOKEN`](https://help.github.com/en/actions/configuring-and-managing-workflows/authenticating-with-the-github_token "GITHUB_TOKEN documentation") secret for this purpose.
The `COMPOSER_TOKEN` key has been deprecated in favor of `GITHUB_TOKEN` and will be removed in the next major version.
```yaml ```yaml
- name: Setup PHP - name: Setup PHP
@ -746,7 +749,42 @@ If you have a number of workflows which set up multiple tools or have many compo
with: with:
php-version: '8.1' php-version: '8.1'
env: env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
### Private Packagist Authentication
If you use Private Packagist for your private composer dependencies, you can set the `PACKAGIST_TOKEN` environment variable to authenticate.
```yaml
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
env:
PACKAGIST_TOKEN: ${{ secrets.PACKAGIST_TOKEN }}
```
### Manual Composer Authentication
In addition to GitHub or Private Packagist, if you want to authenticate private repositories hosted elsewhere, you can set the `COMPOSER_AUTH_JSON` environment variable with the authentication methods and the credentials in json format.
Please refer to the authentication section in [`composer documentation`](https://getcomposer.org/doc/articles/authentication-for-private-packages.md "composer documentation") for more details.
```yaml
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
env:
COMPOSER_AUTH_JSON: |
{
"http-basic": {
"example.org": {
"username": "${{ secrets.EXAMPLE_ORG_USERNAME }}",
"password": "${{ secrets.EXAMPLE_ORG_PASSWORD }}"
}
}
}
``` ```
### Inline PHP Scripts ### Inline PHP Scripts

View File

@ -527,4 +527,14 @@ describe('Tools tests', () => {
process.env['COMPOSER_TOKEN'] = token; process.env['COMPOSER_TOKEN'] = token;
expect(await tools.addTools(tools_csv, '7.4', 'linux')).toContain(script); 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);
});
}); });

8
dist/index.js vendored
View File

@ -622,8 +622,12 @@ const utils = __importStar(__nccwpck_require__(918));
async function getSemverVersion(data) { async function getSemverVersion(data) {
const search = data['version_prefix'] + data['version']; const search = data['version_prefix'] + data['version'];
const url = `https://api.github.com/repos/${data['repository']}/git/matching-refs/tags%2F${search}.`; const url = `https://api.github.com/repos/${data['repository']}/git/matching-refs/tags%2F${search}.`;
const token = await utils.readEnv('COMPOSER_TOKEN'); let github_token = await utils.readEnv('GITHUB_TOKEN');
const response = await fetch.fetch(url, token); const composer_token = await utils.readEnv('COMPOSER_TOKEN');
if (composer_token && !github_token) {
github_token = composer_token;
}
const response = await fetch.fetch(url, github_token);
if (response.error || response.data === '[]') { if (response.error || response.data === '[]') {
data['error'] = response.error ?? `No version found with prefix ${search}.`; data['error'] = response.error ?? `No version found with prefix ${search}.`;
return data['version']; return data['version'];

View File

@ -1,7 +1,8 @@
# Variables # Variables
$composer_bin = "$env:APPDATA\Composer\vendor\bin" $composer_home = "$env:APPDATA\Composer"
$composer_json = "$env:APPDATA\Composer\composer.json" $composer_bin = "$composer_home\vendor\bin"
$composer_lock = "$env:APPDATA\Composer\composer.lock" $composer_json = "$composer_home\composer.json"
$composer_lock = "$composer_home\composer.lock"
# Function to configure composer. # Function to configure composer.
Function Edit-ComposerConfig() { Function Edit-ComposerConfig() {
@ -24,8 +25,30 @@ Function Edit-ComposerConfig() {
} }
Add-EnvPATH $src\configs\composer.env Add-EnvPATH $src\configs\composer.env
Add-Path $composer_bin Add-Path $composer_bin
if (Test-Path env:COMPOSER_TOKEN) { Set-ComposerAuth
Add-Env COMPOSER_AUTH ('{"github-oauth": {"github.com": "' + $env:COMPOSER_TOKEN + '"}}') }
# Function to setup authentication in composer.
Function Set-ComposerAuth() {
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
} else {
Add-Log "$cross" "composer" "Could not parse COMPOSER_AUTH_JSON as valid JSON"
}
}
$composer_auth = @()
if(Test-Path env:PACKAGIST_TOKEN) {
$composer_auth += '"http-basic": {"repo.packagist.com": { "username": "token", "password": "' + $env:PACKAGIST_TOKEN + '"}}'
}
if(-not(Test-Path env:GITHUB_TOKEN) -and (Test-Path env:COMPOSER_TOKEN)) {
$env:GITHUB_TOKEN = $env:COMPOSER_TOKEN
}
if (Test-Path env:GITHUB_TOKEN) {
$composer_auth += '"github-oauth": {"github.com": "' + $env:GITHUB_TOKEN + '"}'
}
if($composer_auth.length) {
Add-Env COMPOSER_AUTH ('{' + ($composer_auth -join ',') + '}')
} }
} }

View File

@ -44,8 +44,27 @@ configure_composer() {
fi fi
add_env_path "${src:?}"/configs/composer.env add_env_path "${src:?}"/configs/composer.env
add_path "$composer_bin" add_path "$composer_bin"
if [ -n "$COMPOSER_TOKEN" ]; then set_composer_auth
add_env COMPOSER_AUTH '{"github-oauth": {"github.com": "'"$COMPOSER_TOKEN"'"}}' }
# 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
else
add_log "${cross:?}" "composer" "Could not parse COMPOSER_AUTH_JSON as valid JSON"
fi
fi
composer_auth=()
if [ -n "$PACKAGIST_TOKEN" ]; then
composer_auth+=( '"http-basic": {"repo.packagist.com": { "username": "token", "password": "'"$PACKAGIST_TOKEN"'"}}' )
fi
if [ -n "${GITHUB_TOKEN:-$COMPOSER_TOKEN}" ]; then
composer_auth+=( '"github-oauth": {"github.com": "'"${GITHUB_TOKEN:-$COMPOSER_TOKEN}"'"}' )
fi
if ((${#composer_auth[@]})); then
add_env COMPOSER_AUTH "{$(IFS=$','; echo "${composer_auth[*]}")}"
fi fi
} }

View File

@ -21,8 +21,12 @@ interface IRef {
export async function getSemverVersion(data: RS): Promise<string> { export async function getSemverVersion(data: RS): Promise<string> {
const search: string = data['version_prefix'] + data['version']; const search: string = data['version_prefix'] + data['version'];
const url = `https://api.github.com/repos/${data['repository']}/git/matching-refs/tags%2F${search}.`; const url = `https://api.github.com/repos/${data['repository']}/git/matching-refs/tags%2F${search}.`;
const token: string = await utils.readEnv('COMPOSER_TOKEN'); let github_token: string = await utils.readEnv('GITHUB_TOKEN');
const response: RS = await fetch.fetch(url, token); const composer_token: string = await utils.readEnv('COMPOSER_TOKEN');
if (composer_token && !github_token) {
github_token = composer_token;
}
const response: RS = await fetch.fetch(url, github_token);
if (response.error || response.data === '[]') { if (response.error || response.data === '[]') {
data['error'] = response.error ?? `No version found with prefix ${search}.`; data['error'] = response.error ?? `No version found with prefix ${search}.`;
return data['version']; return data['version'];