Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/main/groovy/com/cloudogu/gitops/Application.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ class Application {
log.debug("Starting Application")

setNamespaceListToConfig(config)

features.forEach(feature -> {
feature.validate()
})
features.forEach(feature -> {
feature.install()
})
Expand Down
11 changes: 10 additions & 1 deletion src/main/groovy/com/cloudogu/gitops/Feature.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,19 @@ abstract class Feature {
}

abstract boolean isEnabled()




/*
* Hooks for enabling or disabling a feature. Both optional, because not always needed.
*/
protected void enable() {}
protected void disable() {}

/*
* Hook for special feature validation. Optional.
* Feature should throw RuntimeException to stop immediately.
*/
protected void validate() { }

}
274 changes: 179 additions & 95 deletions src/main/groovy/com/cloudogu/gitops/features/Content.groovy

Large diffs are not rendered by default.

39 changes: 7 additions & 32 deletions src/main/groovy/com/cloudogu/gitops/scmm/ScmmRepo.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -95,24 +95,26 @@ class ScmmRepo {
}
}


void cloneRepo() {
log.debug("Cloning $scmmRepoTarget repo")
gitClone()
checkoutOrCreateBranch('main')
Git.cloneRepository()
.setURI(getGitRepositoryUrl())
.setDirectory(new File(absoluteLocalRepoTmpDir))
.setCredentialsProvider(getCredentialProvider())
.call()
}

/**
* @return true if created, false if already exists. Throw exception on all other errors
*/
boolean create(String description, ScmmApiClient scmmApiClient) {
boolean create(String description, ScmmApiClient scmmApiClient, boolean initialize = true) {
def namespace = scmmRepoTarget.split('/', 2)[0]
def repoName = scmmRepoTarget.split('/', 2)[1]

def repositoryApi = scmmApiClient.repositoryApi()
def repo = new Repository(namespace, repoName, description)
log.debug("Creating repo: ${namespace}/${repoName}")
def createResponse = repositoryApi.create(repo, true).execute()
def createResponse = repositoryApi.create(repo, initialize).execute()
handleResponse(createResponse, repo)

def permission = new Permission(config.scmm.gitOpsUsername as String, Permission.Role.WRITE)
Expand Down Expand Up @@ -218,33 +220,6 @@ class ScmmRepo {
.setCredentialsProvider(getCredentialProvider())
}

void checkoutOrCreateBranch(String branch) {
log.debug("Checking out $branch for repo $scmmRepoTarget")
getGit()
.checkout()
.setCreateBranch(!branchExists(branch))
.setName(branch)
.call()
}

private boolean branchExists(String branch) {
return getGit()
.branchList()
.call()
.collect { it.name.replace("refs/heads/", "") }
.contains(branch)
}

protected Git gitClone() {
Git.cloneRepository()
.setURI(getGitRepositoryUrl())
.setDirectory(new File(absoluteLocalRepoTmpDir))
.setNoCheckout(true)
.setCredentialsProvider(getCredentialProvider())
.call()

}

private CredentialsProvider getCredentialProvider() {
if (scmProvider == "gitlab") {
username = "oauth2"
Expand Down
350 changes: 174 additions & 176 deletions src/test/groovy/com/cloudogu/gitops/features/ContentTest.groovy

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import com.cloudogu.gitops.config.Config
import com.cloudogu.gitops.scmm.ScmmRepo
import com.cloudogu.gitops.scmm.ScmmRepoProvider
import org.apache.commons.io.FileUtils
import org.eclipse.jgit.api.Git

import static org.mockito.Mockito.spy
import static org.mockito.Mockito.spy

class TestScmmRepoProvider extends ScmmRepoProvider {
Map<String, ScmmRepo> repos = [:]
Expand Down Expand Up @@ -45,24 +44,6 @@ class TestScmmRepoProvider extends ScmmRepoProvider {
return remoteGitRepopUrl
}

@Override
protected Git gitClone() {
// Cloning from filepath does not work without setting branch
try {
Git.cloneRepository()
.setURI(getGitRepositoryUrl())
.setDirectory(new File(absoluteLocalRepoTmpDir))
.setNoCheckout(true)
.setBranch('main')
.call()

} catch (Exception e) {
// test workaround for testing same repo again. Clean folder with .git and do it again.
// it need 2-3 tries
fileSystemUtils.deleteFilesExcept(new File(absoluteLocalRepoTmpDir))
gitClone()
}
}
}
// Create a spy to enable verification while keeping real behavior
ScmmRepo spyRepo = spy(repoNew)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
copyRepo1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
copyRepo1
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
copyRepo2
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
copyRepo2
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#!groovy

String getApplication() { 'spring-petclinic-plain' }
String getConfigRepositoryPRRepo() { 'example-tenant/gitops' }
String getScmManagerCredentials() { 'scmm-user' }
String getConfigRepositoryPRBaseUrl() { env.SCMM_URL }

String getDockerRegistryBaseUrl() { env.REGISTRY_URL }
String getDockerRegistryPath() { env.REGISTRY_PATH }
String getDockerRegistryCredentials() { 'registry-user' }
String getCesBuildLibRepo() { configRepositoryPRBaseUrl+"/repo/3rd-party-dependencies/ces-build-lib/" }
String getCesBuildLibVersion() { 'main' }
String getGitOpsBuildLibRepo() { configRepositoryPRBaseUrl+"/repo/3rd-party-dependencies/gitops-build-lib" }
String getGitOpsBuildLibVersion() { 'main'}

loadLibraries()

properties([
// Don't run concurrent builds, because the ITs use the same port causing random failures on concurrent builds.
disableConcurrentBuilds()
])

node {

mvn = cesBuildLib.MavenWrapper.new(this)

catchError {

stage('Checkout') {
checkout scm
}

stage('Build') {
mvn 'clean package -DskipTests -Dcheckstyle.skip'
archiveArtifacts artifacts: '**/target/*.jar'
}

stage('Test') {
// Tests skipped for faster demo and exercise purposes
//mvn 'test -Dmaven.test.failure.ignore=true -Dcheckstyle.skip'
}

String imageName = ""
stage('Docker') {
String imageTag = createImageTag()
String pathPrefix = !dockerRegistryPath?.trim() ? "" : "${dockerRegistryPath}/"
imageName = "${dockerRegistryBaseUrl}/${pathPrefix}${application}:${imageTag}"
image = docker.build(imageName, '.')

if (isBuildSuccessful()) {
docker.withRegistry("https://${dockerRegistryBaseUrl}", dockerRegistryCredentials) {
image.push()
}
} else {
echo 'Skipping docker push, because build not successful'
}
}

stage('Deploy') {
if (isBuildSuccessful() && env.BRANCH_NAME in ['main']) {

def gitopsConfig = [
scm: [
provider : 'SCMManager',
credentialsId: scmManagerCredentials,
baseUrl : configRepositoryPRBaseUrl,
repositoryUrl : configRepositoryPRRepo,
],
application: application,
gitopsTool: 'ARGO',
folderStructureStrategy: 'ENV_PER_APP',
k8sVersion : env.K8S_VERSION,
deployments: [
sourcePath: 'k8s',
destinationRootPath: 'apps',
plain: [
updateImages: [
[ filename: 'deployment.yaml',
containerName: application,
imageName: imageName ]
]
]
],
fileConfigmaps: [
// Showcase for gitops-build-lib: Convert file into a config map
[
name : 'messages',
sourceFilePath : '../src/main/resources/messages/messages.properties',
stage: ['staging', 'production']
]
],
stages: [
staging: [
namespace: 'example-apps-staging',
deployDirectly: true ],
production: [
namespace: 'example-apps-production',
deployDirectly: false ],
]
]
addSpecificGitOpsConfig(gitopsConfig)

deployViaGitops(gitopsConfig)
} else {
echo 'Skipping deploy, because build not successful or not on main branch'
}
}
}

// Archive Unit and integration test results, if any
junit allowEmptyResults: true, testResults: '**/target/failsafe-reports/TEST-*.xml,**/target/surefire-reports/TEST-*.xml'
}

/** Initializations might not be needed in a real-world setup, but are necessary for GitOps playground */
void addSpecificGitOpsConfig(gitopsConfig) {
gitopsConfig += [
// In the GitOps playground, we're loading the build libs from our local SCM so it also works in an offline context
// As the gitops-build-lib also uses the ces-build-lib we need to pass those parameters on.
// If you can access the internet, you can rely on the defaults, which load the lib from GitHub.
cesBuildLibRepo: cesBuildLibRepo,
cesBuildLibVersion: cesBuildLibVersion,
cesBuildLibCredentialsId: scmManagerCredentials,


// The GitOps playground provides parameters for overwriting the build images used by gitops-build-lib, so
// it also works in an offline context.
// Those parameters overwrite the following parameters.
// If you can access the internet, you can rely on the defaults, which load the images from public registries.
buildImages : [
helm: 'ghcr.io/cloudogu/helm:3.16.4-1',
kubectl: 'bitnami/kubectl:1.29',
kubeval: 'ghcr.io/cloudogu/helm:3.16.4-1',
helmKubeval: 'ghcr.io/cloudogu/helm:3.16.4-1',
yamllint: 'cytopia/yamllint:1.25-0.7'
]
]
}

String createImageTag() {
def git = cesBuildLib.Git.new(this)
String branch = git.simpleBranchName
String branchSuffix = ""

if (!"develop".equals(branch)) {
branchSuffix = "-${branch}"
}

return "${new Date().format('yyyyMMddHHmm')}-${git.commitHashShort}${branchSuffix}"
}

def loadLibraries() {
// In the GitOps playground, we're loading the build libs from our local SCM so it also works in an offline context
// If you can access the internet, you could also load the libraries directly from github like so
// @Library(["github.com/cloudogu/ces-build-lib@${cesBuildLibVersion}", "github.com/cloudogu/gitops-build-lib@${gitOpsBuildLibRepo}"]) _
//import com.cloudogu.ces.cesbuildlib.*
//import com.cloudogu.ces.gitopsbuildlib.*

cesBuildLib = library(identifier: "ces-build-lib@${cesBuildLibVersion}",
retriever: modernSCM([$class: 'GitSCMSource', remote: cesBuildLibRepo, credentialsId: scmManagerCredentials])
).com.cloudogu.ces.cesbuildlib

library(identifier: "gitops-build-lib@${gitOpsBuildLibVersion}",
retriever: modernSCM([$class: 'GitSCMSource', remote: gitOpsBuildLibRepo, credentialsId: scmManagerCredentials])
).com.cloudogu.gitops.gitopsbuildlib
}

def cesBuildLib
def gitOpsBuildLib
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
mirrorRepo1
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mirror
Repo1

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.