From cf5cb1d0b53e13a3baf8d323685787646abe4bc1 Mon Sep 17 00:00:00 2001 From: Florent Sorel Date: Wed, 30 Sep 2026 13:04:00 +0200 Subject: [PATCH 1/4] chore(ci): publish the image to ghcr.io, and drop the unused action wrapper The PHP-CS-Fixer check of mobsuccess fails with "toomanyrequests: Data limit exceeded": its 34 MB image is pulled anonymously from ECR Public, which caps those pulls on the IPs GitHub runners share. The image was also pushed by hand, from no workflow. docker.yml builds the image on a pull request that touches it, and publishes it to ghcr.io on master when the Dockerfile or entrypoint.sh change, tagged with the PHP-CS-Fixer version (v3.13.0) so a workflow keeps the rules it formats with. The Dockerfile pins php:8.1.34-alpine and checks the SHA-256 of the phar, the one the current image holds. The build context is reduced to entrypoint.sh, the package being public. action.yml and examples/ go: inherited from the upstream fork, they point at oskarstark/php-cs-fixer-ga:2.18.2, another image with older rules, and no workflow of the organization uses this repository as an action. Co-Authored-By: Claude Opus 5.5 --- .dockerignore | 4 +- .github/workflows/docker.yml | 67 +++++++++++++++++++++++++++++ Dockerfile | 17 ++++---- README.md | 61 ++++++++++++-------------- action.yml | 15 ------- compose.yml | 4 ++ docker-compose.yml | 7 --- examples/.github/workflows/push.yml | 12 ------ 8 files changed, 109 insertions(+), 78 deletions(-) create mode 100644 .github/workflows/docker.yml delete mode 100644 action.yml create mode 100644 compose.yml delete mode 100644 docker-compose.yml delete mode 100644 examples/.github/workflows/push.yml diff --git a/.dockerignore b/.dockerignore index b9de7ba..864179f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,2 @@ -README.md -examples +* +!entrypoint.sh diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml new file mode 100644 index 0000000..86997ba --- /dev/null +++ b/.github/workflows/docker.yml @@ -0,0 +1,67 @@ +name: Docker + +on: + pull_request: + types: [opened, synchronize, reopened] + paths: + - "Dockerfile" + - "entrypoint.sh" + - ".github/workflows/docker.yml" + push: + branches: [master] + paths: + - "Dockerfile" + - "entrypoint.sh" + - ".github/workflows/docker.yml" + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build: + name: Build Docker image + runs-on: ubuntu-latest + timeout-minutes: 15 + permissions: + contents: read + packages: write + steps: + - name: Checkout + uses: actions/checkout@v7 + + - name: PHP-CS-Fixer version + id: version + run: echo "version=$(sed -n 's/^ARG PHP_CS_FIXER_VERSION=//p' Dockerfile)" >> "$GITHUB_OUTPUT" + + - name: Log in to Container Registry + if: github.ref == 'refs/heads/master' && github.event_name != 'pull_request' + uses: docker/login-action@v4 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Docker metadata + id: meta + uses: docker/metadata-action@v6 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=raw,value=v${{ steps.version.outputs.version }},enable={{is_default_branch}} + type=sha,format=long + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Build and push + uses: docker/build-push-action@v7 + with: + context: . + platforms: linux/amd64 + push: ${{ github.ref == 'refs/heads/master' && github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha + cache-to: type=gha,mode=max diff --git a/Dockerfile b/Dockerfile index 8db475c..f343dd0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,12 @@ -FROM --platform=linux/amd64 php:8.1-alpine +FROM php:8.1.34-alpine -LABEL "com.github.actions.name"="PHP-CS-Fixer" -LABEL "com.github.actions.description"="check php files" -LABEL "com.github.actions.icon"="check" -LABEL "com.github.actions.color"="blue" +ARG PHP_CS_FIXER_VERSION=3.13.0 +ARG PHP_CS_FIXER_SHA256=ac2e57e32cdae67f21baa88f78405f93d4d6e928f41ba62dc91505565c785a44 -RUN wget https://github.com/FriendsOfPHP/PHP-CS-Fixer/releases/download/v3.13.0/php-cs-fixer.phar -O php-cs-fixer \ - && chmod a+x php-cs-fixer \ - && mv php-cs-fixer /usr/local/bin/php-cs-fixer +ADD --checksum=sha256:${PHP_CS_FIXER_SHA256} --chmod=755 \ + https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases/download/v${PHP_CS_FIXER_VERSION}/php-cs-fixer.phar \ + /usr/local/bin/php-cs-fixer + +COPY entrypoint.sh /entrypoint.sh -ADD entrypoint.sh /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] diff --git a/README.md b/README.md index 8901ef4..7505db2 100644 --- a/README.md +++ b/README.md @@ -1,51 +1,46 @@ -# GithubAction for PHP-CS-Fixer +# github-actions-php-cs-fixer -## Usage +A Docker image that runs [PHP-CS-Fixer](https://github.com/PHP-CS-Fixer/PHP-CS-Fixer) +in a GitHub Actions workflow. Its arguments are passed to `php-cs-fixer fix`. -You can use it as a Github Action like this: +## Usage -_.github/workflows/lint.yml_ ```yaml -on: [push, pull_request] -name: Main jobs: php-cs-fixer: name: PHP-CS-Fixer runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: PHP-CS-Fixer - uses: docker://oskarstark/php-cs-fixer-ga + - uses: actions/checkout@v7 + - name: PHP-CS-Fixer + uses: docker://ghcr.io/mobsuccess-devops/github-actions-php-cs-fixer:v3.13.0 + with: + args: --config=.php-cs-fixer.dist.php --diff --dry-run . ``` -_to use a custom config for example, --diff and --dry-run option:_ -```diff -on: [push, pull_request] -name: Main -jobs: - php-cs-fixer: - name: PHP-CS-Fixer - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: PHP-CS-Fixer - uses: docker://oskarstark/php-cs-fixer-ga -+ with: -+ args: --config=.project.php_cs --diff --dry-run -``` +The tag is the PHP-CS-Fixer version. Keep it in the workflow: another version +has other rules, and would reformat the code it checks. -**You can copy/paste the .github folder (under examples/) to your project and thats all!** +Locally, from the repository to check: -## Docker +```bash +docker run --rm -v "$PWD:/app" -w /app ghcr.io/mobsuccess-devops/github-actions-php-cs-fixer:v3.13.0 --diff --dry-run . +``` -A Docker-Image is built automatically and located here: -https://hub.docker.com/r/oskarstark/php-cs-fixer-ga +## Image -You can run it in any given directory like this: +A push to `master` that changes the `Dockerfile` or `entrypoint.sh` publishes +the image to `ghcr.io/mobsuccess-devops/github-actions-php-cs-fixer` +(`.github/workflows/docker.yml`), tagged with the PHP-CS-Fixer version. The +`Docker` workflow can also be run by hand. -`docker run --rm -it -w=/app -v ${PWD}:/app oskarstark/php-cs-fixer-ga:latest` +Workflows pull it without credentials, so the package has to be public: keep +secrets out of the image. A package is private when first published; someone +with admin rights on it makes it public once (Package settings → Danger Zone → +Change visibility), which cannot be undone. -## A picture is worth a thousand words +To move to another PHP-CS-Fixer version, change `PHP_CS_FIXER_VERSION` and +`PHP_CS_FIXER_SHA256` in the `Dockerfile` (the SHA-256 of the released +`php-cs-fixer.phar`), and the tag in `compose.yml` and in this file. -You can find a working and not working PR here: -https://github.com/OskarStark/test-php-cs-fixer-ga/pulls +To build the image locally: `docker compose build`. diff --git a/action.yml b/action.yml deleted file mode 100644 index 193b3cc..0000000 --- a/action.yml +++ /dev/null @@ -1,15 +0,0 @@ -# https://help.github.com/en/articles/metadata-syntax-for-github-actions - -author: 'OskarStark' - -branding: - icon: 'check' - color: 'blue' - -description: 'Use PHP-CS-Fixer via GithubAction.' - -name: 'OSKAR-PHP-CS-Fixer' - -runs: - using: 'docker' - image: 'docker://oskarstark/php-cs-fixer-ga:2.18.2' diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..aa56762 --- /dev/null +++ b/compose.yml @@ -0,0 +1,4 @@ +services: + php-cs-fixer: + build: . + image: ghcr.io/mobsuccess-devops/github-actions-php-cs-fixer:v3.13.0 diff --git a/docker-compose.yml b/docker-compose.yml deleted file mode 100644 index 3550493..0000000 --- a/docker-compose.yml +++ /dev/null @@ -1,7 +0,0 @@ -version: '3.8' - -services: - php-cs-fixer: - build: . - image: public.ecr.aws/u9q7y3l4/github-actions-php-cs-fixer:v3.13.0 - diff --git a/examples/.github/workflows/push.yml b/examples/.github/workflows/push.yml deleted file mode 100644 index 9a3796e..0000000 --- a/examples/.github/workflows/push.yml +++ /dev/null @@ -1,12 +0,0 @@ -on: [push, pull_request] -name: Lint -jobs: - php-cs-fixer: - name: PHP-CS-Fixer - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@master - - name: PHP-CS-Fixer - uses: docker://oskarstark/php-cs-fixer-ga - with: - args: --diff --dry-run From f171a909d64b890ef7d76c9c475af84d315db62c Mon Sep 17 00:00:00 2001 From: Florent Sorel Date: Wed, 30 Sep 2026 13:38:00 +0200 Subject: [PATCH 2/4] chore(ci): remove the Asana workflow It calls mobsuccess-devops/github-actions-asana, which is archived, and the policy no longer has an asana entry, so ms-bot will not bring it back. The check is not required on master. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/asana.yml | 39 ------------------------------------- 1 file changed, 39 deletions(-) delete mode 100644 .github/workflows/asana.yml diff --git a/.github/workflows/asana.yml b/.github/workflows/asana.yml deleted file mode 100644 index 145bcbe..0000000 --- a/.github/workflows/asana.yml +++ /dev/null @@ -1,39 +0,0 @@ -# DO NOT EDIT: BEGIN -# This snippet has been inserted automatically by mobsuccessbot, do not edit! -# If changes are needed, update the action asana in -# https://github.com/mobsuccess-devops/github-mobsuccess-policy -name: Asana - -on: - pull_request: - types: - - assigned - - unassigned - - review_requested - - review_request_removed - - opened - - synchronize - - closed - - edited - - converted_to_draft - - ready_for_review - - pull_request_review: - types: - - submitted - - edited - - dismissed - -jobs: - Asana: - runs-on: ubuntu-latest - timeout-minutes: 3 - steps: - - uses: mobsuccess-devops/github-actions-asana@master - with: - asana-pat: ${{ secrets.ASANA_PAT }} - github-token: ${{ github.token }} - action: "synchronize" - amplify-uri: ${{ secrets.AWS_AMPLIFY_URI }} - storybook-amplify-uri: ${{ secrets.AWS_STORYBOOK_AMPLIFY_URI }} -# DO NOT EDIT: END From 01ddc89e8148db02bcbd65a75b1963663054e4fb Mon Sep 17 00:00:00 2001 From: Florent Sorel Date: Wed, 30 Sep 2026 13:38:55 +0200 Subject: [PATCH 3/4] chore(gha): update mobsuccess.yml and closed.yml to the policy's current versions Both still asked for ubuntu-20.04, a runner image GitHub has retired: the Mobsuccess PR Compliance job stayed queued forever. These are the files ms-bot writes today (the policy's sources with its header), byte for byte the ones in github-actions-kuberneteslint. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/closed.yml | 6 +- .github/workflows/mobsuccess.yml | 103 ++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 6 deletions(-) diff --git a/.github/workflows/closed.yml b/.github/workflows/closed.yml index d2883a6..5b4089a 100644 --- a/.github/workflows/closed.yml +++ b/.github/workflows/closed.yml @@ -12,7 +12,7 @@ jobs: ZapierReviewRequestedPurpleHeart: if: github.event.pull_request.merged == true name: "Zapier Purple Heart" - runs-on: ubuntu-20.04 + runs-on: ubuntu-slim timeout-minutes: 1 steps: - name: "Sync emoji in #mobsuccess-review-requested" @@ -21,7 +21,7 @@ jobs: ZapierReviewRequestedRedCross: if: github.event.pull_request.merged == false name: "Zapier Red Cross" - runs-on: ubuntu-20.04 + runs-on: ubuntu-slim timeout-minutes: 1 steps: - name: "Sync emoji in #mobsuccess-review-requested" @@ -30,7 +30,7 @@ jobs: CommentSubPRs: if: github.event.pull_request.merged == true name: "Comment rebase --onto on Sub PRs" - runs-on: ubuntu-20.04 + runs-on: ubuntu-slim timeout-minutes: 2 steps: - uses: mobsuccess-devops/github-actions-mobsuccess@master diff --git a/.github/workflows/mobsuccess.yml b/.github/workflows/mobsuccess.yml index b94b3d6..8d5693a 100644 --- a/.github/workflows/mobsuccess.yml +++ b/.github/workflows/mobsuccess.yml @@ -5,6 +5,15 @@ name: Mobsuccess Compliance on: + merge_group: + types: + - checks_requested + + issue_comment: + types: + - created + - edited + pull_request: types: - opened @@ -14,13 +23,101 @@ on: jobs: MobsuccessPRCompliance: name: "Mobsuccess PR Compliance" - runs-on: ubuntu-20.04 + runs-on: ubuntu-slim timeout-minutes: 2 steps: - uses: mobsuccess-devops/github-actions-mobsuccess@master with: github-token: ${{ github.token }} - amplify-uri: ${{ secrets.AWS_AMPLIFY_URI }} - storybook-amplify-uri: ${{ secrets.AWS_STORYBOOK_AMPLIFY_URI }} + amplify-uri: ${{ secrets.AWS_AMPLIFY_URI }}${{ vars.AWS_AMPLIFY_URI }} + storybook-amplify-uri: ${{ secrets.AWS_STORYBOOK_AMPLIFY_URI }}${{ vars.AWS_STORYBOOK_AMPLIFY_URI }} action: "validate-pr" + + - name: Checkout + if: github.event_name == 'pull_request' + uses: actions/checkout@v7 + with: + fetch-depth: 0 + filter: blob:none + + - name: Ignored directory replacement + if: github.event_name == 'pull_request' + run: | + set -uo pipefail + fail=0 + + die() { printf '%s\n' "::error::$(esc "$1")"; exit 1; } + + esc() { local s=${1//'%'/%25}; s=${s//$'\r'/%0D}; s=${s//$'\n'/%0A}; printf '%s' "$s"; } + esc_prop() { local s; s=$(esc "$1"); s=${s//:/%3A}; s=${s//,/%2C}; printf '%s' "$s"; } + + work=$(mktemp -d) + trap 'rm -rf "$work"' EXIT + + git diff --raw -z --no-renames --diff-filter=AMT "$BASE_SHA...$HEAD_SHA" > "$work/diff" \ + || die "Cannot diff $BASE_SHA...$HEAD_SHA. Refusing to pass without having checked." + git ls-tree -r -z --name-only "$HEAD_SHA" > "$work/tree" \ + || die "Cannot list the tree at $HEAD_SHA. Refusing to pass without having checked." + + sandbox="$work/sandbox" + mkdir -p "$sandbox" + git -C "$sandbox" init -q . + + : > "$sandbox/.git/info/exclude" + ignored() { + git -c core.excludesFile=/dev/null -C "$sandbox" \ + check-ignore -q --no-index -- "$1" + } + + while IFS= read -r -d '' gi; do + case "$gi" in .gitignore|*/.gitignore) ;; *) continue ;; esac + mkdir -p "$sandbox/$(dirname "$gi")" + git show "$HEAD_SHA:$gi" > "$sandbox/$gi" \ + || die "Cannot read $gi at $HEAD_SHA. Refusing to pass without having checked." + done < "$work/tree" + + while IFS= read -r -d '' meta && IFS= read -r -d '' path; do + mode=$(printf '%s' "$meta" | awk '{print $2}') + case "$mode" in 040000|000000) continue ;; esac + + if ! ignored "$path" && ignored "$path/__probe__"; then + kind="file" + if [ "$mode" = "120000" ]; then + t=$(git show "$HEAD_SHA:$path") \ + || die "Cannot read the symlink target of $path at $HEAD_SHA." + kind="symlink -> $t" + fi + printf '%s\n' "::error file=$(esc_prop "$path")::$(esc "Tracking '$path' ($kind) will DELETE the ignored directory of the same name when this is merged or checked out — its contents are gitignored but the path itself is not.")" + fail=1 + fi + + if [ "$mode" = "120000" ]; then + target=$(git show "$HEAD_SHA:$path") \ + || die "Cannot read the symlink target of $path at $HEAD_SHA." + resolved=$(python3 -c 'import posixpath,sys; print(posixpath.normpath(posixpath.join(posixpath.dirname(sys.argv[1]), sys.argv[2])))' "$path" "$target") \ + || die "Cannot resolve the symlink target of $path." + escape=0 + case "$target" in /*) escape=1 ;; esac + case "$resolved" in ..*) escape=1 ;; esac + if [ "$escape" -eq 1 ]; then + printf '%s\n' "::error file=$(esc_prop "$path")::$(esc "Symlink '$path' -> '$target' points outside the repository. Tracked symlinks must stay repo-internal.")" + fail=1 + fi + fi + done < "$work/diff" + + if [ "$fail" -ne 0 ]; then + echo "" + echo "Remove the offending entry from the commit: git rm --cached " + echo "" + echo "Do NOT 'fix' the .gitignore instead: 'dir/*' plus '!dir/keep' cannot be" + echo "rewritten as a bare 'dir', because git will not re-include anything inside" + echo "an ignored directory. A bare 'dir' is correct only where there is no" + echo "negation to preserve." + exit 1 + fi + echo "No ignored-directory replacement detected." + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} # DO NOT EDIT: END From f1f59dd6cd6df6462b375c75e39200307bd6c0b8 Mon Sep 17 00:00:00 2001 From: Florent Sorel Date: Wed, 30 Sep 2026 13:44:25 +0200 Subject: [PATCH 4/4] chore(ci): keep the Asana workflow, its check is required on master Removing it left the pull request waiting on a required check that nothing reports. The file goes back as it is on master; it can be removed once Asana is dropped from the branch protection. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/asana.yml | 39 +++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/asana.yml diff --git a/.github/workflows/asana.yml b/.github/workflows/asana.yml new file mode 100644 index 0000000..145bcbe --- /dev/null +++ b/.github/workflows/asana.yml @@ -0,0 +1,39 @@ +# DO NOT EDIT: BEGIN +# This snippet has been inserted automatically by mobsuccessbot, do not edit! +# If changes are needed, update the action asana in +# https://github.com/mobsuccess-devops/github-mobsuccess-policy +name: Asana + +on: + pull_request: + types: + - assigned + - unassigned + - review_requested + - review_request_removed + - opened + - synchronize + - closed + - edited + - converted_to_draft + - ready_for_review + + pull_request_review: + types: + - submitted + - edited + - dismissed + +jobs: + Asana: + runs-on: ubuntu-latest + timeout-minutes: 3 + steps: + - uses: mobsuccess-devops/github-actions-asana@master + with: + asana-pat: ${{ secrets.ASANA_PAT }} + github-token: ${{ github.token }} + action: "synchronize" + amplify-uri: ${{ secrets.AWS_AMPLIFY_URI }} + storybook-amplify-uri: ${{ secrets.AWS_STORYBOOK_AMPLIFY_URI }} +# DO NOT EDIT: END