{"id":15046196,"url":"https://github.com/laminas/laminas-continuous-integration-action","last_synced_at":"2025-04-04T08:08:16.381Z","repository":{"id":37928936,"uuid":"336055313","full_name":"laminas/laminas-continuous-integration-action","owner":"laminas","description":"GitHub Action for running a QA check","archived":false,"fork":false,"pushed_at":"2025-03-11T13:06:52.000Z","size":614,"stargazers_count":19,"open_issues_count":14,"forks_count":19,"subscribers_count":14,"default_branch":"1.42.x","last_synced_at":"2025-03-28T07:08:02.582Z","etag":null,"topics":["ci","continuous-integration","github-actions"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/laminas.png","metadata":{"funding":{"community_bridge":"laminas-project"},"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-04T19:04:59.000Z","updated_at":"2025-03-11T13:06:47.000Z","dependencies_parsed_at":"2023-10-01T16:58:09.125Z","dependency_job_id":"7481fb03-8104-4d2d-8c3a-606b5bd6779b","html_url":"https://github.com/laminas/laminas-continuous-integration-action","commit_stats":{"total_commits":270,"total_committers":18,"mean_commits":15.0,"dds":0.6407407407407407,"last_synced_commit":"e28337c2d5951671a899a6dda52b551aada6aabe"},"previous_names":[],"tags_count":112,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laminas%2Flaminas-continuous-integration-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laminas%2Flaminas-continuous-integration-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laminas%2Flaminas-continuous-integration-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/laminas%2Flaminas-continuous-integration-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/laminas","download_url":"https://codeload.github.com/laminas/laminas-continuous-integration-action/tar.gz/refs/heads/1.42.x","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247142066,"owners_count":20890652,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ci","continuous-integration","github-actions"],"created_at":"2024-09-24T20:52:50.247Z","updated_at":"2025-04-04T08:08:16.359Z","avatar_url":"https://github.com/laminas.png","language":"Shell","funding_links":["https://funding.communitybridge.org/projects/laminas-project"],"categories":[],"sub_categories":[],"readme":"# Laminas Continuous Integration GitHub Action\n\n\u003e ## 🇷🇺 Русским гражданам\n\u003e \n\u003e Мы, участники Laminas, родились и живем в разных странах. У многих из нас есть друзья, родственники и коллеги как в России, так и в Украине. Некоторые из нас родились в России. Некоторые из нас живут в России. У некоторых бабушки и дедушки сражались с фашистами во Второй мировой войне. Здесь никто не поддерживает фашизм.\n\u003e \n\u003e У одного из нас есть украинская родственница, которая спаслась из дома вместе с сыном. Поезд задержался из-за бомбежки на дороге впереди. У нас есть друзья, которые прячутся в бомбоубежищах. Мы с тревогой ждем весточки от них после воздушных налетов, которые беспорядочно наносят удары и попадают по больницам, школам, детским садам и домам. Мы не берем это из каких-либо СМИ. Мы наблюдаем это напрямую.\n\u003e \n\u003e Вы доверяете нам достаточно, чтоб использовать наши программы, и мы просим вас довериться нам вновь. Мы нуждаемся в помощи. Выходите и протестуйте против этой бесполезной войны. Остановите кровопролитие. Скажите \"Нет войне!\"\n\u003e \n\u003e ## 🇺🇸 To Citizens of Russia\n\u003e \n\u003e We at Laminas come from all over the world. Many of us have friends, family and colleagues in both Russia and Ukraine. Some of us were born in Russia. Some of us currently live in Russia. Some have grandparents who fought Nazis in World War II. Nobody here supports fascism.\n\u003e \n\u003e One team member has a Ukrainian relative who fled her home with her son. The train was delayed due to bombing on the road ahead. We have friends who are hiding in bomb shelters. We anxiously follow up on them after the air raids, which indiscriminately fire at hospitals, schools, kindergartens and houses. We're not taking this from any media. These are our actual experiences.\n\u003e \n\u003e You trust us enough to use our software. We ask that you trust us to say the truth on this. We need your help. Go out and protest this unnecessary war. Stop the bloodshed. Say \"stop the war!\"\n\nThis repository represents a GitHub Action that runs a single PHP QA job, using the [laminas/laminas-continuous-integration image](https://ghcr.io/laminas/laminas-continuous-integration).\n\nA job is presented as an argument to the container, and will be a JSON string representing the job to run.\n\n\u003e **NOTE** that it is a JSON string representation, and not an actual JSON object.\n\nThe JSON string should represent an object with the following information:\n\n```json\n{\n  \"php\": \"string PHP minor version to run against\",\n  \"extensions\": [\n    \"extension names to install; names are from the ondrej PHP repository, minus the php{VERSION}- prefix\"\n  ],\n  \"ini\": [\n    \"php.ini directives, one per element; e.g. 'memory_limit=-1'\"\n  ],\n  \"dependencies\": \"dependencies to test against; one of lowest, locked, latest\",\n  \"ignore_platform_reqs_on_8\": \"(boolean; OPTIONAL; DEPRECATED) Whether or not to ignore platform requirements on PHP 8; defaults to true\",\n  \"ignore_php_platform_requirement\": \"(boolean; OPTIONAL) Whether or not to ignore PHP platform requirement; defaults to false\",\n  \"command\": \"command to run to perform the check (empty in case you dont want to excecute any command)\",\n  \"additional_composer_arguments\": [\n    \"arguments which will be passed to `composer install` or `composer update`, passed as a list or as a list; e.g. --no-scripts\"\n  ],\n  \"before_script\": [\n    \"tool configuration linting\",\n    \"tool specific setting overrides\",\n    \"specific composer dependency to be installed prior executing command\"\n  ],\n  \"after_script\": [\n    \"post process tool result\"\n  ]\n}\n```\n\nThe PHP version and command are required; all other elements are optional.\n\nIt will then execute the job, and the exit status will determine job failure or success.\n\nGenerally speaking, you will use this in combination with the [laminas/laminas-ci-matrix-action](https://github.com/laminas/laminas-ci-matrix-action), which will build a matrix of jobs for you based on configuration files already present in your package.\n\n## Usage\n\nCreate `.github/workflows/continuous-integration.yml` file with following content:\n\n```yaml\nname: \"Continuous Integration\"\n\non:\n  pull_request:\n  push:\n    branches:\n\njobs:\n  matrix:\n    name: Generate job matrix\n    runs-on: ubuntu-latest\n    outputs:\n      matrix: ${{ steps.matrix.outputs.matrix }}\n    steps:\n      - name: Gather CI configuration\n        id: matrix\n        uses: laminas/laminas-ci-matrix-action@v1\n  qa:\n    name: QA Checks\n    needs: [matrix]\n    runs-on: ${{ matrix.operatingSystem }}\n    strategy:\n      fail-fast: false\n      matrix: ${{ fromJSON(needs.matrix.outputs.matrix) }}\n    steps:\n      - name: ${{ matrix.name }}\n        uses: laminas/laminas-continuous-integration-action@v1\n        env:\n          \"GITHUB_TOKEN\": ${{ secrets.GITHUB_TOKEN }}\n        with:\n          job: ${{ matrix.job }}\n```\n\nThe same can be achieved with our reusable workflow:\n\n```yaml\nname: \"Continuous Integration\"\n\non:\n  pull_request:\n  push:\n    branches:\n\njobs:\n  ci:\n    uses: laminas/workflow-continuous-integration/.github/workflows/continuous-integration.yml@1.x\n```\n\n\u003e ### Duplicate CI runs\n\u003e\n\u003e When pull requests are opened from branches in the same repository, the CI pipeline could run twice for the same commit: once when pushed to a branch and once when the PR is opened.\n\u003e Workflow triggers can be adjusted to only run for specific branches or to skip branches using simple glob patterns.\n\u003e See the GitHub documentation for [Events that trigger workflows](https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#running-your-workflow-only-when-a-push-to-specific-branches-occurs) for more info.\n\n\u003e ### actions/checkout not required\n\u003e\n\u003e The action will perform a checkout of the repository at the requested reference as part of its work, and therefore does not require the actions/checkout action as a preceding step.\n\n\u003e ### GITHUB_TOKEN not required\n\u003e\n\u003e While injection of the `GITHUB_TOKEN` env variable is demonstrated above, in most cases it is not necessary.\n\u003e Only add it if you start seeing rate limit issues when using Composer (e.g., when you receive a \"Could not authenticate against github.com\" message when installing dependencies).\n\n### Pre/Post commands\n\nSome packages may require additional setup steps: setting up a web server to test an HTTP client, seeding a database or cache service, etc.\nOther times, you may want to do additional reporting, particularly if the QA command failed.\n\nTo enable this, you may create one or more of the following files in your package:\n\n- `.laminas-ci/pre-install.sh`\n- `.laminas-ci/pre-run.sh`\n- `.laminas-ci/post-run.sh`\n\n(Note: the files MUST be executable to be consumed!)\n\nThe `.laminas-ci/pre-install.sh` command runs before any other command is executed in the action, and will receive the following arguments:\n\n- `$1`: the user the QA command will run under\n- `$2`: the WORKDIR path\n- `$3`: the `$JOB` passed to the entrypoint (see above)\n- `$4`: the `$PHP` (\u003cmajor\u003e.\u003cminor\u003e) configured for execution\n\nThe `.laminas-ci/pre-run.sh` command runs immediately prior to the QA command, and will receive the following arguments:\n\n- `$1`: the user the QA command will run under\n- `$2`: the WORKDIR path\n- `$3`: the `$JOB` passed to the entrypoint (see above)\n- `$4`: the `$PHP` (\u003cmajor\u003e.\u003cminor\u003e) configured for execution\n\nIt is also possible to pass `before_script` with a list of commands via the `$JOB` variable.\n\nThe `.laminas-ci/post-run.sh` command will receive these arguments:\n\n- `$1`: the exit status of the QA command\n- `$2`: the user the QA command will run under\n- `$3`: the WORKDIR path\n- `$4`: the `$JOB` passed to the entrypoint (see above)\n- `$5`: the `$PHP` (\u003cmajor\u003e.\u003cminor\u003e) configured for execution\n\nIt is also possible to pass `after_script` with a list of commands via the `$JOB` variable. \n`$STATUS` is a variable containing the exit code of the command and can be used in the commands listed in `after_script`. \n\n#### Parsing the $JOB\n\nYou may want to grab elements of the `$JOB` argument in order to branch logic.\nGenerally speaking, you can use the [jq](https://stedolan.github.io/jq/) command to get at this data.\nAs an example, to get the PHP version:\n\n```bash\nJOB=$3\nPHP_VERSION=$(echo \"${JOB}\" | jq -r '.php')\n```\n\nIf you want to conditionally skip setup based on the command (in this case, exiting early if the command to run is not phpunit):\n\n```bash\nJOB=$3\nCOMMAND=$(echo \"${JOB}\" | jq -r '.command')\nif [[ ! ${COMMAND} =~ phpunit ]];then\n    exit 0\nfi\n```\n\nPerhaps after running a job against locked dependencies, you want to see if newer versions are available:\n\n```bash\nJOB=$3\nDEPS=$(echo \"${JOB}\" | jq -r '.dependencies')\nif [[ \"${DEPS}\" != \"locked\" ]];then\n    exit 0\nfi\n# check for newer versions...\n```\n\nIf you need access to the list of extensions or php.ini directives, you should likely write a script in PHP or node to do so.\n\n#### Using PECL\n\nOne key reason to use a `.laminas-ci/pre-install.sh` script is to install an extension via PECL.\nYou may need to do this if no corresponding package exists for an extension you need, or if you need to test against a different version than is in the Sury repository.\n\nAn example of such a script:\n\n```bash\n#!/bin/bsh\n# .laminas-ci/pre-install.sh\n\npecl install couchbase-2.6.2\n```\n\n### Using locally\n\nThe [standard Laminas Continuous Integration workflow](https://gist.github.com/weierophinney/9decd19f76b7d9745c6559074053fa65) defines one job using the laminas/laminas-ci-matrix-action to create the matrix, and defines another job to run the various jobs in the matrix that consumes it.\nUnfortunately, as of this writing, tools like [nektos/act](https://github.com/nektos/act) are unable to work with job/step dependencies, nor with workflow metadata expressions, meaning you cannot run the full suite at once.\n\nWhat you _can_ do, however, is run individual jobs via the [laminas/laminas-continuous-integration container](https://ghcr.io/laminas/laminas-continuous-integration).\n\nIt defines an entrypoint that accepts a single argument, a JSON string. The JSON string should contain the following elements:\n\n- command: (string; required) the command to run (e.g., `./vendor/bin/phpunit`)\n- php: (string; required) the PHP version to use when running the check\n- extensions: (array of strings; optional) additional extensions to install.\n  The names used should correspond to package names from the Sury repository, minus the `php{version}-` prefix.\n  As examples, \"sqlite3\" or \"tidy\".\n- ini: (array of strings; optional) php.ini directives to use.\n  Each item should be the full directive; e.g., `memory_limit=-1` or `date.timezone=America/New_York`.\n- dependencies: (string; optional) the dependency set to run against: lowest, locked, or latest.\n  If not provided, \"locked\" is used.\n\nTo run a test locally, first, pull the container:\n\n```bash\n$ docker pull ghcr.io/laminas/laminas-continuous-integration:1\n```\n\nOnce you have pulled it, you can run individual jobs.\nThe tricks to remember are:\n\n- You need to set bind the package directory as a volume.\n- You need to set the container WORKDIR to that volume.\n- You need to provide the job JSON.\n\nAs an example, if you wanted to run the CS checks under PHP 7.4 using locked dependencies, you could do something like the following:\n\n```bash\n$ docker run -v $(realpath .):/github/workspace -w=/github/workspace ghcr.io/laminas/laminas-continuous-integration:1  '{\"php\":\"7.4\",\"dependencies\":\"locked\",\"extensions\":[],\"ini\":[\"memory_limit=-1\"],\"command\":\"./vendor/bin/phpcs\"}'\n```\n\nThe trick to remember: the job JSON should generally be in single quotes, to allow the `\"` characters used to delimit properties and strings in the JSON to not cause interpolation issues.\n\n## PHP versions, extensions, and tools available\n\nThe container the action provides and consumes builds off the ubuntu:focal image, installs the [Sury PHP repository](https://deb.sury.org/), and installs PHP versions:\n\n- 5.6\n- 7.0\n- 7.1\n- 7.2\n- 7.3\n- 7.4\n- 8.0\n- 8.1\n- 8.2\n- 8.3\n- 8.4\n\nEach provides the following extensions by default:\n\n- bz2\n- curl\n- fileinfo\n- intl\n- json\n- mbstring\n- phar\n- readline\n- sockets\n- xml\n- xsl\n- zip\n\nYou may specify other extensions to install during a job by selecting them from the list of packages in the Sury repository, and dropping the `php{VERSION}` prefix; e.g., the package \"php7.4-tidy\" provides the \"tidy\" extension, so you would only specify \"tidy\" if you want to include that extension for your build.\n\nWe also provide the following extensions:\n\n- sqlsrv (version 5.9.0)\n- pdo_sqlsrv (version 5.9.0)\n\nOther extensions may be installed using pecl, or directly retrieving the extension package, and doing the `phpize`/`configure`/`make` dance; this can be done in a [pre-run command script](#pre-post-commands).\n\n### Other tools available\n\nThe container provides the following tools:\n\n- Composer (v2 release)\n\n- [cs2pr](https://github.com/staabm/annotate-pull-request-from-checkstyle), which creates PR annotations from checkstyle output. If a tool you are using, such as `phpcs`, provides checkstyle output, you can pipe it to `cs2pr` to create PR annotations from errors/warnings/etc. raised.\n\n- [roave-backward-compatibility-check](https://github.com/Roave/BackwardCompatibilityCheck), which checks the code for BC breakages and creates PR annotations in case something will break the exposed API.\n\n- A `markdownlint` binary, via the [DavidAnson/markdownlint-cli2](https://github.com/DavidAnson/markdownlint-cli2) package.\n  A default configuration is provided that disables the following rules:\n\n  - MD013 (line-length)\n  - MD014 (dollar signs used before commands without showing output)\n  - MD024 (duplicate header)\n  - MD028 (blank line inside block quote)\n  - MD034 (bare URLs)\n\n  Consumers can provide their own rules via a [.markdownlint.json](https://github.com/DavidAnson/markdownlint-cli2#markdownlintjsonc-or-markdownlintjson) file.\n\n- A `xmllint` binary, via the [libxml2-utils](https://packages.debian.org/stretch/libxml2-utils) package.\n\n- A `yamllint` binary, via the [adrienverge/yamllint](https://github.com/adrienverge/yamllint) package.\n\n- The [jq](https://stedolan.github.io/jq/) command, a CLI JSON processor.\n\n## Notes on contributing\n\nThis package includes a workflow that will build the container during pull request, to verify that builds complete successfully.\n\nThe workflow has three different conditional build steps:\n\n- One that happens only on release; this is irrelevant to pull requests.\n- Two that happen for pull requests:\n  - One that triggers if the repository's `CONTAINER_USERNAME` (and, by extension, `CONTAINER_PAT`) secret is present.\n  - One that triggers if the repository's `CONTAINER_USERNAME` (and, by extension, `CONTAINER_PAT`) secret is NOT present.\n\nIn the case where the repository secrets are present, the build will also cache layers it has built, which will speed up later builds.\nHowever, because repository secrets are not provided when a pull request is performed from a forked repository, the second case will kick in; in that scenario, the build will still run, but no layers will be pushed to the container registry.\n\nAs such, if you are a Laminas Technical Steering Committee member or a maintainer with write access to this repository, please submit your patches via branches pushed directly to the repository, as this will speed up builds for everyone.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaminas%2Flaminas-continuous-integration-action","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flaminas%2Flaminas-continuous-integration-action","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flaminas%2Flaminas-continuous-integration-action/lists"}