From 9e86dfbfb4e8b6019fc31a4d1a8f22d5cf90bf71 Mon Sep 17 00:00:00 2001 From: Philipp Schmelter Date: Wed, 9 Apr 2025 13:31:24 +0200 Subject: [PATCH 1/3] GHA --- .github/workflows/ci.yml | 102 +++++++++++++++++++++++++++++++ CHANGELOG.md | 2 + build.gradle | 1 + gradle/scripts/branchName.gradle | 26 ++++++++ gradle/scripts/semVer.gradle | 8 +-- scripts/branch_type.sh | 39 ++++++++++++ scripts/get_versions.sh | 38 ++++++++++++ scripts/run-version-check.sh | 10 +++ scripts/version_check.sh | 76 +++++++++++++++++++++++ 9 files changed, 298 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 gradle/scripts/branchName.gradle create mode 100644 scripts/branch_type.sh create mode 100644 scripts/get_versions.sh create mode 100644 scripts/run-version-check.sh create mode 100644 scripts/version_check.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..53490d4a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,102 @@ +# © 2025. TU Dortmund University, +# Institute of Energy Systems, Energy Efficiency and Energy Economics, +# Research group Distribution grid planning and operation +# + +name: CI + +on: + push: + paths-ignore: + - 'docs/**' + branches: + - main + - dev + - 'hotfix/*' + - 'rel/*' + - 'dependabot/*' + pull_request: + branches: + - main + - dev + +jobs: + buildAndTest: + runs-on: ubuntu-latest + + steps: + - name: Checkout Source + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Setup Java + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: 17 + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v4 + + - name: Check Branch + run: | + if [ "${{ github.event_name }}" == "pull_request" ]; then + BRANCH_NAME="${{ github.head_ref }}" + else + BRANCH_NAME="${{ github.ref_name }}" + fi + + if [[ "$BRANCH_NAME" == refs/heads/* ]]; then + BRANCH_NAME="${BRANCH_NAME#refs/heads/}" + fi + + export BRANCH_NAME + + echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV + + ./gradlew checkBranchName -PbranchName="$BRANCH_NAME" --warning-mode=none + + bash scripts/branch_type.sh + + - name: Version Check + if: ${{ github.event_name == 'pull_request' }} + env: + BASE_BRANCH: ${{ github.event.pull_request.base.ref }} + run: bash scripts/run-version-check.sh + + - name: Build Project + run: ./gradlew --refresh-dependencies clean assemble spotlessCheck + + - name: Run Tests + run: ./gradlew pmdMain pmdTest test jacocoTestReport jacocoTestCoverageVerification + + - name: Build Java-Docs + run: ./gradlew javadoc + + - name: SonarQube + run: | + ./gradlew sonar \ + -Dsonar.projectKey=${{ vars.SONAR_PROJECT_KEY }} \ + -Dsonar.host.url=${{ vars.SONAR_HOST_URL }} \ + -Dsonar.login=${{ secrets.SONAR_TOKEN }} \ + -Dsonar.qualitygate.wait=true + + #Deployment + - name: Deploy + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/dev' + env: + ORG_GRADLE_PROJECT_signingKey: ${{ secrets.MAVENCENTRAL_SIGNINGKEY }} + ORG_GRADLE_PROJECT_signingPassword: ${{ secrets.MAVENCENTRAL_SIGNINGPASS }} + ORG_GRADLE_PROJECT_user: ${{ secrets.MAVENCENTRAL_USER }} + ORG_GRADLE_PROJECT_password: ${{ secrets.MAVENCENTRAL_PASS }} + run: | + if [ "${GITHUB_REF}" == "refs/heads/main" ]; then + currentVersion=$(./gradlew -q currentVersion) + else + currentVersion=$(./gradlew -q devVersion) + fi + + echo "currentVersion=$currentVersion" + + ./gradlew publish -PdeployVersion=$currentVersion diff --git a/CHANGELOG.md b/CHANGELOG.md index 22f86c33..daf203c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased/Snapshot] +### Added +- Implemented GitHub Actions pipeline [#247](https://github.com/ie3-institute/simonaAPI/issues/247) ### Changed - Converting pekko classic to typed [#232](https://github.com/ie3-institute/simonaAPI/issues/232) diff --git a/build.gradle b/build.gradle index 296d070e..77f4e9aa 100644 --- a/build.gradle +++ b/build.gradle @@ -40,6 +40,7 @@ apply from: scriptsLocation + 'mavenCentralPublish.gradle' apply from: scriptsLocation + 'jacoco.gradle' apply from: scriptsLocation + 'documentation.gradle' apply from: scriptsLocation + 'test.gradle' +apply from: scriptsLocation + 'branchName.gradle' repositories { mavenCentral() diff --git a/gradle/scripts/branchName.gradle b/gradle/scripts/branchName.gradle new file mode 100644 index 00000000..f6b4bcbf --- /dev/null +++ b/gradle/scripts/branchName.gradle @@ -0,0 +1,26 @@ +tasks.register('checkBranchName') { + doLast { + if (!project.hasProperty('branchName')) { + throw new GradleException("Error: Missing required property 'branchName'.") + } + + def branchName = project.property('branchName') + + def patterns = [ + ~/^(developer|develop|dev)$/, + ~/.*rel\/.*/, + ~/^dependabot\/.*$/, + ~/.*hotfix\/\pL{2}\/#\d+.*/, + ~/.*main/, + ~/^[a-z]{2}\/#[0-9]+(?:-.+)?$/ + ] + + def isValid = patterns.any { pattern -> branchName ==~ pattern } + + if (!isValid) { + throw new GradleException("Error: Check Branch name format (e.g., ps/#1337-FeatureName). Current branch name is $branchName.") + } + + println "Branch name is $branchName" + } +} diff --git a/gradle/scripts/semVer.gradle b/gradle/scripts/semVer.gradle index ec680a48..c3300893 100644 --- a/gradle/scripts/semVer.gradle +++ b/gradle/scripts/semVer.gradle @@ -1,13 +1,13 @@ // tasks for semantic versioning using semver-gradle https://github.com/ethauvin/semver-gradle -task currentVersion { - doFirst{ +tasks.register('currentVersion') { + doFirst { println semver.semver } } -task devVersion { - doFirst{ +tasks.register('devVersion') { + doFirst { println "${semver.major}.${semver.minor}-SNAPSHOT" } } diff --git a/scripts/branch_type.sh b/scripts/branch_type.sh new file mode 100644 index 00000000..e1c27248 --- /dev/null +++ b/scripts/branch_type.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -euo pipefail + +if [ -z "${BRANCH_NAME:-}" ]; then + echo "Error: BRANCH_NAME variable is not set." + exit 1 +fi + + +pattern_dev='^(developer|develop|dev)$' +pattern_release='.*rel/.*' +pattern_dependabot='^dependabot/.*' +pattern_hotfix='.*hotfix/.*' +pattern_main='.*main' +pattern_feature='^[a-z]{2}/#[0-9]+(-.+)?$' + +BRANCH_TYPE="unknown" + +if [[ "$BRANCH_NAME" =~ $pattern_dev ]]; then + BRANCH_TYPE="dev" +elif [[ "$BRANCH_NAME" =~ $pattern_release ]]; then + BRANCH_TYPE="release" +elif [[ "$BRANCH_NAME" =~ $pattern_dependabot ]]; then + BRANCH_TYPE="dependabot" +elif [[ "$BRANCH_NAME" =~ $pattern_hotfix ]]; then + BRANCH_TYPE="hotfix" +elif [[ "$BRANCH_NAME" =~ $pattern_main ]]; then + BRANCH_TYPE="main" +elif [[ "$BRANCH_NAME" =~ $pattern_feature ]]; then + BRANCH_TYPE="feature" +else + echo "Error:'$BRANCH_NAME' does not match any pattern." + exit 1 +fi + +echo "=========================" +echo "Branch type: $BRANCH_TYPE" +echo "BRANCH_TYPE=$BRANCH_TYPE" >> "$GITHUB_ENV" +echo "=========================" diff --git a/scripts/get_versions.sh b/scripts/get_versions.sh new file mode 100644 index 00000000..7001c49d --- /dev/null +++ b/scripts/get_versions.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -euo pipefail + +cd "$(dirname "$0")/.." + +REPO_URL=$(git config --get remote.origin.url) +export REPO_URL +echo "REPO_URL=$REPO_URL" >> $GITHUB_ENV + +echo "Fetching current version of PR..." +PR_VERSION=$(./gradlew -q currentVersion) +echo "PR_VERSION=$PR_VERSION" +echo "export PR_VERSION=$PR_VERSION" >> versions.env +echo "PR_VERSION=$PR_VERSION" >> "$GITHUB_ENV" + +get_branch_version() { + local BRANCH_NAME=$1 + local DIR_NAME="${BRANCH_NAME}-branch" + + git clone --depth 1 --branch "$BRANCH_NAME" "$REPO_URL" "$DIR_NAME" + cd "$DIR_NAME" + + echo "Fetching version from $BRANCH_NAME branch..." + BRANCH_VERSION=$(./gradlew -q currentVersion) + cd .. + + echo "${BRANCH_NAME^^}_VERSION=$BRANCH_VERSION" + echo "export ${BRANCH_NAME^^}_VERSION=$BRANCH_VERSION" >> versions.env + echo "${BRANCH_NAME^^}_VERSION=$BRANCH_VERSION" >> "$GITHUB_ENV" + + rm -rf "$DIR_NAME" +} + + +get_branch_version "dev" +get_branch_version "main" + +echo "Get Versions: OK!" diff --git a/scripts/run-version-check.sh b/scripts/run-version-check.sh new file mode 100644 index 00000000..ebd2bb25 --- /dev/null +++ b/scripts/run-version-check.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -euo pipefail + +rm -f versions.env + +scripts/get_versions.sh + +source versions.env + +scripts/version_check.sh diff --git a/scripts/version_check.sh b/scripts/version_check.sh new file mode 100644 index 00000000..bfa3328c --- /dev/null +++ b/scripts/version_check.sh @@ -0,0 +1,76 @@ +#!/bin/bash +set -euo pipefail + +cd "$(dirname "$0")/.." + +echo "=========================" +echo "LOADED ENV VARIABLES:" +echo "PR_VERSION: $PR_VERSION" +echo "DEV_VERSION: $DEV_VERSION" +echo "MAIN_VERSION: $MAIN_VERSION" +echo "BASE_BRANCH: $BASE_BRANCH" +echo "=========================" + +semver_gt() { + IFS='.' read -r major1 minor1 patch1 <<< "$1" + IFS='.' read -r major2 minor2 patch2 <<< "$2" + + # Compare major version + if [ "$major1" -gt "$major2" ]; then + return 0 + elif [ "$major1" -lt "$major2" ]; then + return 1 + fi + + # Compare minor version + if [ "$minor1" -gt "$minor2" ]; then + return 0 + elif [ "$minor1" -lt "$minor2" ]; then + return 1 + fi + + # Compare patch version + if [ "$patch1" -gt "$patch2" ]; then + return 0 + else + return 1 + fi +} + +# Version Checking Logic +if [ "$BASE_BRANCH" = "dev" ]; then + echo "PR into dev => applying dev rules" + if [ "$DEV_VERSION" = "$PR_VERSION" ]; then + echo "OK: PR version ($PR_VERSION) matches the current dev version ($DEV_VERSION)." + exit 0 + else + if [ "$MAIN_VERSION" = "$DEV_VERSION" ]; then + if semver_gt "$PR_VERSION" "$DEV_VERSION"; then + echo "OK: Increasing working version in dev from $DEV_VERSION to $PR_VERSION" + exit 0 + else + echo "FAIL: Release and working version are $MAIN_VERSION, but PR is not increasing the working version in dev" + exit 1 + fi + else + echo "FAIL: PR version ($PR_VERSION) does not match the current dev version ($DEV_VERSION)." + echo "Regular PRs must not update the working version. The working version should only change in controlled updates." + exit 1 + fi + fi + +elif [ "$BASE_BRANCH" = "main" ]; then + echo "PR into main => applying main rules" + if semver_gt "$PR_VERSION" "$MAIN_VERSION"; then + echo "OK: PR version ($PR_VERSION) is greater than the current main version ($MAIN_VERSION)." + exit 0 + else + echo "FAIL: PR version ($PR_VERSION) is NOT greater than the current main version ($MAIN_VERSION)." + echo "A new release must have a higher version than the existing main version." + exit 1 + fi + +else + echo "Skipping version check: Base branch is '$BASE_BRANCH'. No version enforcement required." + exit 0 +fi From 740a4b88d7297153756e78bd27348c9d7da30389 Mon Sep 17 00:00:00 2001 From: Philipp Schmelter Date: Wed, 9 Apr 2025 13:34:41 +0200 Subject: [PATCH 2/3] spotless --- gradle/scripts/branchName.gradle | 38 ++++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/gradle/scripts/branchName.gradle b/gradle/scripts/branchName.gradle index f6b4bcbf..99ba2c50 100644 --- a/gradle/scripts/branchName.gradle +++ b/gradle/scripts/branchName.gradle @@ -1,26 +1,26 @@ tasks.register('checkBranchName') { - doLast { - if (!project.hasProperty('branchName')) { - throw new GradleException("Error: Missing required property 'branchName'.") - } - - def branchName = project.property('branchName') + doLast { + if (!project.hasProperty('branchName')) { + throw new GradleException("Error: Missing required property 'branchName'.") + } - def patterns = [ - ~/^(developer|develop|dev)$/, - ~/.*rel\/.*/, - ~/^dependabot\/.*$/, - ~/.*hotfix\/\pL{2}\/#\d+.*/, - ~/.*main/, - ~/^[a-z]{2}\/#[0-9]+(?:-.+)?$/ - ] + def branchName = project.property('branchName') - def isValid = patterns.any { pattern -> branchName ==~ pattern } + def patterns = [ + ~/^(developer|develop|dev)$/, + ~/.*rel\/.*/, + ~/^dependabot\/.*$/, + ~/.*hotfix\/\pL{2}\/#\d+.*/, + ~/.*main/, + ~/^[a-z]{2}\/#[0-9]+(?:-.+)?$/ + ] - if (!isValid) { - throw new GradleException("Error: Check Branch name format (e.g., ps/#1337-FeatureName). Current branch name is $branchName.") - } + def isValid = patterns.any { pattern -> branchName ==~ pattern } - println "Branch name is $branchName" + if (!isValid) { + throw new GradleException("Error: Check Branch name format (e.g., ps/#1337-FeatureName). Current branch name is $branchName.") } + + println "Branch name is $branchName" + } } From a3a94058ee31e63bbcd371535dd0ee8856d7f13a Mon Sep 17 00:00:00 2001 From: Philipp Schmelter Date: Wed, 9 Apr 2025 13:42:13 +0200 Subject: [PATCH 3/3] permissions --- scripts/branch_type.sh | 0 scripts/get_versions.sh | 0 scripts/run-version-check.sh | 0 scripts/version_check.sh | 0 4 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 scripts/branch_type.sh mode change 100644 => 100755 scripts/get_versions.sh mode change 100644 => 100755 scripts/run-version-check.sh mode change 100644 => 100755 scripts/version_check.sh diff --git a/scripts/branch_type.sh b/scripts/branch_type.sh old mode 100644 new mode 100755 diff --git a/scripts/get_versions.sh b/scripts/get_versions.sh old mode 100644 new mode 100755 diff --git a/scripts/run-version-check.sh b/scripts/run-version-check.sh old mode 100644 new mode 100755 diff --git a/scripts/version_check.sh b/scripts/version_check.sh old mode 100644 new mode 100755