Automating manual actions with GitHub Actions

GitHub Actions is a tool for automating routine actions from your package on GitHub.



From personal experience, I will tell you how, without experience and knowledge about setting up CI, I learned to automate a routine in my Open Source project in just a day and that in fact it is really not as scary and difficult as many people think.



GitHub provides really convenient and working tools for this.





Action plan

  • set up CI in GitHub Actions for a small PHP project





  • ( )





  • , / , PR-s ( ), Check Suite PR, .





  • , , packagist.





, , , Open-Source , , -, . , , .





CI

CI , , PHP Postgres CI . , .



:





.github/workflows/ci.yml
name: CI

on:
  push:
    branches:
      - master
  pull_request:
    types:
      - opened
      - reopened
      - edited
      - synchronize

env:
  COVERAGE: '1'
  php_extensions: 'pdo, pdo_pgsql, pcntl, pcov, ...'
  key: cache-v0.1
  DB_USER: 'postgres'
  DB_NAME: 'testing'
  DB_PASSWORD: 'postgres'
  DB_HOST: '127.0.0.1'

jobs:	
  lint:
    runs-on: '${{ matrix.operating_system }}'
    timeout-minutes: 20	
    strategy:	
      matrix:
        operating_system: ['ubuntu-latest']
        php_versions: ['7.4']
      fail-fast: false
    env:	
      PHP_CS_FIXER_FUTURE_MODE: '0'
    name: 'Lint PHP'
    steps:	
      - name: 'Checkout'
        uses: actions/checkout@v2
      - name: 'Setup cache environment'
        id: cache-env
        uses: shivammathur/cache-extensions@v1
        with:
          php-version: '${{ matrix.php_versions }}'
          extensions: '${{ env.php_extensions }}'
          key: '${{ env.key }}'
      - name: 'Cache extensions'
        uses: actions/cache@v1
        with:
          path: '${{ steps.cache-env.outputs.dir }}'
          key: '${{ steps.cache-env.outputs.key }}'
          restore-keys: '${{ steps.cache-env.outputs.key }}'
      - name: 'Setup PHP'
        uses: shivammathur/setup-php@v2	
        with:	
          php-version: ${{ matrix.php_versions }}
          extensions: '${{ env.php_extensions }}'
          ini-values: memory_limit=-1	
          tools: pecl, composer
          coverage: none
      - name: 'Setup problem matchers for PHP (aka PHP error logs)'
        run: 'echo "::add-matcher::${{ runner.tool_cache }}/php.json"'
      - name: 'Setup problem matchers for PHPUnit'
        run: 'echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"'
      - name: 'Install PHP dependencies with Composer'
        run: composer install --prefer-dist --no-progress --no-suggest --optimize-autoloader
        working-directory: './'
      - name: 'Linting PHP source files'
        run: 'composer lint'
  test:
    strategy:
      fail-fast: false
      matrix:
        operating_system: ['ubuntu-latest']
        postgres: [11, 12]
        php_versions: ['7.3', '7.4', '8.0']
        experimental: false
        include:
          - operating_system: ubuntu-latest
            postgres: '13'
            php_versions: '8.0'
            experimental: true   
    runs-on: '${{ matrix.operating_system }}'
    services:
      postgres:
        image: 'postgres:${{ matrix.postgres }}'
        env:
          POSTGRES_USER: ${{ env.DB_USER }}
          POSTGRES_PASSWORD: ${{ env.DB_PASSWORD }}
          POSTGRES_DB: ${{ env.DB_NAME }}
        ports:
          - 5432:5432
        options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
    name: 'Test / PHP ${{ matrix.php_versions }} / Postgres ${{ matrix.postgres }}'
    needs:
      - lint
    steps:
      - name: 'Checkout'
        uses: actions/checkout@v2
        with:
          fetch-depth: 1
      - name: 'Install postgres client'
        run: |
          sudo apt-get update -y
          sudo apt-get install -y libpq-dev postgresql-client
      - name: 'Setup cache environment'
        id: cache-env
        uses: shivammathur/cache-extensions@v1
        with:
          php-version: ${{ matrix.php_versions }}
          extensions: ${{ env.php_extensions }}
          key: '${{ env.key }}'
      - name: 'Cache extensions'
        uses: actions/cache@v1
        with:
          path: '${{ steps.cache-env.outputs.dir }}'
          key: '${{ steps.cache-env.outputs.key }}'
          restore-keys: '${{ steps.cache-env.outputs.key }}'
      - name: 'Setup PHP'
        uses: shivammathur/setup-php@v2
        with:
          php-version: ${{ matrix.php_versions }}
          extensions: ${{ env.php_extensions }}
          ini-values: 'pcov.directory=src, date.timezone=UTC, upload_max_filesize=20M, post_max_size=20M, memory_limit=512M, short_open_tag=Off'
          coverage: pcov
          tools: 'phpunit'
      - name: 'Install PHP dependencies with Composer'
        run: composer install --prefer-dist --no-progress --no-suggest --optimize-autoloader
        working-directory: './'
      - name: 'Run Unit Tests with PHPUnit'
        continue-on-error: ${{ matrix.experimental }}
        run: |
          sed -e "s/\${USERNAME}/${{ env.DB_USER }}/" \
              -e "s/\${PASSWORD}/${{ env.DB_PASSWORD }}/" \
              -e "s/\${DATABASE}/${{ env.DB_NAME }}/" \
              -e "s/\${HOST}/${{ env.DB_HOST }}/" \
              phpunit.xml.dist > phpunit.xml
          ./vendor/bin/phpunit \
            --verbose \
            --stderr \
            --coverage-clover build/logs/clover.xml
        working-directory: './'
      - name: 'Upload coverage results to Coveralls'
        if: ${{ !matrix.experimental }}
        env:
          COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          COVERALLS_PARALLEL: true
          COVERALLS_FLAG_NAME: php-${{ matrix.php_versions }}-postgres-${{ matrix.postgres }}
        run: |
          ./vendor/bin/php-coveralls \
            --coverage_clover=build/logs/clover.xml \
            -v
  coverage:
    needs: test
    runs-on: ubuntu-latest
    name: "Code coverage"
    steps:
      - name: 'Coveralls Finished'
        uses: coverallsapp/github-action@v1.1.2
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}
          parallel-finished: true
      
      







, 3 (lint, tests coverage)





lint - , , , , .



code style , CI . , umbrellio/code-style-php, ( , ):





"scripts": {
   "lint": "ecs check --config=ecs.yml .",
   "lint-fix": "ecs check --config=ecs.yml . --fix"
}
      
      



test - (os, postgres php), include - ( ).





, :





  • experimental ( ) , CI, , PHP, . ( ).





  • sed -e "s/\${USERNAME}/${{ env.DB_USER }}/"...



    , phpunit.xml.dist phpunit.xml, , ENV, :





phpunit.xml.dist
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false"
         xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
>
    <php>
        <env name="APP_ENV" value="testing"/>
        <ini name="error_reporting" value="-1" />
        <var name="db_type" value="pdo_pgsql"/>
        <var name="db_host" value="${HOST}" />
        <var name="db_username" value="${USERNAME}" />
        <var name="db_password" value="${PASSWORD}" />
        <var name="db_database" value="${DATABASE}" />
        <var name="db_port" value="5432"/>
    </php>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./src</directory>
            <exclude>
                <file>./src/.meta.php</file>
            </exclude>
        </whitelist>
    </filter>
    <testsuites>
        <testsuite name="Test suite">
            <directory suffix="Test.php">./tests</directory>
        </testsuite>
    </testsuites>
</phpunit>
      
      







coverage - .. , .. Postgres, , 100% . , composer, Bandler- Ruby, .





.. badge:100% coverage, , , . , coveralls.io .





CI, .





- (labels)

( ):





.github/labeler.config.yml
type:build:
  - ".github/**/*"
  - ".coveralls.yml"
  - ".gitignore"
  - "ecs.yml"
  - "phpcs.xml"

dependencies:
  - "composer.json"
  - "composer.lock"

type:common
  - "src/**/*"

type:tests:
  - 'tests/**/*'
  - 'phpunit.xml.dist'
  - 'tests.sh'

theme:docs:
  - "README.md"
  - "LICENSE"
  - "CONTRIBUTING.md"
  - "CODE_OF_CONDUCT.md"
      
      







, , PR, PR.





, Summary PR ( patch, minor major). , -, , (pull-) .





.github/workflows/labeler.yml
name: "Auto labeling for a pull request"
on:
  - pull_request_target

jobs:
  triage:
    name: "Checking for labels"
    runs-on: ubuntu-latest
    steps:
      - uses: actions/labeler@main
        with:
          repo-token: "${{ secrets.GITHUB_TOKEN }}"
          sync-labels: true
          configuration-path: ".github/labeler.config.yml"
      
      







-

( ):





.github/assignee.config.yml
addReviewers: true
numberOfReviewers: 1
reviewers:
 - pvsaitpe

addAssignees: true
assignees:
 - pvsaintpe
numberOfAssignees: 1

skipKeywords:
  - wip
  - draft
      
      







, - , GitHub.





.github/workflows/assignee.yml
name: 'Auto assign assignees or reviewers'
on: pull_request

jobs:
  add-reviews:
    name: "Auto assignment of a assignee"
    runs-on: ubuntu-latest
    steps:
      - uses: kentaro-m/auto-assign-action@v1.1.2
        with:
          configuration-path: ".github/assignee.config.yml"
      
      







- PR

:





.github/workflows/auto_merge.yml
name: 'Auto merge of approved pull requests with passed checks'

on:
  pull_request:
    types:
      - labeled
      - unlabeled
      - synchronize
      - opened
      - edited
      - ready_for_review
      - reopened
      - unlocked
  pull_request_review:
    types:
      - submitted
  check_suite:
    types:
      - completed
  status: {}

jobs:
  automerge:
    runs-on: ubuntu-latest
    steps:
      - name: 'Automerge PR'
        uses: "pascalgn/automerge-action@v0.12.0"
        env:
          GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
          MERGE_METHOD: 'squash'
          MERGE_LABELS: "approved,!work in progress"
          MERGE_REMOVE_LABELS: "approved"
          MERGE_COMMIT_MESSAGE: "pull-request-description"
          MERGE_RETRIES: "6"
          MERGE_RETRY_SLEEP: "10000"
          UPDATE_LABELS: ""
          UPDATE_METHOD: "rebase"
          MERGE_DELETE_BRANCH: false
      
      







, PR, approved, CheckSuite .





Squash, .





- PR

PR, approved, :





.github/workflows/auto_approve.yml
on: pull_request_review
name: 'Label approved pull requests'
jobs:
  labelWhenApproved:
    name: 'Label when approved'
    runs-on: ubuntu-latest
    steps:
      - name: 'Label when approved'
        uses: pullreminders/label-when-approved-action@master
        env:
          APPROVALS: "1"
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          ADD_LABEL: "approved"
          REMOVE_LABEL: "awaiting review"
      
      







-

( ) :





.github/release-drafter.yml
template: |
  ## Changes
  $CHANGES
change-template: '- **$TITLE** (#$NUMBER)'

version-template: "$MAJOR.$MINOR.$PATCH"
name-template: '$RESOLVED_VERSION'
tag-template: '$RESOLVED_VERSION'

categories:
  - title: 'Features'
    labels:
      - 'feature'
      - 'type:common'
  - title: 'Bug Fixes'
    labels:
      - 'fix'
      - 'bugfix'
      - 'bug'
      - 'hotfix'
      - 'dependencies'
  - title: 'Maintenance'
    labels:
      - 'type:build'
      - 'refactoring'
      - 'theme:docs'
      - 'type:tests'

change-title-escapes: '\<*_&'

version-resolver:
  major:
    labels:
      - major
      - refactoring
  minor:
    labels:
      - feature
      - minor
      - type:common
  patch:
    labels:
      - patch
      - type:build
      - bug
      - bugfix
      - hotfix
      - fix
      - theme:docs
      - type:tests
  default: patch
      
      







, MAJOR, MINOR, PATCH





.github/workflows/release_drafter.yml
name: Release Drafter

on:
  push:
    branches:
      - master

jobs:
  update_release_draft:
    runs-on: ubuntu-latest
    steps:
      - uses: release-drafter/release-drafter@v5
        with:
          publish: true
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      
      







GitHub Settings





Check Suite GitHub

GitHub , , , , , 100%, , Check Suite.





,





. , , :





approvals





, - , PR, , , Code Owners .





, approvalls





Check Suite





( CI , , , , Coveralls / Scrutinizer, ), .





, PR .





, Check Suite









, , Settings => Options Squash, "Automatically delete head branches"









- packagist.org





, packagist , .





, webhook packagist

packagist (Show Api Token).





, - OpenSource , Contributor- ( ), CI , , , workflow .





coveralls / scrutinizer , Check Suite % 100%, Readme , :





I will be glad if my tutorial is useful to someone, because Before writing this post, I first encountered GitHub Actions, I am not DevOps and I am not engaged in setting up CI, I myself had to google more than one site to set up such a workflow that I needed.








All Articles