From bee5ff02de2b7fe5857981b35eb09aabb869b5a6 Mon Sep 17 00:00:00 2001 From: Philipp Schmelter Date: Tue, 15 Apr 2025 20:34:15 +0200 Subject: [PATCH 1/4] deleted Jenkinsfile and fixed deployment --- Jenkinsfile | 471 ---------------------- gradle/scripts/mavenCentralPublish.gradle | 57 +-- 2 files changed, 30 insertions(+), 498 deletions(-) delete mode 100644 Jenkinsfile diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index 7bd57197..00000000 --- a/Jenkinsfile +++ /dev/null @@ -1,471 +0,0 @@ -#!groovy - -/* - * © 2022. TU Dortmund University, - * Institute of Energy Systems, Energy Efficiency and Energy Economics, - * Research group Distribution grid planning and operation - */ -//////////////////////////////// -// general config values -//////////////////////////////// - -//// project build dir order -//// this list contains the build order -//// normally it *should* start with the project under investigation -//// but if this projects depends on some of our other projects, you have to *build the dependencies first*! -//// *IMPORTANT:* you *MUST* use exact repo names as this will used for checkout! -//// *IMPORTANT2:* you must provide exact 4 elements! -projects = ['powersystemutils'] - -orgNames = ['ie3-institute'] -urls = [ - 'git@github.com:' + orgNames.get(0) -] - -def sonarqubeProjectKey = "edu.ie3:utils" - -/// code coverage token id -codeCovTokenId = "psu-codecov-token" - -//// internal jenkins credentials link for git ssh keys -//// requires the ssh key to be stored in the internal jenkins credentials keystore -def sshCredentialsId = "19f16959-8a0d-4a60-bd1f-5adb4572b702" - -//// internal maven central credentials -def mavenCentralCredentialsId = "197ffae7-08b2-4641-aa15-a2351d8011cd" - -def mavenCentralSignKeyFileId = "dc96216c-d20a-48ff-98c0-1c7ba096d08d" - -def mavenCentralSignKeyId = "a1357827-1516-4fa2-ab8e-72cdea07a692" - -//// define and setjava version //// -//// requires the java version to be set in the internal jenkins java version management -//// use identifier accordingly -def javaVersionId = 'jdk-17' - -//// set java version method (needs node{} for execution) -void setJavaVersion(javaVersionId) { - env.JAVA_HOME = "${tool javaVersionId}" - env.PATH = "${env.JAVA_HOME}/bin:${env.PATH}" -} - -/// global config variables that should be available during runtime -/// and will be overwritten during runtime -> DO NOT CHANGE THEM -String featureBranchName = "" - -//// gradle tasks that are executed -def gradleTasks = "--refresh-dependencies clean spotlessCheck pmdMain pmdTest spotbugsMain spotbugsTest test" // the gradle tasks that are executed on ALL projects -def mainProjectGradleTasks = "jacocoTestReport jacocoTestCoverageVerification reportScoverage checkScoverage" // additional tasks that are only executed on project 0 (== main project) - -/// commit hash -def commitHash = "" - -if (env.BRANCH_NAME == "main") { - - // setup - getMasterBranchProps() - - // pure deployment - // TODO SP: this can probably be removed - if (params.deploy == "true") { - - node { - ansiColor('xterm') { - // get the deployment version - def projectVersion = sh(returnStdout: true, script: "cd ${projects.get(0)}; set +x; ./gradlew -q printVersion") - - try { - - // set java version - setJavaVersion(javaVersionId) - - // set build display name - currentBuild.displayName = "deployment v"+projectVersion +" (" + currentBuild.displayName + ")" - - // checkout from scm - stage('checkout from scm') { - try { - // merged mode - commitHash = gitCheckout(projects.get(0), urls.get(0), 'refs/heads/main', sshCredentialsId).GIT_COMMIT - } catch (exc) { - sh 'exit 1' // failure due to not found main branch - } - } - - // test the project - stage("gradle test ${projects.get(0)}") { - // build and test the project - gradle("${gradleTasks} ${mainProjectGradleTasks}") - } - - // execute sonarqube code analysis - stage('SonarQube analysis') { - withSonarQubeEnv() { - // Will pick the global server connection from jenkins for sonarqube - gradle("sonarqube -Dsonar.branch.name=main -Dsonar.projectKey=$sonarqubeProjectKey") - } - } - - // wait for the sonarqube quality gate - stage("Quality Gate") { - timeout(time: 1, unit: 'HOURS') { - // Just in case something goes wrong, pipeline will be killed after a timeout - def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv - if (qg.status != 'OK') { - error "Pipeline aborted due to quality gate failure: ${qg.status}" - } - } - } - - // publish report und coverage - stage('publish reports + coverage') { - // publish reports - publishReports() - - // inform codecov.io - withCredentials([ - string(credentialsId: codeCovTokenId, variable: 'CODECOV_TOKEN') - ]) { - // call codecov - sh 'curl -s https://codecov.io/bash | bash -s - -t ${CODECOV_TOKEN} -C ' + commitHash - } - } - - // deploy snapshot version to oss sonatype - stage('deploy') { - // get the sonatype credentials stored in the jenkins secure keychain - withCredentials([ - usernamePassword(credentialsId: mavenCentralCredentialsId, usernameVariable: 'MAVENCENTRAL_USER', passwordVariable: 'MAVENCENTRAL_PASS'), - file(credentialsId: mavenCentralSignKeyFileId, variable: 'MAVENCENTRAL_KEYFILE'), - usernamePassword(credentialsId: mavenCentralSignKeyId, usernameVariable: 'MAVENCENTRAL_SIGNINGKEYID', passwordVariable: 'MAVENCENTRAL_SIGNINGPASS') - ]) { - deployGradleTasks = '--refresh-dependencies clean test publish -Puser=${MAVENCENTRAL_USER} -Ppassword=${MAVENCENTRAL_PASS} -Psigning.keyId=${MAVENCENTRAL_SIGNINGKEYID} -Psigning.password=${MAVENCENTRAL_SIGNINGPASS} -Psigning.secretKeyRingFile=${MAVENCENTRAL_KEYFILE}' - - gradle(deployGradleTasks) - } - } - } catch (Exception e) { - // set build result to failure - currentBuild.result = 'FAILURE' - - // publish reports even on failure - publishReports() - - // print exception - Date date = new Date() - println("[ERROR] [${date.format("dd/MM/yyyy")} - ${date.format("HH:mm:ss")}]" + e) - } - } - } - } else { - // merge of features - - node { - ansiColor('xterm') { - try { - // set java version - setJavaVersion(javaVersionId) - - // checkout from scm - stage('checkout from scm') { - try { - // merged mode - commitHash = gitCheckout(projects.get(0), urls.get(0), 'refs/heads/main', sshCredentialsId).GIT_COMMIT - } catch (exc) { - sh 'exit 1' // failure due to not found main branch - } - } - - // get information based on commit hash - def jsonObject = getGithubCommitJsonObj(commitHash, orgNames.get(0), projects.get(0)) - featureBranchName = splitStringToBranchName(jsonObject.commit.message) - - def message = (featureBranchName?.trim()) ? - "main branch build triggered (incl. snapshot deploy) by merging pr from feature branch '${featureBranchName}'" - : "main branch build triggered (incl. snapshot deploy) for commit with message '${jsonObject.commit.message}'" - - // set build display name - currentBuild.displayName = ((featureBranchName?.trim()) ? "merge pr branch '${featureBranchName}'" : "commit '" + - "${jsonObject.commit.message.length() <= 20 ? jsonObject.commit.message : jsonObject.commit.message.substring(0, 20)}...'") + " (" + currentBuild.displayName + ")" - - - // test the project - stage("gradle test ${projects.get(0)}") { - // build and test the project - gradle("${gradleTasks} ${mainProjectGradleTasks}") - } - - // execute sonarqube code analysis - stage('SonarQube analysis') { - withSonarQubeEnv() { - // Will pick the global server connection from jenkins for sonarqube - gradle("sonarqube -Dsonar.branch.name=main -Dsonar.projectKey=$sonarqubeProjectKey ") - } - } - - - // wait for the sonarqube quality gate - stage("Quality Gate") { - timeout(time: 1, unit: 'HOURS') { - // Just in case something goes wrong, pipeline will be killed after a timeout - def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv - if (qg.status != 'OK') { - error "Pipeline aborted due to quality gate failure: ${qg.status}" - } - } - } - - // post processing - stage('publish reports + coverage') { - // publish reports - publishReports() - - // inform codecov.io - withCredentials([ - string(credentialsId: codeCovTokenId, variable: 'CODECOV_TOKEN') - ]) { - // call codecov - sh 'curl -s https://codecov.io/bash | bash -s - -t ${CODECOV_TOKEN} -C ' + commitHash - } - } - - - // deploy snapshot version to oss sonatype - stage('deploy') { - // get the sonatype credentials stored in the jenkins secure keychain - withCredentials([ - usernamePassword(credentialsId: mavenCentralCredentialsId, usernameVariable: 'MAVENCENTRAL_USER', passwordVariable: 'MAVENCENTRAL_PASS'), - file(credentialsId: mavenCentralSignKeyFileId, variable: 'MAVENCENTRAL_KEYFILE'), - usernamePassword(credentialsId: mavenCentralSignKeyId, usernameVariable: 'MAVENCENTRAL_SIGNINGKEYID', passwordVariable: 'MAVENCENTRAL_SIGNINGPASS') - ]) { - deployGradleTasks = '--refresh-dependencies clean test publish -Puser=${MAVENCENTRAL_USER} -Ppassword=${MAVENCENTRAL_PASS} -Psigning.keyId=${MAVENCENTRAL_SIGNINGKEYID} -Psigning.password=${MAVENCENTRAL_SIGNINGPASS} -Psigning.secretKeyRingFile=${MAVENCENTRAL_KEYFILE}' - - gradle(deployGradleTasks) - } - } - } catch (Exception e) { - // set build result to failure - currentBuild.result = 'FAILURE' - - // publish reports even on failure - publishReports() - - // print exception - Date date = new Date() - println("[ERROR] [${date.format("dd/MM/yyyy")} - ${date.format("HH:mm:ss")}]" + e) - } - } - } - } -} else { - - // setup - getFeatureBranchProps() - - node { - - def repoName = "" - // init variables depending of this build is triggered by a branch with PR or without PR - if (env.CHANGE_ID == null) { - // no PR exists - featureBranchName = env.BRANCH_NAME - repoName = orgNames.get(0) + "/" + projects.get(0) - } else { - // PR exists - /// curl the api to get debugging details - def jsonObj = getGithubPRJsonObj(env.CHANGE_ID, orgNames.get(0), projects.get(0)) - - featureBranchName = jsonObj.head.ref - repoName = jsonObj.head.repo.full_name - } - - - ansiColor('xterm') { - try { - // set java version - setJavaVersion(javaVersionId) - - /// set the build name - currentBuild.displayName = featureBranchName + " (" + currentBuild.displayName + ")" - - stage('checkout from scm') { - - try { - commitHash = gitCheckout(projects.get(0), urls.get(0), featureBranchName, sshCredentialsId).GIT_COMMIT - } catch (exc) { - // our target repo failed during checkout - sh 'exit 1' // failure due to not found forcedPR branch - } - } - - // test the project - stage("gradle test ${projects.get(0)}") { - - // build and test the project - gradle("${gradleTasks} ${mainProjectGradleTasks}") - } - - // execute sonarqube code analysis - stage('SonarQube analysis') { - withSonarQubeEnv() { - // Will pick the global server connection from jenkins for sonarqube - - String gradleCommand = "sonarqube -Dsonar.projectKey=$sonarqubeProjectKey" - - if (env.CHANGE_ID != null) { - gradleCommand = gradleCommand + " -Dsonar.pullrequest.branch=${featureBranchName} -Dsonar.pullrequest.key=${env.CHANGE_ID} -Dsonar.pullrequest.base=main -Dsonar.pullrequest.github.repository=${orgNames.get(0)}/${projects.get(0)} -Dsonar.pullrequest.provider=Github" - } else { - gradleCommand = gradleCommand + " -Dsonar.branch.name=$featureBranchName" - } - - - gradle(gradleCommand) - } - } - - // wait for the sonarqube quality gate - stage("Quality Gate") { - timeout(time: 1, unit: 'HOURS') { - // Just in case something goes wrong, pipeline will be killed after a timeout - def qg = waitForQualityGate() // Reuse taskId previously collected by withSonarQubeEnv - if (qg.status != 'OK') { - error "Pipeline aborted due to quality gate failure: ${qg.status}" - } - } - } - - // post processing - stage('post processing') { - // publish reports - publishReports() - - withCredentials([ - string(credentialsId: codeCovTokenId, variable: 'CODECOV_TOKEN') - ]) { - // call codecov - sh 'curl -s https://codecov.io/bash | bash -s - -t ${CODECOV_TOKEN} -C ' + commitHash - } - } - } catch (Exception e) { - // set build result to failure - currentBuild.result = 'FAILURE' - - // publish reports even on failure - publishReports() - - // print exception - Date date = new Date() - println("[ERROR] [${date.format("dd/MM/yyyy")} - ${date.format("HH:mm:ss")}]" + e) - } - } - } -} - - -def getFeatureBranchProps() { - - properties( - [ - pipelineTriggers([ - issueCommentTrigger('.*!test.*') - ]) - ]) -} - - -def getMasterBranchProps() { - properties([ - parameters( - [ - string(defaultValue: '', description: '', name: 'deploy', trim: true) - ]), - [$class: 'ThrottleJobProperty', categories: [], limitOneJobWithMatchingParams: false, maxConcurrentPerNode: 0, maxConcurrentTotal: 0, paramsToUseForLimit: '', throttleEnabled: true, throttleOption: 'project'] - ]) -} - - -//////////////////////////////////// -// git checkout -// NOTE: requires node {} -//////////////////////////////////// -def gitCheckout(String relativeTargetDir, String baseUrl, String branch, String sshCredentialsId) { - checkout([ - $class : 'GitSCM', - branches : [[name: branch]], - doGenerateSubmoduleConfigurations: false, - extensions : [ - [$class: 'RelativeTargetDirectory', relativeTargetDir: relativeTargetDir] - ], - submoduleCfg : [], - userRemoteConfigs : [ - [credentialsId: sshCredentialsId, url: baseUrl + "/" + relativeTargetDir + ".git"] - ] - ]) -} - - -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// publish reports -// IMPORTANT: has to be called inside the same node{} as where the build process (report generation) took place! -///////////////////////////////////////////////////////////////////////////////////////////////////////////////// -def publishReports() { - // publish test reports - publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, escapeUnderscores: false, keepAll: true, reportDir: projects.get(0) + '/build/reports/tests/test', reportFiles: 'index.html', reportName: "${projects.get(0)}_java_tests_report", reportTitles: '']) - - // publish jacoco report for main project only - publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, escapeUnderscores: false, keepAll: true, reportDir: projects.get(0) + '/build/reports/jacoco', reportFiles: 'index.html', reportName: "${projects.get(0)}_jacoco_report", reportTitles: '']) - - // publish pmd report for main project only - publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, escapeUnderscores: false, keepAll: true, reportDir: projects.get(0) + '/build/reports/pmd', reportFiles: 'main.html', reportName: "${projects.get(0)}_pmd_report", reportTitles: '']) - - // publish spotbugs report for main project only - publishHTML([allowMissing: true, alwaysLinkToLastBuild: true, escapeUnderscores: false, keepAll: true, reportDir: projects.get(0) + '/build/reports/spotbugs', reportFiles: 'main.html', reportName: "${projects.get(0)}_spotbugs_report", reportTitles: '']) - - // scoverage report dir - publishHTML([allowMissing: false, alwaysLinkToLastBuild: true, escapeUnderscores: false, keepAll: true, reportDir: projects.get(0) + '/build/reports/scoverageTest', reportFiles: 'scoverage.xml', reportName: "${projects.get(0)}_scoverage_report", reportTitles: '']) -} - - -// gradle wrapper method for easy execution -// requires the gradle version to be configured with the same name under tools in jenkins configuration -def gradle(String command) { - env.JENKINS_NODE_COOKIE = 'dontKillMe' // this is necessary for the Gradle daemon to be kept alive - - // switch directory to be able to use gradle wrapper - sh """cd ${projects.get(0)}""" + ''' set +x; ./gradlew ''' + command -} - -def getGithubPRJsonObj(String prId, String orgName, String repoName) { - def jsonObj = readJSON text: curlByPR(prId, orgName, repoName) - return jsonObj -} - - -def curlByPR(String prId, String orgName, String repoName) { - - def curlUrl = "curl https://api.github.com/repos/" + orgName + "/" + repoName + "/pulls/" + prId - String jsonResponseString = sh(script: curlUrl, returnStdout: true) - - return jsonResponseString -} - -def getGithubCommitJsonObj(String commit_sha, String orgName, String repoName) { - def jsonObj = readJSON text: curlByCSHA(commit_sha, orgName, repoName) - return jsonObj -} - -def curlByCSHA(String commit_sha, String orgName, String repoName) { - - def curlUrl = "curl https://api.github.com/repos/" + orgName + "/" + repoName + "/commits/" + commit_sha - String jsonResponseString = sh(script: curlUrl, returnStdout: true) - - return jsonResponseString -} - -def splitStringToBranchName(String string) { - def obj = string.split().find { it.startsWith("ie3-institute") } - if (obj) - return (obj as String).substring(14) - else - return "" -} diff --git a/gradle/scripts/mavenCentralPublish.gradle b/gradle/scripts/mavenCentralPublish.gradle index 52834008..07e619ca 100644 --- a/gradle/scripts/mavenCentralPublish.gradle +++ b/gradle/scripts/mavenCentralPublish.gradle @@ -1,24 +1,25 @@ /* Maven publish - start */ -task sourcesJar(type: Jar) { + +tasks.register("sourcesJar", Jar) { archiveClassifier.set("sources") from sourceSets.main.allJava } -task javadocJar(type: Jar, dependsOn: javadoc) { +tasks.register("javadocJar", Jar) { + dependsOn tasks.named("javadoc", Javadoc) archiveClassifier.set("javadoc") - from javadoc.destinationDir + from { tasks.named("javadoc", Javadoc).get().destinationDir } } -if (project.hasProperty('user') && project.hasProperty('password')) { - signing { - required { !version.endsWith('SNAPSHOT') } - if(required) - sign(publishing.publications) - } +if (project.hasProperty('user') && project.hasProperty('password') && project.hasProperty('deployVersion')) { + + // snapshot version differs from normal version + String versionString = project.getProperty('deployVersion') + publishing { publications { - mavenJava(MavenPublication) { + create("mavenJava", MavenPublication) { versionMapping { // resolves dynamic versioning to current version number @@ -30,12 +31,12 @@ if (project.hasProperty('user') && project.hasProperty('password')) { } } pom { - description = 'Utility library that is used by several projects @ the Institute of Energy Systems, Energy Efficiency and Energy Economics (ie3) @ TU Dortmund University' - name = 'Power System Utils' + description = 'PowerSystemUtils - an agent-based power system simulation' + name = 'PowerSystemUtils' url = 'https:github.com/ie3-institute/PowerSystemUtils' organization { name = 'Institute of Energy Systems, Energy Efficiency and Energy Economics (ie3)/TU Dortmund University' - url = 'https:www.ie3.tu-dortmund.de' + url = 'https:www.ie3.tu-dortmund.de/' } issueManagement { system = 'GitHub' @@ -44,7 +45,7 @@ if (project.hasProperty('user') && project.hasProperty('password')) { licenses { license { name = 'BSD 3-Clause License' - url = 'https:github.com/ie3-institute/PowerSystemUtils/blob/main/LICENSE' + url = 'https:github.com/ie3-institute/PowerSystemUtils/blob/master/LICENSE' } } developers { @@ -61,38 +62,41 @@ if (project.hasProperty('user') && project.hasProperty('password')) { } removeTestDependenciesFromPom(pom) - groupId group - artifactId 'PowerSystemUtils' - version version + groupId = group + artifactId = 'PowerSystemUtils' + version = versionString from components.java - artifact sourcesJar - artifact javadocJar + artifact tasks.named("sourcesJar") + artifact tasks.named("javadocJar") } } repositories { maven { def releasesRepoUrl = "https://s01.oss.sonatype.org/service/local/staging/deploy/maven2/" def snapshotsRepoUrl = "https://s01.oss.sonatype.org/content/repositories/snapshots/" - url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl + url = versionString.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl credentials { username project.getProperty('user') password project.getProperty('password') } } } + signing { + useInMemoryPgpKeys( + findProperty('signingKey') as String, + findProperty('signingPassword') as String + ) + sign publications.mavenJava + } } - - model { - tasks.generatePomFileForMavenJavaPublication { - destination = file("$rootDir/build/generated-pom.xml") - } + tasks.named("generatePomFileForMavenJavaPublication") { + destination = layout.buildDirectory.file("generated-pom.xml").get().asFile } } def removeTestDependenciesFromPom(pom) { - pom.withXml { def root = asNode() // eliminate test-scoped dependencies (no need in maven central POMs) @@ -102,5 +106,4 @@ def removeTestDependenciesFromPom(pom) { } } - /* Maven publish - end */ From 7c11fafc6a50642d78cf275a0e1c097bcdc0e882 Mon Sep 17 00:00:00 2001 From: Philipp Schmelter Date: Tue, 15 Apr 2025 20:36:23 +0200 Subject: [PATCH 2/4] CHANGELOG.md --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d3176d6..97b8a68a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Added Bao and Staudt to the list of reviewers [#510](https://github.com/ie3-institute/PowerSystemUtils/issues/510) - Upgraded to `scala3` [#533](https://github.com/ie3-institute/PowerSystemUtils) +### Fixed +- Fixed deployment in GitHub Actions pipeline and removed Jenkinsfile [#546](https://github.com/ie3-institute/PowerSystemUtils/issues/546) + ## [2.2.1] ### Changed From f0d1360ee9dc08ff2189c7153c946a914066307a Mon Sep 17 00:00:00 2001 From: Philipp Schmelter Date: Tue, 15 Apr 2025 20:40:51 +0200 Subject: [PATCH 3/4] spotless --- gradle/scripts/mavenCentralPublish.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/scripts/mavenCentralPublish.gradle b/gradle/scripts/mavenCentralPublish.gradle index 07e619ca..b9e3d476 100644 --- a/gradle/scripts/mavenCentralPublish.gradle +++ b/gradle/scripts/mavenCentralPublish.gradle @@ -86,7 +86,7 @@ if (project.hasProperty('user') && project.hasProperty('password') && project.ha useInMemoryPgpKeys( findProperty('signingKey') as String, findProperty('signingPassword') as String - ) + ) sign publications.mavenJava } } From cb7e33f60f28948e38b3c8b0a5c94f1df58d8d2d Mon Sep 17 00:00:00 2001 From: Philipp Schmelter Date: Tue, 15 Apr 2025 21:25:48 +0200 Subject: [PATCH 4/4] resolved conversations --- build.gradle | 7 ------- gradle/scripts/mavenCentralPublish.gradle | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/build.gradle b/build.gradle index d30e0373..8cfbf9f9 100644 --- a/build.gradle +++ b/build.gradle @@ -89,10 +89,3 @@ dependencies { tasks.withType(JavaCompile) { options.encoding = 'UTF-8' } - - -tasks.register("printVersion") { - doLast { - println project.version - } -} diff --git a/gradle/scripts/mavenCentralPublish.gradle b/gradle/scripts/mavenCentralPublish.gradle index b9e3d476..1e2d16ed 100644 --- a/gradle/scripts/mavenCentralPublish.gradle +++ b/gradle/scripts/mavenCentralPublish.gradle @@ -31,7 +31,7 @@ if (project.hasProperty('user') && project.hasProperty('password') && project.ha } } pom { - description = 'PowerSystemUtils - an agent-based power system simulation' + description = 'PowerSystemUtils - Contains utility classes that are used by several ie3 subprojects' name = 'PowerSystemUtils' url = 'https:github.com/ie3-institute/PowerSystemUtils' organization { @@ -45,7 +45,7 @@ if (project.hasProperty('user') && project.hasProperty('password') && project.ha licenses { license { name = 'BSD 3-Clause License' - url = 'https:github.com/ie3-institute/PowerSystemUtils/blob/master/LICENSE' + url = 'https:github.com/ie3-institute/PowerSystemUtils/blob/main/LICENSE' } } developers {