Integration test with GitHub Actions
Tags: github, testing, java, maven
Published: 2020-08-30 19:37:17

Integration tests can run for hours, they cover edge cases and complex flows which the regular unit test suit doesn't check, in my case, integration test is deeper level of testing. 

The point is that I don't want them to run for any commit in my PR.

Yes, this flow won't work for me:

```yaml
  
name: Java CI 

on: [push]

jobs:
  build:
```

I want them to run *before* I make the merge, will the bellow flow satisfied me?
```yaml
name: Java CI 

on:
  push:
    branches:
      - master
```
No, too late for me, the code is already merged, and if my tests will fail? master is broken? no way, I want to run them before the merge...



I came up with some "bot" style solution, I'll write a comment in the PR and it will trigger the integration job, it can be helpful to trigger it even before I'm ready to merge, just to get a feeling what is my PR status.

There are 2 issues with that solution (beside that it isn't automatic and require someone to "ask" for ci job..)
1. The job is not running in the PR context.
2. Need to check in any step that this is the required comment I looked for.

Both can be handled just keep it in mind, because it will make the solution a bit complex.

Let's start describe the flow step by step: 

Here is the trigger, I want it to run per comment.
```yaml
name: integration-test

on:
  issue_comment:
    types: [created]
```

But, only for comment with "ci" text :
I use a nice [action](https://github.com/Khan/pull-request-comment-trigger) that checks the comment text and give me output if that comment matches to my trigger word, it also has a nice ability to add emoji if the comment matches:

```yaml
steps:
      - uses: khan/pull-request-comment-trigger@master
        id: check
        with:
          trigger: 'ci'
          reaction: rocket
        env:
          GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
```

After my comment is verified I want to send a message to the PR with the job link, that is needed because the build is not running in the PR context, it runs from the master, in order to make the linkage between the PR and the build, I send this comment back to the PR:

```yaml
 - name: send comment 
        if: steps.check.outputs.triggered == 'true'
        env:
          URL: ${{ github.event.issue.comments_url }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          curl \
            -X POST \
            $URL \
            -H "Content-Type: application/json" \
            -H "Authorization: token $GITHUB_TOKEN" \
            --data '{ "body": ":test_tube: [starting ci integration job]( https://github.com/'"$GITHUB_REPOSITORY"'/actions/runs/'"$GITHUB_RUN_ID"')" }'

```
The next step will pull the PR branch ,as already said, it is needed because the build isn't running in PR context

```yaml
 - name: Get PR informations
        if: steps.check.outputs.triggered == 'true'
        id: pr_data
        run: |
          echo "::set-output name=branch::${{ fromJson(steps.request.outputs.data).head.ref }}"
          echo "::set-output name=repo_name::${{ fromJson(steps.request.outputs.data).head.repo.full_name }}"
          echo "::set-output name=repo_clone_url::${{ fromJson(steps.request.outputs.data).head.repo.clone_url }}"
          echo "::set-output name=repo_ssh_url::${{ fromJson(steps.request.outputs.data).head.repo.ssh_url }}"
    
- name: Checkout PR Branch
        if: steps.check.outputs.triggered == 'true'
        uses: actions/checkout@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          repository: ${{ fromJson(steps.request.outputs.data).head.repo.full_name }}
          ref: ${{ steps.pr_data.outputs.branch }}
        
```
And, last thing, add the checked commit revision to the step output, I will need in next steps.

```yaml
  - name: debug
        if: steps.check.outputs.triggered == 'true'
        id: debug
        run: |
          echo ::set-output name=sha::$( curl -u "u:${{github.token}}" https://api.github.com/repos/${{steps.pr_data.outputs.repo_name}}/git/ref/heads/${{steps.pr_data.outputs.branch}} | jq .object.sha | tr -d '"' )
```

Now comes the regular build step, in my case running Java unit test with Maven (-Pci will turn on maven profile that run only integration tests)

```yaml
 - name: Set up JDK 1.8
        if: steps.check.outputs.triggered == 'true'
        uses: actions/setup-java@v1
        with:
          java-version: 1.8
     
      - name: Build with Maven
        if: steps.check.outputs.triggered == 'true'
        run: mvn clean install -Pci

```

After this step the job is failed or succeeded and I want to send a message indicates the status, it will send a link with the job build url by using `${{GITHUB_RUN_ID}}`.

```yaml
 - name: Create success comment
        if:  steps.check.outputs.triggered == 'true' &&  success()
    
        env:
          URL: ${{ github.event.issue.comments_url }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          curl \
            -X POST \
            $URL \
            -H "Content-Type: application/json" \
            -H "Authorization: token $GITHUB_TOKEN" \
            --data '{ "body": ":v: [finish ci integration job successfully]( https://github.com/'"$GITHUB_REPOSITORY"'/actions/runs/'"$GITHUB_RUN_ID"')" }'    

      - name: Create fail comment
        if:  steps.check.outputs.triggered == 'true' && failure()
    
        env:
          URL: ${{ github.event.issue.comments_url }}
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          curl \
            -X POST \
            $URL \
            -H "Content-Type: application/json" \
            -H "Authorization: token $GITHUB_TOKEN" \
            --data '{ "body": ":facepalm: [ci integration job failed]( https://github.com/'"$GITHUB_REPOSITORY"'/actions/runs/'"$GITHUB_RUN_ID"')" }'
      
```

Bonus part! 
*relevant if your build has Surefire reports*
You can generate test report by using [this](https://github.com/ScaCap/action-surefire-report) nice action.
But you have to send it your last PR commit in order ti see the test results in the PR itself, this is the reason I output the commit sha id in the `debug` step.

```yaml
      - name: Publish Test Report
        if: steps.check.outputs.triggered == 'true' && (failure() || success())
        uses: scacap/action-surefire-report@v1
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          commit: ${{ steps.debug.outputs.sha }}
          check_name: integration_test_results
          
```

That is!

Here is it how it looks in the PR conversation:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/6c7wxbtwiplrv4qlwbbg.png)