Preview Pull Requests and Automated CI/CD
Tags: actionshackathon21
Published: 2021-12-09 07:22:13

### My Workflow
I am going to Automate CI/CD with linting, testing and code analysis for Python and Vue.js and Preview Pull Requests Builds.

My Repository have a Client build with Vue.js and a Server build with Python. Now, It is a E2E chat messenger.

So, Here how it works

My first workflow is to build and deploy or preview Client, It runs whenever a push or pull request creates for main branch containing changes to the code of client. It install dependencies and builds vue.js app. After build I use [peaceiris/actions-gh-pages](https://github.com/peaceiris/actions-gh-pages) to deploy it to Github Pages. If the event is Pull Request then deploy to a sub-directory named preview and commit hash and leave a comment on PR.

My second workflow it to lint, test and build docker of Python Server, It runs on the same condition as of client with commit containing changes to the code of Python Server. It setup python, installs dependencies of the server and lints and tests the code. On successful completion of the first job second job is to build and release the Docker Image. If the event is Pull Request then it leaves a comment on PR.
There is one other job that performs code analysis with [github/codeql-action](https://github.com/github/codeql-action).

![Comments on PR](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/64dctz6d0ovs8eza698w.png)


So, These two workflow performs CI/CD and preview Pull Request builds.

{% github https://github.com/PradyumnaKrishna/enigma-protocol %}

### Submission Category: 
Maintainer Must-Haves


### Yaml File or Link to Code

Here are my files for the two workflows

1. Client Build & Deployment
```yml
name: Client Build

on:
  push:
    branches:
      - main
    paths:
      - client/**
  pull_request:
    branches:
      - main
    paths:
      - client/**

jobs:
  release:
    defaults:
      run:
        working-directory: client
    runs-on: ubuntu-latest
    env:
      VUE_APP_APIURL: ${{ secrets.VUE_APP_APIURL }}
    steps:
      - name: Checkout Code
        uses: actions/checkout@v2
      - name: Setup Node
        uses: actions/setup-node@v2
        with:
          node-version: '14'
      - name: Cache Dependencies
        uses: actions/cache@v2
        with:
          path: ~/.npm
          key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
          restore-keys: |
            ${{ runner.os }}-node-
      - name: Install Dependencies
        run: npm ci
      - name: Build
        run: npm run build
      - name: Set outputs
        id: vars
        run: echo "::set-output name=sha_short::$(git rev-parse --short ${{ github.event.pull_request.head.sha }})"
      - name: Preview Pull Request
        if: ${{ github.event_name == 'pull_request' }}
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./client/dist
          destination_dir: preview/${{ steps.vars.outputs.sha_short }}
          cname: protocol.onpy.in
      - name: Release
        if: ${{ github.event_name == 'push' }}
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./client/dist
          cname: protocol.onpy.in
          keep_files: true
      - name: Publish
        if: ${{ github.event_name == 'pull_request' }}
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          header: Client Github Pages Build
          message: |
            Preview avaiable to https://protocol.onpy.in/preview/${{ steps.vars.outputs.sha_short }}
```

2. Server Build and Release
```yml
name: Python Server Build

on:
  push:
    branches:
      - main
    paths:
      - server/python/**
  pull_request:
    branches:
      - main
    paths:
      - server/python/**

jobs:
  code_analysis:
    defaults:
      run:
        working-directory: server/python
    name: Code Analysis
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write
    strategy:
      fail-fast: false
      matrix:
        language: ["python"]
    steps:
      - name: Checkout Code
        uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: 3.8
      - name: Install Dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements-test.txt
      - name: Lint
        run: |
          pylint *.py
          black --check .
      - name: Initialize CodeQL
        uses: github/codeql-action/init@v1
        with:
          languages: ${{ matrix.language }}
      - name: Autobuild
        uses: github/codeql-action/autobuild@v1
      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v1

  lint-and-test:
    defaults:
      run:
        working-directory: server/python
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Set up Python
        uses: actions/setup-python@v1
        with:
          python-version: 3.8
      - name: Install Dependencies
        run: |
          python -m pip install --upgrade pip
          pip install -r requirements-test.txt
      - name: Lint
        run: |
          pylint *.py
          black --check .
      - name: Test
        run: |
          pytest tests

  build:
    needs: lint-and-test
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      pull-requests: write

    env:
      REGISTRY: ghcr.io
      IMAGE_NAME: ghcr.io/pradyumnakrishna/enigma-protocol/python-server
    
    steps:
      - name: Set DATE
        run: echo "DATE=$(date '+%Y-%m-%d')" >> $GITHUB_ENV
      - name: Checkout repository
        uses: actions/checkout@v2
      - name: Log in to the Container registry
        uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - name: Set Image Tags
        run: |
          export SHORT_SHA=$(echo ${{ github.sha }} | cut -c1-7)
          if [[ ${{ github.event_name }} == 'push' ]]; then
            echo "IMAGE_TAG=${{ env.IMAGE_NAME }}:latest,${{ env.IMAGE_NAME }}:$SHORT_SHA" >> $GITHUB_ENV
          else
            echo "IMAGE_TAG=${{ env.IMAGE_NAME }}:$SHORT_SHA" >> $GITHUB_ENV
          fi
          exit 0
        shell: bash
      - name: Build and Push Server Image
        uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
        with:
          context: server/python
          push: true
          tags: ${{ env.IMAGE_TAG }}
      - name: Publish
        if: ${{ github.event_name == 'pull_request' }}
        uses: marocchino/sticky-pull-request-comment@v2
        with:
          header: Python Server Docker Build
          message: |
            Python Server image build with tag consist commit hash, Use command given below to pull it.
            docker pull ${{ env.IMAGE_TAG }}
```


### Additional Resources / Info
Here's the repo where this workflow is used: [github.com/PradyumnaKrishna/enigma-protocol](https://github.com/PradyumnaKrishna/enigma-protocol)

The Client Deployment and Preview Website: [protocol.onpy.in](https://protocol.onpy.in)
The Server Releases: [ghcr.io/PradyumnaKrishna/enigma-protocol/python-server](https://ghcr.io/PradyumnaKrishna/enigma-protocol/python-server)

Actions I used
- actions/setup-python
- actions/setup-node
- marocchino/sticky-pull-request-comment
- peaceiris/actions-gh-pages
- docker/build-push-action
- docker/login-action
- github/codeql-action
- actions/checkout