1 of 45

Najskuteczniejsze

GitHub Actions

dla programistów PHP

Lighting Talk

Aleksander Tabor

PHP Developer

aleksandertabor.com

linkedin.com/in/aleksander-tabor

github.com/aleksandertabor�alekx.tabor@gmail.com

2 of 45

Czym są GitHub Actions i do czego się przydają?

  • CI/CD (testy, deployment)
  • sprawdzanie jakości kodu np. analiza statyczna
  • udowodnienie kompatybilności np. z różnymi wersjami PHP
  • reakcje na zdarzenia w naszym repozytorium
  • automatyzacje

3 of 45

Niski próg wejścia

  • scenariusze pisane w YAML
  • prosty start: github.com/OWNER/REPOSITORY-NAME/actions
  • ogromna ilość gotowych scenariuszy dzięki projektom Open Source

4 of 45

Eventy, po których wiesz, że coś się dzieje…

Link: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows

  • push
  • pull_request
  • schedule
  • workflow_dispatch
  • repository_dispatch

5 of 45

Szereg akcji przy Pull Requescie

6 of 45

Workflow GitHub Action - plik .yml w .github/workflows

Źródło: https://www.youtube.com/watch?v=Tz7FsunBbfQ

7 of 45

Testy PHPUnit

name: deployment # workflow => .github/workflows/deployment.yml

on:

workflow_dispatch: # event

push: # event

paths:

- "**"

jobs:

tests: # job

runs-on: ubuntu-latest # operation system

services:

mysql:

image: bitnami/mysql:8.0

env:

MYSQL_ROOT_PASSWORD: password

MYSQL_USER: sail

MYSQL_DATABASE: testing

MYSQL_PASSWORD: password

MYSQL_AUTHENTICATION_PLUGIN: mysql_native_password

ports:

- 3306:3306

options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=10

steps: # steps

- uses: actions/checkout@v4

- uses: shivammathur/setup-php@v2

with:

php-version: '8.2'

tools: composer:v2

8 of 45

Testy PHPUnit #2

- name: Mysql privileges

run: mysql --host 127.0.0.1 --port 3306 --user="root" --password="password" --execute="GRANT ALL PRIVILEGES ON *.* TO sail@'%';"

- name: Get composer cache directory

id: composer-cache

working-directory: ./

run: echo "::set-output name=dir::$(composer config cache-files-dir)"

- name: Cache dependencies

uses: actions/cache@v3

with:

path: ${{ steps.composer-cache.outputs.dir }}

key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }}

restore-keys: ${{ runner.os }}-composer-

- name: Install composer dependencies

working-directory: ./

run: composer install

- name: Setup env for testing

working-directory: ./

run: |

sed -ri "s/^DB_HOST=mysql/DB_HOST=127.0.0.1/" .env.testing

sed -ri "s/^DB_PORT=3306/DB_PORT=${{ job.services.mysql.ports[3306] }}/" .env.testing

9 of 45

Testy PHPUnit #3

- name: PhpUnit

working-directory: ./

run: php artisan test --parallel

10 of 45

Testy PHPUnit #4

11 of 45

Testy PHPUnit #5

12 of 45

Deployment

deploy-staging:

runs-on: ubuntu-latest

needs: tests-job

if: github.ref == 'refs/heads/master'

steps:

- uses: actions/checkout@v4

- name: Install SSH key

uses: shimataro/ssh-key-action@v2

with:

key: ${{ secrets.SSH_KEY_STAGING }}

known_hosts: ${{ secrets.KNOWN_HOSTS_STAGING }}

- name: Deploy

working-directory: ./deployer

run: php deployer.phar -f web.php deploy staging

13 of 45

Testy Laravel Dusk z Artifacts

- name: Upgrade Chrome Driver

run: php artisan dusk:chrome-driver `/opt/google/chrome/chrome --version | cut -d " " -f3 | cut -d "." -f1`

- name: Start Chrome Driver

run: ./vendor/laravel/dusk/bin/chromedriver-linux

- name: Run Dusk

run: |

php artisan serve --no-reload & php artisan dusk

env:

APP_URL: "http://127.0.0.1:8000"

APP_ENV: "testing"

- name: Upload dusk screenshots

uses: actions/upload-artifact@v4

if: ${{ failure() }}

with:

name: dusk-screenshots

path: tests/Browser/screenshots

14 of 45

Testy Laravel Dusk z Artifacts #2

15 of 45

Testy Laravel Dusk z Artifacts #3

16 of 45

Static Analysis z Annotations

- name: PhpStan

working-directory: ./

run: php vendor/bin/phpstan analyse --memory-limit=2G --error-format=github

17 of 45

Comment Pull Request Action

- name: Comment PR

uses: thollander/actions-comment-pull-request@v2

with:

message: |

# New comment 🔗

New comment body

18 of 45

Git Auto Commit Action

- name: Commit changes

uses: stefanzweifel/git-auto-commit-action@v4

with:

commit_message: ♻️ Refactor code

19 of 45

Git Auto Commit Action #2 - Rector

rector-job:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: shivammathur/setup-php@v2

with:

php-version: '8.2'

tools: composer:v2

- run: git pull

- run: composer install --no-interaction --no-progress --no-suggest

- run: vendor/bin/rector process --ansi

- name: Check for Rector modified files

id: rector-git-check

run: echo ::set-output name=modified::$(if git diff --exit-code --no-patch; then echo "false"; else echo "true"; fi)

- name: Commit changes

if: steps.rector-git-check.outputs.modified == 'true'

uses: stefanzweifel/git-auto-commit-action@v4

with:

commit_message: ♻️ Refactor code

20 of 45

Git Auto Commit Action #3 - PHP CS Fixer

php-cs-fixer-job:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: shivammathur/setup-php@v2

with:

php-version: '8.2'

tools: composer:v2

- name: Install composer dependencies

working-directory: ./

run: composer install --no-interaction --no-progress --no-suggest

- name: PhpCs

working-directory: ./

run: php vendor/bin/php-cs-fixer fix --config=.php_cs.dist.php --allow-risky=yes

- name: Commit changes

uses: stefanzweifel/git-auto-commit-action@v4

with:

commit_message: 🎨 Fix styling

21 of 45

Notyfikacje Slack

- name: Slack Notification

uses: rtCamp/action-slack-notify@v2

if: ${{ failure() }}

env:

SLACK_USERNAME: Tests Bot

SLACK_ICON_EMOJI: ':fire:'

SLACK_COLOR: ${{ job.status }}

SLACK_MESSAGE: Laravel Dusk Tests Failed

SLACK_FOOTER: by Aleksander Tabor

SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}

22 of 45

Notyfikacje Slack #2

23 of 45

Zmiany w paczkach Composer

name: Composer Diff

on:

pull_request:

paths:

- 'composer.lock'

permissions:

contents: read

pull-requests: write

jobs:

composer-diff:

name: Composer Diff

runs-on: ubuntu-latest

steps:

- name: Checkout

uses: actions/checkout@v4

with:

fetch-depth: 0

- name: Generate composer diff

id: composer_diff

uses: IonBazan/composer-diff-action@v1

24 of 45

Zmiany w paczkach Composer #2

- uses: marocchino/sticky-pull-request-comment@v2

if: ${{ steps.composer_diff.outputs.composer_diff_exit_code != 0 }}

with:

header: composer-diff

message: |

<details>

<summary>Composer package changes</summary>

${{ steps.composer_diff.outputs.composer_diff }}

</details>

25 of 45

Zmiany w paczkach Composer #3

26 of 45

GitHub Actions Schedule - wtedy kiedy śpimy…

name: Scheduler

on:

schedule:

- cron: '0 0 * * *'

workflow_dispatch:

jobs:

schedule-job:

runs-on: ubuntu-latest

steps:

- name: Checkout repository

uses: actions/checkout@v4

with:

fetch-depth: 0

- name: Fetch all branches

run: git fetch --all

- name: Get commits from last day

id: get-commits

run: |

git log --since="1 day ago" --format="%H %ad %s" --date=format:'%Y-%m-%d %H:%M:%S' --all > commits.txt

27 of 45

GitHub Actions Schedule - wtedy kiedy śpimy… #2

- name: Post commits as comment

id: get-parsed-commits

uses: actions/github-script@v7

with:

script: |

const fs = require('fs');

const path = './commits.txt';

if (fs.existsSync(path)) {

const content = fs.readFileSync(path, 'utf8');

const lines = content.split('\n');

const commits = lines.map(line => {

const [commitHash, ...message] = line.split(' ');

return `- [\`${commitHash}\`](https://github.com/${{ github.repository }}/commit/${commitHash}) - ${message.join(' ')}`;

}).join('\n');

const issue_number = 327;

const commentBody = `### Last Day Commits:\n${commits}`;

github.rest.issues.createComment({

owner: context.repo.owner,

repo: context.repo.repo,

issue_number: issue_number,

body: commentBody

});

} else {

throw new Error(`File ${path} does not exist`);

}

28 of 45

GitHub Actions Schedule - wtedy kiedy śpimy… #3

29 of 45

Labeler Action

name: Label Pull Requests

on: [pull_request]

permissions:

contents: read

pull-requests: write

jobs:

labeler:

name: Label Pull Requests Job

runs-on: ubuntu-latest

steps:

- name: Checkout

uses: actions/checkout@v4

- uses: actions/labeler@v5

with:

repo-token: "${{ secrets.GITHUB_TOKEN }}"

sync-labels: true

configuration-path: .github/labeler.yml

dot: true

30 of 45

Labeler Action #2

routes:

- changed-files:

- any-glob-to-any-file: 'routes/web.php'

migrations:

- changed-files:

- any-glob-to-any-file:

- database/migrations/*

31 of 45

Labeler Action #3

32 of 45

Dalsza zabawa - routing aplikacji jako komentarz PR

name: Show routes

on: [pull_request]

permissions:

contents: read

pull-requests: write

jobs:

show-routes-job:

name: Show routes job

runs-on: ubuntu-latest

steps:

- name: Checkout

uses: actions/checkout@v4

- uses: shivammathur/setup-php@v2

with:

php-version: '8.2'

tools: composer:v2

- name: Install composer dependencies

working-directory: ./

run: composer install --no-interaction --no-progress --no-suggest

33 of 45

Dalsza zabawa - routing aplikacji jako komentarz PR #2

- name: Vendor Route List

id: vendor-route-list

working-directory: ./

run: |

echo "::set-output name=results::$(php artisan route:list --only-vendor --json)"

- uses: buildingcash/json-to-markdown-table-action@v1

id: table

with:

json: ${{ steps.vendor-route-list.outputs.results }}

- name: Comment PR

uses: thollander/actions-comment-pull-request@v2

with:

message: |

# Routes list 🔗

All routes in your application.

${{ steps.table.outputs.table }}

34 of 45

Dalsza zabawa - routing aplikacji jako komentarz PR #3

35 of 45

Dependabot

version: 2

updates:

- package-ecosystem: "github-actions"

directory: "/"

schedule:

interval: "weekly"

labels:

- "dependencies"

- package-ecosystem: "composer"

directory: "/"

schedule:

interval: "weekly"

labels:

- "php"

- "dependencies"

36 of 45

Dependabot

37 of 45

Actionlint

Link: https://github.com/rhysd/actionlint

38 of 45

Wsparcie IDE

Link: https://plugins.jetbrains.com/plugin/21396-github-workflow

39 of 45

Jira

40 of 45

Co dalej?

Link: https://github.com/marketplace?type=actions&query=php

41 of 45

GitHub Actions Certificate

Link: https://examregistration.github.com/certification/ACTIONS

42 of 45

Co jeszcze możemy zrobić z GitHub Actions?

  • Tworzenie dokumentacji
  • Zarządzanie releases
  • Changelog
  • Uruchamianie narzędzi PHP np. Composer Normalize, Behat, phparkitect, phpmd
  • Wpuścić AI do Code Review
  • Własne GitHub Actions - pisane w JavaScripcie, a nawet w PHP
  • Badges do Readme.md
  • Wszelkiego rodzaju automatyzacje

43 of 45

Źródła, wiedza

Link: https://github.com/aleksandertabor/PHPers-Summit-2024-Najskuteczniejsze-GitHub-Actions-dla-programistow-PHP

44 of 45

Dziękuję

45 of 45

Q&A