Skip to content

Commit

Permalink
Post about gh actions and services
Browse files Browse the repository at this point in the history
  • Loading branch information
alkampfergit committed Apr 29, 2024
1 parent e2b191e commit b19bca6
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: "CodeQL Scanning in GitHub"
description: "GitHub code scanning can spot security problem in your code automatically, a really nice feature"
date: 2024-04-23T08:00:00+02:00
draft: false
tags: ["GitHub", "GitHub Actions"]
categories: ["continuous integration"]
---

I blogged in the past on how you can Analyze you code with SonarCloud [in a GitHub action](https://www.codewrecks.com/post/github/github-sonarcloud-codecoverage/). Things changed a little in the latest year but in this post I want to examine a different aspect **running tests that rely on external service, like ElasticSearch**. Running integration test in GH action is a little more complex than running unit tests, because you need to **setup the environment but thanks to docker usually this can be done with a little effort**.

Lets examine how we can create a GH action to run integration tests that relies on ElasticSearch.

{{< highlight yaml "linenos=table,hl_lines=7-12,linenostart=1" >}}
jobs:
build:
name: Build
runs-on: ubuntu-latest
timeout-minutes: 5

services:
elasticsearch:
image: docker.elastic.co/elasticsearch/elasticsearch:8.13.0
ports:
- 9800:9200
options: --health-cmd="curl http://localhost:9200/_cluster/health" -e "discovery.type=single-node" -e "xpack.security.enabled=false"
{{< /highlight >}}

As you can see, before starting to declare **job steps, I've added a services section where I can specify services that are needed to run this action**. In this example I have only one service, called elasticsearch: that is **based on the official docker image of ElasticSearch.** I've also specified that I want to map port 9200 of the container to port 9800 of the host, and I've also specified some options to the container.

Thanks to services, I can specify containers that needs to run before my jobs starts. Then you usually need **to add some steps that wait for the service to be available**. This happens because when the docker instance started, elasticsearch needs some time to become operational. Generic service node has no way to know if its internal service is operative. The result is using a simple step **that uses PowerShell core code to wait for the base ElasticSearch url to answer a successful code**. This is a matter of few lines of PowerShell code. **Since this is powershell code (shell: pwsh) it runs perfectly even on ubuntu machines.**

{{< highlight yaml "linenos=table,linenostart=1" >}}
- name: Wait for Elasticsearch to be ready
shell: pwsh
run: |
$uri = "http://localhost:9800"
$timeoutSeconds = 120
$intervalSeconds = 5
$sw = [Diagnostics.Stopwatch]::StartNew()
while ($sw.elapsed.totalseconds -lt $timeoutSeconds) {
try {
$response = Invoke-WebRequest -Uri $uri -Method Get -ErrorAction Stop
if ($response.StatusCode -eq 200) {
Write-Host "Successfully connected to $uri"
Write-Host "Response content: $($response.Content)"
$sw.Stop()
return
}
}
catch {
Write-Host "Failed to connect to $uri. Retrying in $intervalSeconds second(s)..."
Start-Sleep -Seconds $intervalSeconds
}
}
$sw.Stop()
throw "Could not connect to $uri within $timeoutSeconds second(s)."
{{< /highlight >}}

This is what you see when your action runs. As you can see you can also verify basic information about the version of elasticsearch that got deployed. Action runners are quite fast, so I usually do not see wait cycles, but it happened **and this simple step makes sure that the service is up and running before running the tests**.

![Wait for Elasticsearch action screenshot](../images/ghit wait-for-elastic-action.png)
***Figure 1:*** *Wait for Elasticsearch action screenshot*

Now after this action complete, elasticsearch is up and operational, so I can run my PowerShell core script that builds the solution, executes the tests, collect code coverage and so on.

This shows you how flexible GitHub actions are, thanks to **services you can run whatever docker image you need to run your integration scripts**, just by specifying images and configuration. This is a real lifesaver when you need to run **integration tests that rely on databases or external services**.

Gian Maria.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b19bca6

Please sign in to comment.