Github Actions – Deploying [P2]

Tiếp theo bài về execute UnitTest giờ thì ta deploy lên STAG / UAT

Giả sử ta có Workflow như sau

  • Chạy Code Standards checks
  • Rồi Rector để upgrade code structure với PHP 8
  • Sau đó chạy UnitTest
  • Cuối cùng sẽ deploy lên STAG
  • Sau khi merge PR về develop sẽ deploy lên UAT

1 chút nhắc lại câu chuyện Parallel

  • Nếu chạy Tests mà có tương tác với database thì chỉ nên chạy 1 runner / server

Đầu tiên là build và deploy trên Stag

# https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
on:
  # https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows
  pull_request:
    branches: [ develop ]
    types: [ opened, synchronize ]
  push:
    branches: [ develop ]

Action này sẽ được trigger các branches của develop với 2 types là opened & synchronize

Note: By default, only the openedsynchronize, and reopened activity types trigger workflows that run on the pull_request event. To trigger workflows by different activity types, use the types keyword.

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

Tiếp theo là build & tests

jobs:

  build:
    name: Code standards check
    strategy:
      matrix:
        lint: [ phpstan, phpmd, rector ]
        php: [ php8.0, php8.1 ]

    runs-on:
      - self-hosted
      - ${{ matrix.php }}

    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      #      PHP will be installed on server by itself

      - name: Setup application
        if: success()
        run: |
          php -r "file_exists('.env') || copy('.env.example', '.env');"
          composer install --no-ansi --no-scripts --no-progress --prefer-dist

      - name: Lint
        run: composer ${{ matrix.lint }}

  tests:
    name: Execute UnitTest
    strategy:
      matrix:
        test: [ Core, Flickr, Jav ]
    runs-on:
      - self-hosted
      - database
    needs: [ build ]

    services:
      mysql:
        image: mariadb:latest
        env:
          MYSQL_ROOT_PASSWORD: root
          MYSQL_DATABASE: xcrawler
        ports:
          - 3306:3306

      redis:
        image: redis
        ports:
          - 6379:6379

      mongo:
        image: mongo:bionic
        options: >-
          --health-cmd mongo
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
        ports:
          - 27017:27017

    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Setup application
        if: success()
        run: |
          php -r "file_exists('.env') || copy('.env.example', '.env');"
          composer install --no-ansi --no-scripts --no-progress --prefer-dist
          php artisan key:generate
          chmod -R 777 storage bootstrap/cache
          php artisan config:clear
          php artisan migrate:fresh

      - name: Execute tests (Unit and Feature tests) via PHPUnit
        if: success()
        run: |
          ./vendor/bin/phpunit --testsuite=${{ matrix.test }} --coverage-clover coverage-${{ matrix.test }}.xml

      - name: Coverage
        uses: actions/upload-artifact@v2
        if: success()
        with:
          name: coverage-reports
          path: coverage-${{ matrix.test }}.xml

  test_finished:
    name: Test Finished
    runs-on:
      - self-hosted
    needs: [ tests ]

    steps:
      - name: Download build from artifact
        uses: actions/download-artifact@v2
        if: success()
        with:
          name: coverage-reports
          path: ./reports

      - name: Upload coverage to codecov.io
        uses: codecov/codecov-action@v1
        if: success()
        with:
          directory: ./reports

      - name: Notifications
        uses: act10ns/slack@v1.5.0
        if: success()
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
        with:
          status: ${{ job.status }}
          config: .github/config/slack.yml

Và đây là khúc quan trọng nhất. Deploy lên stag – dynamic branch. Giả sử mỗi PR ta đều deploy lên độc lập.

  deploy_staging:
    name: Deploy to Staging
    runs-on:
      - self-hosted
      - staging
    needs: [ test_finished ]

    steps:

      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - name: Build staging
        if: success() && ${{ github.event.pull_request.type}} == 'opened'
        run: |
          BRANCH_NAME=$(bin/slugified.sh "${{ github.head_ref }}")
          rm -rf ~/public_html/xcrawler.dynamic/$BRANCH_NAME
          git clone git@github.com:jooservices/XCrawler.git ~/public_html/xcrawler.dynamic/$BRANCH_NAME
          cd ~/public_html/xcrawler.dynamic/$BRANCH_NAME
          cp ~/.env.xcrawler.staging .env
          composer install
          php artisan migrate --force

Ở đây còn 1 số bất cập

  • Database là hard code từ env.xcrawler.staging . Do đó … hờ mất đi ý nghĩa của dynamic . Nên cái này có thể gọi là chỉ 1 staging thôi.

1 lưu ý khác

  • Nếu staging server nằm độc lập và không có runner trên đó thì ta cần execute deploy qua SSH. Do staging ở trên nằm cùng server với runner nên tiện chạy run luôn
  • Gọi qua bin/slugified.sh để tạo slug từ branch name .
  • Có thể improve thêm bằng việc gửi Notification nếu đã deployed success hoặc notification khi test_finished bị fail .

Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Up ↑

%d bloggers like this: