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/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/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/.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 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