Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
db59fa1
api_refs.sh: Avoid hint about master VS main
adriendupuis May 22, 2026
ef1d3d8
api_refs.sh: COMPOSER_BINARY var
adriendupuis May 22, 2026
7b1cffe
api_refs.sh: Fix Composer authentication
adriendupuis Jul 22, 2026
1b4ac28
README.md: Update
adriendupuis Jul 22, 2026
aff679f
README.md: Update
adriendupuis Jul 22, 2026
fa0d44c
README.md: Update
adriendupuis Jul 22, 2026
e31c321
api_refs.yaml: base_branch as an input
adriendupuis Jul 22, 2026
6673291
README.md: Update
adriendupuis Jul 22, 2026
8f370c4
api_refs.yaml: base_branch as an input
adriendupuis Jul 22, 2026
a9456d9
api_refs.yaml: base_branch as an input
adriendupuis Jul 22, 2026
1ee8124
Merge branch 'fix-api_refs-tool' into enh-api_refs-tool
adriendupuis Jul 22, 2026
d965cfa
tools/api_refs/README.md: More examples
adriendupuis Jul 22, 2026
0888a42
tools/api_refs/README.md: <!-- vale off -->
adriendupuis Jul 22, 2026
677c093
tools/api_refs/README.md: Format
adriendupuis Jul 22, 2026
6b95db9
api_refs.yaml: Add `work_branch` `force`
adriendupuis Jul 23, 2026
ee028f7
api_refs.yaml: Add `work_branch` `force`
adriendupuis Jul 23, 2026
869e544
api_refs.yaml: Add `work_branch` `force`
adriendupuis Jul 23, 2026
72edb9a
api_refs.yaml: Add `work_branch` `force`
adriendupuis Jul 23, 2026
820de14
api_refs.yaml: Fix `force`
adriendupuis Jul 23, 2026
5b7a3b3
api_refs.yaml: Fix `force`
adriendupuis Jul 23, 2026
3ecd58f
Merge branch '5.0' into fix-api_refs-tool
adriendupuis Jul 23, 2026
d3a8b2d
api_refs.yaml: Fix vulnerability w/ Copilot
adriendupuis Jul 23, 2026
a399a19
Apply suggestions from code review
adriendupuis Jul 23, 2026
14f74d5
Test $AUTH_JSON file existence
adriendupuis Jul 23, 2026
2ac2957
Apply suggestions from code review
adriendupuis Jul 23, 2026
5d8a58c
Merge branch 'fix-api_refs-tool' into enh-api_refs-tool
adriendupuis Jul 23, 2026
4d11558
Test $AUTH_JSON file existence
adriendupuis Jul 24, 2026
f2c809d
Test $AUTH_JSON file existence
adriendupuis Jul 24, 2026
6f5b84a
Merge branch 'fix-api_refs-tool' into enh-api_refs-tool
adriendupuis Jul 24, 2026
cc33091
Merge branch '5.0' into enh-api_refs-tool
adriendupuis Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 39 additions & 6 deletions .github/workflows/api_refs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ on:
required: false
type: boolean
default: false
base_branch:
description: 'Start from this branch of the doc to build the refs (default: Maj.min from version)'
required: false
type: string
work_branch:
description: 'Commit builds to this branch of the doc (default: api_refs_<version>)'
required: false
type: string
force:
description: 'Push to work_branch even if it exists (default: false)'
required: false
type: boolean
default: false

jobs:
open_php_api_ref_pr:
Expand All @@ -26,17 +39,28 @@ jobs:
steps:
- name: Set version and branches
id: version_and_branches
env:
INPUT_VERSION: ${{ inputs.version }}
INPUT_BASE_BRANCH: ${{ inputs.base_branch }}
INPUT_WORK_BRANCH: ${{ inputs.work_branch }}
INPUT_USE_DEV_VERSION: ${{ inputs.use_dev_version }}
run: |
# Strip leading 'v' to get a plain version number (e.g. 5.0.9)
version="${{ inputs.version }}"
version="$INPUT_VERSION"
version="${version#v}"
base_branch="$(echo $version | sed 's/\(.*\..*\)\..*/\1/')"
work_branch="api_refs_v${version}"
base_branch="$INPUT_BASE_BRANCH"
if [ -z "$base_branch" ]; then
base_branch="$(echo "$version" | sed 's/\(.*\..*\)\..*/\1/')"
fi
work_branch="$INPUT_WORK_BRANCH"
if [ -z "$work_branch" ]; then
work_branch="api_refs_v${version}"
fi

if [[ "${{ inputs.use_dev_version }}" == "true" ]]; then
if [[ "$INPUT_USE_DEV_VERSION" == "true" ]]; then
# Dev build: install from the x-dev branch and label output with the target version
dxp_version="v${base_branch}.x-dev"
base_dxp_branch="${base_branch}"
base_dxp_branch="$(echo "$version" | sed 's/\(.*\..*\)\..*/\1/')"
dxp_version="v${base_dxp_branch}.x-dev"
virtual_dxp_version="${version}"
else
# Stable build: install from the released tag
Expand All @@ -57,6 +81,15 @@ jobs:
with:
ref: ${{ steps.version_and_branches.outputs.base_branch }}

- name: Check if work branch exists

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For performance optimization, it should be moved above the checkout. But the checkout step does more than just checkout. Among other things, it seems to set Git authentication.

When I moved it before the checkout, I had fatal: 'origin' does not appear to be a git repository error.

id: check_work_branch
if: inputs.force == false
run: |
if git ls-remote --exit-code --heads origin "${{ steps.version_and_branches.outputs.work_branch }}"; then
echo "::error title=Branch exists::The branch ${{ steps.version_and_branches.outputs.work_branch }} already exists. You can use the 'force' option to overwrite it."
exit 1
fi

- name: Disable PHP coverage
uses: shivammathur/setup-php@v2
with:
Expand Down
71 changes: 63 additions & 8 deletions tools/api_refs/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<!-- vale off -->

# PHP API Ref

## Install/Dependencies
Expand All @@ -6,16 +8,20 @@ Requires [`jq`](https://stedolan.github.io/jq/download/)

## Basic usage

`tools/api_refs/api_refs.sh` is a script generating PHP API Reference, by default, under `docs/api/php_api/php_api_reference/`.
`tools/api_refs/api_refs.sh` is a script generating PHP & REST API References, by default, under `docs/api/php_api/php_api_reference/` and `docs/api/rest_api/rest_api_reference/`.

- For Composer, if you do not use a global authentication to retrieve _Commerce_ edition, a path to an auth.json file can be given as first argument. For example:
- For Composer, if you do not use a global authentication to retrieve _Commerce_ edition, a path to an auth.json file can be given as first optional argument. For example:
```
tools/api_refs/api_refs.sh ~/www/ibexa-dxp-commerce/auth.json
```
- The second argument can be a path to an output directory to use instead of the default one. For example, using the Composer global authentication file as first argument and the path to directory (which is created if it doesn't exist yet):
- The second optional argument can be a path to an output directory to use instead of the default one. For example, using the Composer global authentication file as first argument and the path to directory (which is created if it doesn't exist yet):
```
tools/api_refs/api_refs.sh ~/.composer/auth.json ./docs/api/php_api/php_api_reference-TMP
```
- The next three optional arguments are the REST API files
- 3rd argument is the reference HTML file path
- 4th argument is the file path for the OpenAPI specification in YAML format
- 5th argument is the file path for the OpenAPI specification in JSON format

## Rebuild example

Expand All @@ -32,7 +38,7 @@ In `tools/api_refs/api_refs.sh`:

`PHPDOC_VERSION` should always target the last version of phpDocumentor.

`DXP_VERSION` should target the version of Ibexa DXP Commerce corresponding to the main doc's branch.
`DXP_VERSION` should target the version of Ibexa DXP Commerce corresponding to the doc's branch.

### Templates

Expand All @@ -51,17 +57,35 @@ For example, when working on the design, the set of parsed files can be reduced

`PHP_BINARY` can be edited, for example, to use a different PHP version than the default, to change verbosity, or to add `-d memory_limit=-1`.

```bash
PHP_BINARY="/opt/homebrew/opt/php@8.4/bin/php -d memory_limit=-1 -d error_reporting=`php -r 'echo E_ALL & ~E_DEPRECATED;'`";
```

`COMPOSER_BINARY` can be edited, for example, to add options to `composer`, or change the PHP used with it.

```bash
COMPOSER_BINARY="$PHP_BINARY $(which composer)";
```

`FORCE_DXP_INSTALL` can be changed to `0` (zero) to have a persistent `TMP_DXP_DIR`.
After a first run to create it, the Ibexa DXP won't be rebuilt by Composer by next runs.
Time is saved. The DXP's code could even be modified for test purpose.
`TMP_DXP_DIR` can be set to the path of a running installation.

```bash
PHP_BINARY='ddev php';
COMPOSER_BINARY='ddev composer';
TMP_DXP_DIR=~/my-ddev-project/;
FORCE_DXP_INSTALL=0;
```

If you change some of those values, please do not commit those changes, and don't commit their output.
To prevent that, you can make a local copy, and use this copy to generate in a temporary output directory:
```bash
cp tools/api_refs/api_refs.sh tools/api_refs/phpdoc.dev.sh
nano phpdoc.dev.sh # Edit and make your changes. For example, change PHPDOC_CONF to use phpdoc.dev.xml.
nano phpdoc.dev.xml # Edit and make your changes. For example, target only your package.
tools/api_refs/api_refs.sh ~/.composer/auth.json ./docs/api/php_api/php_api_reference-TMP
cp tools/api_refs/api_refs.sh tools/api_refs/api_refs.dev.sh
nano tools/api_refs/api_refs.dev.sh # Edit and make your changes. For example, change PHPDOC_CONF to use phpdoc.dev.xml.
nano tools/api_refs/phpdoc.dev.xml # Edit and make your changes. For example, target only your package.
tools/api_refs/api_refs.dev.sh ~/.composer/auth.json ./docs/api/php_api/php_api_reference-TMP
```

### Creating a build of dev version
Expand Down Expand Up @@ -100,3 +124,34 @@ if [ 0 -eq $DXP_ALREADY_EXISTS ]; then
composer require --no-interaction --ignore-platform-reqs --no-scripts ibexa/$MY_PACKAGE "$MY_BRANCH as $DXP_VERSION";
fi;
```

### Run as GitHub Action

#### By using `gh`

With [GitHub CLI `gh`](https://cli.github.com/), you can trigger a GitHub Action workflow to build the API References.

```bash
gh workflow run api_refs.yaml -f version=<tag> -f use_dev_version=<false|true> --ref <branch> -f base_branch=<branch> -f work_branch=<branch> -f force=<false|true>
```

`-f version=<tag>` to pass the Ibexa DXP version tag for which the API References are built.
`-f use_dev_version=<false|true>` to use the released version designed by the tag, or to use the development version (`v5.0.x-dev`) for an incoming tag.
`--ref <branch>` to use the `api_refs.yaml` workflow from a given branch instead of the default branch (`5.0`).
`-f base_branch=<branch>` to use the `api_refs.sh` from a given branch and make a PR to that branch.
`-f work_branch=<branch>` to use a given target branch to commit the build and make a PR from that branch.
`-f force=<false|true>` to force the commit on the target branch even if it already exists.

Examples:

Build from the dev branch `5.0.x-dev` API references for `v5.0.999`:

```bash
gh workflow run api_refs.yaml -f version=v5.0.999 -f use_dev_version=true
```

Rebuild references for the released version `v5.0.10` from `my-tools`'s `api_refs.yaml` with `my-tools`'s tools and commit the result into `my-api-refs` even if it already exists:

```bash
gh workflow run api_refs.yaml -f version=v5.0.10 --ref my-builder -f base_branch=my-builder -f work_branch=my-api-refs -f force=true
```
40 changes: 23 additions & 17 deletions tools/api_refs/api_refs.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
#!/usr/bin/env bash

set -x;
set +x;

AUTH_JSON=${1:-~/.composer/auth.json}; # Path to an auth.json file allowing to install the targeted edition and version
AUTH_JSON=$(realpath ${1:-~/.composer/auth.json}); # Path to an auth.json file allowing to install the targeted edition and version
PHP_API_OUTPUT_DIR=${2:-./docs/api/php_api/php_api_reference}; # Path to the directory where the built PHP API Reference is hosted
REST_API_OUTPUT_FILE=${3:-./docs/api/rest_api/rest_api_reference/rest_api_reference.html}; # Path to the REST API Reference file
REST_API_OPENAPI_FILE_YAML=${4:-./docs/api/rest_api/rest_api_reference/openapi.yaml}; # Path to the REST API OpenAPI spec file
Expand All @@ -24,6 +24,7 @@ REDOCLY_TEMPLATE="$(pwd)/tools/api_refs/redocly.hbs"; # Absolute path to Redocly
OPENAPI_FIX="$(pwd)/tools/api_refs/openapi.php"; # A script editing and fixing few things on the dumped schema (should be temporary and fixes reported to source)

PHP_BINARY="php -d error_reporting=`php -r 'echo E_ALL & ~E_DEPRECATED;'`"; # Avoid depreciation messages from phpDocumentor/Reflection/issues/529 when using PHP 8.2 or higher
COMPOSER_BINARY='composer';
TMP_DXP_DIR=/tmp/ibexa-dxp-phpdoc; # Absolute path of the temporary directory in which Ibexa DXP will be installed and the PHP API Reference built
FORCE_DXP_INSTALL=1; # If 1, empty the temporary directory, install DXP from scratch, build, remove temporary directory; if 0, potentially reuse the DXP already installed in temporary directory, keep temporary directory for future uses.
BASE_DXP_BRANCH="${BASE_DXP_BRANCH:-}"; # Branch from and for which the Reference is built when using a dev branch as version; can be overridden by the BASE_DXP_BRANCH env var
Expand Down Expand Up @@ -61,42 +62,47 @@ fi;
cd $TMP_DXP_DIR; # /!\ Change working directory (reason why all paths must be absolute)

if [ 0 -eq $DXP_ALREADY_EXISTS ]; then
if [ ! -f $AUTH_JSON ]; then
echo "Credentials file ${AUTH_JSON} doesn't exist.";
exit 3;
fi;

echo "Creating ibexa/$DXP_EDITION-skeleton:$DXP_VERSION project in ${TMP_DXP_DIR}…";
if [[ "$DXP_VERSION" == *".x-dev" ]]; then
composer create-project ibexa/website-skeleton:$DXP_VERSION . --no-interaction --ignore-platform-reqs --no-scripts --stability=dev;
COMPOSER_AUTH="$(tr -d '\n' < $AUTH_JSON)" $COMPOSER_BINARY create-project ibexa/website-skeleton:$DXP_VERSION . --no-interaction --ignore-platform-reqs --no-scripts --stability=dev;
if [ -n "$AUTH_JSON" ]; then
cp $AUTH_JSON ./;
fi;
composer config repositories.ibexa composer https://updates.ibexa.co;
composer config extra.symfony.endpoint "https://api.github.com/repos/ibexa/recipes-dev/contents/index.json?ref=flex/main";
composer require ibexa/$DXP_EDITION:$DXP_VERSION --no-interaction --update-with-all-dependencies --no-install --ignore-platform-reqs --no-scripts;
$COMPOSER_BINARY config repositories.ibexa composer https://updates.ibexa.co;
$COMPOSER_BINARY config extra.symfony.endpoint "https://api.github.com/repos/ibexa/recipes-dev/contents/index.json?ref=flex/main";
$COMPOSER_BINARY require ibexa/$DXP_EDITION:$DXP_VERSION --no-interaction --update-with-all-dependencies --no-install --ignore-platform-reqs --no-scripts;
elif [[ "$DXP_VERSION" == *"-rc"* ]]; then
composer create-project ibexa/website-skeleton:$DXP_VERSION . --no-interaction --ignore-platform-reqs --no-scripts --stability=rc;
COMPOSER_AUTH="$(tr -d '\n' < $AUTH_JSON)" $COMPOSER_BINARY create-project ibexa/website-skeleton:$DXP_VERSION . --no-interaction --ignore-platform-reqs --no-scripts --stability=rc;
if [ -n "$AUTH_JSON" ]; then
cp $AUTH_JSON ./;
fi;
composer config repositories.ibexa composer https://updates.ibexa.co;
composer require ibexa/$DXP_EDITION:$DXP_VERSION --no-interaction --update-with-all-dependencies --no-install --ignore-platform-reqs --no-scripts;
$COMPOSER_BINARY config repositories.ibexa composer https://updates.ibexa.co;
$COMPOSER_BINARY require ibexa/$DXP_EDITION:$DXP_VERSION --no-interaction --update-with-all-dependencies --no-install --ignore-platform-reqs --no-scripts;
else
composer create-project ibexa/$DXP_EDITION-skeleton:$DXP_VERSION . --no-interaction --no-install --ignore-platform-reqs --no-scripts;
COMPOSER_AUTH="$(tr -d '\n' < $AUTH_JSON)" $COMPOSER_BINARY create-project ibexa/$DXP_EDITION-skeleton:$DXP_VERSION . --no-interaction --no-install --ignore-platform-reqs --no-scripts;
if [ -n "$AUTH_JSON" ]; then
cp $AUTH_JSON ./;
fi;
fi;
composer install --no-interaction --ignore-platform-reqs --no-scripts;
$COMPOSER_BINARY install --no-interaction --ignore-platform-reqs --no-scripts;
fi;

if [[ "$DXP_VERSION" == *".*"* ]]; then
export COMPOSER_ROOT_VERSION=0.0.0;
DXP_VERSION=$(composer -n show ibexa/$DXP_EDITION | grep -E "^version" | cut -d 'v' -f 3);
DXP_VERSION=$($COMPOSER_BINARY -n show ibexa/$DXP_EDITION | grep -E "^version" | cut -d 'v' -f 3);
echo "Obtained version: $DXP_VERSION";
fi;

export COMPOSER_ROOT_VERSION=$DXP_VERSION;

if [ 0 -eq $DXP_ALREADY_EXISTS ]; then
for additional_package in "${DXP_ADD_ONS[@]}"; do
composer require --no-interaction --ignore-platform-reqs --no-scripts --with-all-dependencies ibexa/$additional_package:$DXP_VERSION;
$COMPOSER_BINARY require --no-interaction --ignore-platform-reqs --no-scripts --with-all-dependencies ibexa/$additional_package:$DXP_VERSION;
done;
fi;

Expand All @@ -118,7 +124,7 @@ if [ 0 -eq $DXP_ALREADY_EXISTS ]; then
package=$(echo $line | cut -d '"' -f 2);
if [[ ! "${DXP_EDITIONS[*]}" =~ "${package/ibexa\//}" ]]; then
PACKAGE_MAP="$PACKAGE_MAP\n'$package': '$edition',"
NAMESPACES=$(composer show "$package" --available --format=json | \
NAMESPACES=$($COMPOSER_BINARY show "$package" --available --format=json | \
jq -r --arg PACKAGE "$package" '"'\''\(.autoload | ."psr-4" | try to_entries[] catch empty | .key[:-1] | sub("\\\\";"\\\\\\";"g"))'\'': '\''\($PACKAGE)'\'',"')
NAMESPACE_MAP="$NAMESPACE_MAP\n$NAMESPACES"
fi;
Expand All @@ -131,7 +137,7 @@ if [ 0 -eq $DXP_ALREADY_EXISTS ]; then

echo -n 'Building namespace→edition map… ';
for package in "${DXP_ADD_ONS[@]}"; do
NAMESPACES=$(composer show "ibexa/$package" --available --format=json | \
NAMESPACES=$($COMPOSER_BINARY show "ibexa/$package" --available --format=json | \
jq -r --arg PACKAGE "ibexa/$package" '"'\''\(.autoload | ."psr-4" | try to_entries[] catch empty | .key[:-1] | sub("\\\\";"\\\\\\";"g"))'\'': '\''\($PACKAGE)'\'',"')
NAMESPACE_MAP="$NAMESPACE_MAP\n$NAMESPACES"
PACKAGE_MAP="$PACKAGE_MAP\n'ibexa/$package': 'optional',"
Expand Down Expand Up @@ -217,8 +223,8 @@ fi;

if [ 0 -eq $DXP_ALREADY_EXISTS ]; then
echo 'Set up DXP recipes…';
git init && git add . && git commit -m "Installed Ibexa Commerce" > /dev/null;
composer recipes:install ibexa/$DXP_EDITION --force --reset --no-interaction;
git init -b main && git add . && git commit -m "Installed Ibexa Commerce" > /dev/null;
$COMPOSER_BINARY recipes:install ibexa/$DXP_EDITION --force --reset --no-interaction;
fi;

echo 'Dump REST OpenAPI schema… ';
Expand Down
Loading