Skip to content

CI

CI #577

Workflow file for this run

---
# DO NOT EDIT: this file is automatically synced from the template repository
# in https://github.com/Liber-UFPE/project-starter.
name: CI
# yamllint disable rule:truthy
on:
push:
branches: [ "main" ]
pull_request:
types: [ "opened", "synchronize", "reopened" ]
# yamllint enable rule:truthy
env:
REGISTRY: ghcr.io
GRADLE_OPTS: >
-Dorg.gradle.console=plain
-Dorg.gradle.caching=true
-Dsonar.gradle.skipCompile=true
-Dorg.gradle.jvmargs="-Xmx2g -XX:MaxMetaspaceSize=512m"'
concurrency:
# This workflow cuts releases, so we want only a
# single concurrent workflow run per branch/tag/etc.
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
diktat:
name: Code Analysis / diktat
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: marcospereira/kotlin-diktat-action@v1
with:
patterns: "src/main/kotlin src/test/kotlin '!src/main/kotlin/br/ufpe/liber/tasks/*.kt'"
ktlint:
name: Code Analysis / ktlint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: nbadal/action-ktlint-setup@v1
- run: ktlint --version
- run: ktlint --relative >> $GITHUB_STEP_SUMMARY
detekt:
name: Code Analysis / detekt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: detekt report
uses: natiginfo/[email protected]
with:
args: |
--report md:build/reports/detekt/detekt.md
- name: Detekt Summary
run: cat build/reports/detekt/detekt.md >> $GITHUB_STEP_SUMMARY
stylelint:
name: Code Analysis / stylelint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: "lts/*" # latest lts
check-latest: true
cache: "yarn"
- run: yarn install
- run: npx stylelint src/main/**/*.scss
eslint:
name: Code Analysis / eslint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: "lts/*" # latest lts
check-latest: true
cache: "yarn"
- run: yarn install
- run: npx eslint .
esbuild-check:
name: Test / Assets / pipeline
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [ 20, 21 ]
steps:
- uses: actions/checkout@v4
- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
check-latest: true
cache: "yarn"
- run: node --version
- run: corepack enable
- run: yarn install
- name: Run assets pipeline
run: |
rm -rf ./build
node assets-pipeline.mjs
tree ./build
gradle-wrapper-validation:
name: Gradle / wrapper-validation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: gradle/actions/wrapper-validation@v3
validate-external-links:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Link Checker
uses: lycheeverse/lychee-action@v1
with:
args: '--verbose --no-progress --exclude-loopback --exclude-path node_modules **/*.md'
jobSummary: true
format: markdown
fail: true
compile:
name: Build / compile
runs-on: ubuntu-latest
needs:
- diktat
- detekt
- ktlint
- stylelint
- eslint
- esbuild-check
- gradle-wrapper-validation
- validate-external-links
steps:
- uses: actions/checkout@v4
- run: corepack enable
- name: Set up Gradle and Java
uses: ./.github/gradle-action
with:
# Allows this job to write to the cache every time it runs
gradle-cache-read-only: false
- name: Start Gradle Daemon
run: ./gradlew --info
- run: ./gradlew testClasses
dependency-review:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
needs:
- compile
steps:
- uses: actions/checkout@v4
- name: 'Dependency Review'
uses: actions/dependency-review-action@v4
with:
fail-on-severity: high
fail-on-scopes: runtime
test:
name: Tests / test
runs-on: ubuntu-latest
needs:
- compile
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- run: corepack enable
- name: Set up Gradle and Java
uses: ./.github/gradle-action
- name: Cache SonarCloud packages
uses: actions/cache@v4
with:
path: ~/.sonar/cache
key: ${{ runner.os }}-sonar
restore-keys: ${{ runner.os }}-sonar
- name: Run tests
run: ./gradlew check koverXmlReport
- name: Run SonarCloud Analysis
continue-on-error: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
run: ./gradlew sonar
- name: Buildkite Test Analytics
if: ${{ github.ref == 'refs/heads/main' && always() }}
env:
BUILDKITE_ANALYTICS_TOKEN: ${{ secrets.BUILDKITE_ANALYTICS_TOKEN }}
run: |
./gradlew mergeJUnitReports
COMMIT_MESSAGE=$(git log -n 1 --format="%s")
curl -X POST --fail-with-body \
-H "Authorization: Token token=$BUILDKITE_ANALYTICS_TOKEN" \
-F "data=@build/test-results/junit.xml" \
-F "format=junit" \
-F "run_env[CI]=github_actions" \
-F "run_env[key]=$GITHUB_ACTION-$GITHUB_RUN_NUMBER-$GITHUB_RUN_ATTEMPT" \
-F "run_env[number]=$GITHUB_RUN_NUMBER" \
-F "run_env[branch]=$GITHUB_REF" \
-F "run_env[commit_sha]=$GITHUB_SHA" \
-F "run_env[message]=$COMMIT_MESSAGE" \
-F "run_env[url]=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" \
https://analytics-api.buildkite.com/v1/uploads
- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v4
continue-on-error: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
with:
verbose: true
test-docker-image:
name: Tests / docker image
runs-on: ubuntu-latest
needs:
- compile
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- name: Docker / Get image name
id: dockerImageName
# yamllint disable rule:line-length
# language="shell script"
run: |
echo "dockerImageName=${{ env.REGISTRY }}/${{ github.repository }}" | tr '[:upper:]' '[:lower:]'>> "$GITHUB_OUTPUT"
- name: Create Image
uses: docker/build-push-action@v6
with:
context: .
load: true # Load is a shorthand for --output=type=docker
tags: ${{ steps.dockerImageName.outputs.dockerImageName }}:latest
# See https://docs.docker.com/build/ci/github-actions/cache/#github-cache
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
BUILDKIT_INLINE_CACHE=1
- name: Test Image
run: |
containerId=$(docker run -d --rm --publish 8080:8080 ${{ steps.dockerImageName.outputs.dockerImageName }})
wget --retry-connrefused --tries=20 -nv --wait=1 --spider http://localhost:8080/
docker container logs "$containerId"
docker container stop "$containerId"
- name: Generate image tar if release branch
if: ${{ github.ref == 'refs/heads/main' }}
# language="shell script"
run: |
docker save "${{ steps.dockerImageName.outputs.dockerImageName }}:latest" | gzip > generate-image-latest.tar.gz
# yamllint enable rule:line-length
- name: Upload image tar if release branch
if: ${{ github.ref == 'refs/heads/main' }}
uses: actions/upload-artifact@v4
with:
path: generate-image-latest.tar.gz
# From GitHub Actions docs: https://docs.github.com/en/actions/learn-github-actions/contexts#github-context
# github.run_id is a unique number for each workflow run within a repository.
# This number does not change if you re-run the workflow run.
#
# It then makes sense to use this to name artifacts and have some guarantees that the name
# is stable (per workflow) and unique (to avoid artifacts uploading name clashes).
#
# The same naming MUST be used when downloading the artifact later. See actions/upload-artifact migration
# docs for more information:
# https://github.com/actions/upload-artifact/blob/main/docs/MIGRATION.md#multiple-uploads-to-the-same-named-artifact
name: docker-image-${{ github.run_id }}
compression-level: 0 # No compression since it is already a gzip file
good-to-merge:
name: Good to merge
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' }}
needs:
- test
- test-docker-image
- dependency-review
steps:
- run: echo "This PR is ready to merge."
generate-tag-name:
name: Generate GitHub tag name
if: ${{ github.ref == 'refs/heads/main' }}
runs-on: ubuntu-latest
needs:
- test
- test-docker-image
# This job also has an output that can be used by downstream jobs.
# https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs
outputs:
tagName: ${{ steps.generateTagName.outputs.tagName }}
steps:
- run: echo "This is a push to main branch. Following with release a new version"
- name: Generate tag name
id: generateTagName
# TAG_NAME value is trying to emulate semver to avoid release ordering issues.
# See https://github.com/orgs/community/discussions/8226.
run: echo "tagName=v$(date '+%Y%m%d.%H%M.%S')" >> "$GITHUB_OUTPUT"
gh-dependency-graph:
name: Generate and Submit Dependency Graph
runs-on: ubuntu-latest
needs:
- generate-tag-name
steps:
- uses: actions/checkout@v4
- uses: ./.github/gradle-action
- uses: gradle/actions/dependency-submission@v3
create-release:
name: Creates a GitHub Release
runs-on: ubuntu-latest
needs:
- generate-tag-name
# Docs:
# https://docs.github.com/en/actions/using-jobs/assigning-permissions-to-jobs
permissions:
contents: write
packages: read # to preserve default permissions
env:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ needs.generate-tag-name.outputs.tagName }}
RELEASE_TITLE: Release ${{ needs.generate-tag-name.outputs.tagName }}
steps:
- uses: actions/checkout@v4
- run: corepack enable
- uses: ./.github/gradle-action
- name: Generate jar artifacts
run: ./gradlew -PreleaseTag=$TAG_NAME clean shadowJar -x test -x accessibilityTest --no-configuration-cache
- name: Create Github Release
run: gh release create "$TAG_NAME" --title "$RELEASE_TITLE" --generate-notes --latest ./build/libs/*.jar
publish-docker-image:
name: Publish docker image
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
TAG_NAME: ${{ needs.generate-tag-name.outputs.tagName }}
needs:
- generate-tag-name
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 0 indicates all history for all branches and tags.
- uses: docker/setup-buildx-action@v3
- name: Docker / Get image name
id: dockerImageName
# yamllint disable rule:line-length
# language="shell script"
run: |
echo "dockerImageName=${{ env.REGISTRY }}/${{ github.repository }}" | tr '[:upper:]' '[:lower:]'>> "$GITHUB_OUTPUT"
# yamllint enable rule:line-length
- name: Download previously generated image tar
uses: actions/download-artifact@v4
with:
name: docker-image-${{ github.run_id }}
- name: Create Image
# language="shell script"
run: |
artifact_file="generate-image-latest.tar.gz"
if [ -f "$artifact_file" ]; then
echo "Previously generate image found. Will load image"
docker load < "$artifact_file"
else
echo "Previously generate image NOT found. Will build image"
docker image build -t ${{ steps.dockerImageName.outputs.dockerImageName }}:latest .
fi
# Needs to log in to use docker scout below
- uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- uses: docker/scout-action@v1
continue-on-error: true
with:
command: quickview
image: ${{ steps.dockerImageName.outputs.dockerImageName }}
write-comment: false
summary: true
# Adapted from https://docs.docker.com/build/ci/github-actions/test-before-push/
- name: Test Image
# From `docker run --help`:
# -d, --detach Run container in background and print container ID
# --rm Automatically remove the container when it exits
# -p, --publish list Publish a container's port(s) to the host
run: |
containerId=$(docker run -d --rm --publish 8080:8080 ${{ steps.dockerImageName.outputs.dockerImageName }})
wget --retry-connrefused --tries=20 -nv --wait=1 --spider http://localhost:8080/
docker container logs "$containerId"
docker container stop "$containerId"
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Publish to GitHub Registry
run: |
last_git_sha=$(git log --pretty=format:'%h' HEAD -1)
source_image_name=${{ steps.dockerImageName.outputs.dockerImageName }}
echo "Using git tag $TAG_NAME"
echo "Using last git sha $last_git_sha"
echo "Context's github.sha = ${{ github.sha }}"
echo "Images to tag => $source_image_name:$TAG_NAME"
echo "Images to tag => $source_image_name:$last_git_sha"
docker tag "$source_image_name" "$source_image_name:$TAG_NAME"
docker tag "$source_image_name" "$source_image_name:$last_git_sha"
docker push --all-tags ${{ steps.dockerImageName.outputs.dockerImageName }}