diff --git a/.github/workflows/api_refs.yaml b/.github/workflows/api_refs.yaml index 6d216c7d10..cc51f8b54a 100644 --- a/.github/workflows/api_refs.yaml +++ b/.github/workflows/api_refs.yaml @@ -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_)' + 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: @@ -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 @@ -57,6 +81,15 @@ jobs: with: ref: ${{ steps.version_and_branches.outputs.base_branch }} + - name: Check if work branch exists + 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: diff --git a/tools/api_refs/README.md b/tools/api_refs/README.md index 12c61dbdf9..a04d5142cb 100644 --- a/tools/api_refs/README.md +++ b/tools/api_refs/README.md @@ -1,3 +1,5 @@ + + # PHP API Ref ## Install/Dependencies @@ -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 @@ -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 @@ -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 @@ -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= -f use_dev_version= --ref -f base_branch= -f work_branch= -f force= +``` + +`-f version=` to pass the Ibexa DXP version tag for which the API References are built. +`-f use_dev_version=` to use the released version designed by the tag, or to use the development version (`v5.0.x-dev`) for an incoming tag. +`--ref ` to use the `api_refs.yaml` workflow from a given branch instead of the default branch (`5.0`). +`-f base_branch=` to use the `api_refs.sh` from a given branch and make a PR to that branch. +`-f work_branch=` to use a given target branch to commit the build and make a PR from that branch. +`-f force=` 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 +``` diff --git a/tools/api_refs/api_refs.sh b/tools/api_refs/api_refs.sh index f152149606..26efb47fe2 100755 --- a/tools/api_refs/api_refs.sh +++ b/tools/api_refs/api_refs.sh @@ -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 @@ -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 @@ -61,34 +62,39 @@ 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; @@ -96,7 +102,7 @@ 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; @@ -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; @@ -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'," @@ -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… ';