Skip to content

Commit fa17d2e

Browse files
authored
Prepare release 4.13.0 (#1283)
1 parent 6ecd0f4 commit fa17d2e

30 files changed

Lines changed: 1286 additions & 143 deletions

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88

99
### Fixed
1010
* Fix Tailor deployment drifts for D, Q envs ([#1055](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1055))
11+
12+
## [4.13.0] - 2026-06-30
13+
### Changed
14+
* Push container images to AWS ECR independently of EKS, while optionally triggering EKS deployments when needed ([#1267](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1267))
15+
* Updated Java version in sonarqube execution to Java 21 ([#1269](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1269))
16+
17+
### Fixed
1118
* Fix branch mapping logic to ensure correct environment assignment ([#1263](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1263))
1219
* Fix Nexus not accepting npm artifacts when uploaded through odsComponentStageUploadToNexus ([#1268](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1268))
1320
* Aqua Stage is being skipped when branches are not eligable ([#1170](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1170))
@@ -46,6 +53,7 @@
4653
### Fixed
4754
* Fix SonarQube run enable/disable logic ([#1259](https://github.com/opendevstack/ods-jenkins-shared-library/pull/1259))
4855

56+
4957
## [4.11.1] - 2025-12-19
5058

5159
### Fixed

docs/modules/jenkins-shared-library/partials/odsComponentStageRolloutOpenShiftDeployment.adoc

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,19 @@ In addition to the configuration options below, one can use e.g. a `Tailorfile`
6161
| Option | Description
6262

6363

64+
| *awsEnvPath* +
65+
_String_
66+
|Path to AWS environment configuration env files (defaults to `./environments`).
67+
Files (dev.yml, test.yaml, prod.yaml) must contain the following keys:
68+
account: "..."
69+
eksCluster: "..."
70+
region: ...
71+
credentials:
72+
key: ... (e.g. projectName-cd-aws-us-access-key-id-dev)
73+
secret: ... (e.g. projectName-cd-aws-us-secret-access-key-dev)
74+
Only relevant for AWS-based deployments (odsComponentStageRolloutAWSDeployment)
75+
76+
6477
| *branch* +
6578
_String_
6679
|Branch to run stage for.
@@ -165,6 +178,14 @@ _List<String>_
165178
directory referenced by `chartDir` exists.
166179

167180

181+
| *helmWithOnlyECR* +
182+
_Boolean_
183+
|Whether to use Helm for deployment or only sync with ECR (defaults to `false`)
184+
If `true`, the process will only use the ECR repository to store the image. So, no Helm deployment will be done.
185+
If `false`, the image will be stored in ECR and the helm deployment will be executed.
186+
Only relevant for AWS-based deployments (odsComponentStageRolloutAWSDeployment)
187+
188+
168189
| *imageTag* +
169190
_String_
170191
|Image tag on which to apply the `latest` tag (defaults to `context.shortGitCommit`).

src/org/ods/component/AbstractDeploymentStrategy.groovy

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -37,23 +37,6 @@ abstract class AbstractDeploymentStrategy implements IDeploymentStrategy {
3737
originalVersions
3838
}
3939

40-
protected findOrCreateImageStream(String targetProject, String image) {
41-
try {
42-
openShift.findOrCreateImageStream(targetProject, image)
43-
} catch (Exception ex) {
44-
steps.error "Could not find/create ImageStream ${image} in ${targetProject}. Error was: ${ex}"
45-
}
46-
}
47-
48-
protected void retagImages(String targetProject, Set<String> images) {
49-
images.each { image ->
50-
findOrCreateImageStream(targetProject, image)
51-
openShift.importImageTagFromProject(
52-
targetProject, image, context.cdProject, options.imageTag, options.imageTag
53-
)
54-
}
55-
}
56-
5740
@TypeChecked(TypeCheckingMode.SKIP)
5841
protected Set<String> getBuiltImages() {
5942
context.buildArtifactURIs.builds.keySet().findAll { it ->

src/org/ods/component/Context.groovy

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ class Context implements IContext {
495495
// https://issues.jenkins-ci.org/browse/JENKINS-27421 and
496496
// https://issues.jenkins-ci.org/browse/JENKINS-35191.
497497
for (def key : config.branchToEnvironmentMapping.keySet()) {
498-
if (config.gitBranch.startsWith(key)) {
498+
if (config.gitBranch.startsWith(key) && key.endsWith('/')) {
499499
setMostSpecificEnvironment(
500500
config.branchToEnvironmentMapping[key],
501501
config.gitBranch.replace(key, '')
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.ods.component
2+
3+
import org.ods.util.ILogger
4+
import org.ods.util.PodData
5+
6+
/**
7+
* Deployment strategy that only pushes images to ECR without performing a
8+
* Helm upgrade or any OpenShift/EKS rollout. Use this when images must be
9+
* synchronised to ECR but the actual cluster deployment is handled elsewhere.
10+
*/
11+
class ECROnlyDeploymentStrategy extends AbstractDeploymentStrategy {
12+
13+
private final IContext context
14+
private final ILogger logger
15+
private final IImageRepository imageRepository
16+
private final RolloutOpenShiftDeploymentOptions options
17+
18+
ECROnlyDeploymentStrategy(
19+
IContext context,
20+
Map<String, Object> config,
21+
IImageRepository imageRepository,
22+
ILogger logger
23+
) {
24+
this.context = context
25+
this.logger = logger
26+
this.imageRepository = imageRepository
27+
this.options = new RolloutOpenShiftDeploymentOptions(config)
28+
}
29+
30+
@Override
31+
Map<String, List<PodData>> deploy() {
32+
def targetProject = context.targetProject
33+
if (options.helmValues && options.helmValues['namespaceOverride']) {
34+
targetProject = options.helmValues['namespaceOverride']
35+
logger.info("Override namespace deployment to ${targetProject}")
36+
}
37+
logger.info("Retagging images for ${targetProject}")
38+
imageRepository.retagImages(targetProject, getBuiltImages(), options.imageTag, options.imageTag)
39+
logger.info("ECR-only deployment configured, skipping Helm/OpenShift rollout.")
40+
return [:]
41+
}
42+
43+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.ods.component
2+
3+
import com.cloudbees.groovy.cps.NonCPS
4+
import groovy.transform.TypeChecked
5+
import groovy.transform.TypeCheckingMode
6+
7+
/**
8+
* Centralises the default configuration values shared by Helm-based deployment
9+
* stages and strategies. Call {@link #applyDefaults} once with the pipeline
10+
* context and the user-supplied config map; values that were not explicitly set
11+
* by the user will be filled in with sensible defaults.
12+
*/
13+
@TypeChecked
14+
class HelmDeploymentConfig {
15+
16+
@NonCPS
17+
@TypeChecked(TypeCheckingMode.SKIP)
18+
static void applyDefaults(IContext context, Map<String, Object> config) {
19+
if (!config.selector) {
20+
config.selector = context.selector
21+
}
22+
if (!config.imageTag) {
23+
config.imageTag = context.shortGitCommit
24+
}
25+
if (!config.deployTimeoutMinutes) {
26+
config.deployTimeoutMinutes = context.openshiftRolloutTimeout ?: 15
27+
}
28+
if (!config.deployTimeoutRetries) {
29+
config.deployTimeoutRetries = context.openshiftRolloutTimeoutRetries ?: 5
30+
}
31+
if (!config.chartDir) {
32+
config.chartDir = 'chart'
33+
}
34+
if (!config.containsKey('helmReleaseName')) {
35+
config.helmReleaseName = context.componentId
36+
}
37+
if (!config.containsKey('helmValues')) {
38+
config.helmValues = [:]
39+
}
40+
if (!config.containsKey('helmValuesFiles')) {
41+
config.helmValuesFiles = ['values.yaml']
42+
}
43+
if (!config.containsKey('helmEnvBasedValuesFiles')) {
44+
config.helmEnvBasedValuesFiles = []
45+
}
46+
if (!config.containsKey('helmDefaultFlags')) {
47+
config.helmDefaultFlags = ['--install', '--atomic']
48+
}
49+
if (!config.containsKey('helmAdditionalFlags')) {
50+
config.helmAdditionalFlags = []
51+
}
52+
if (!config.containsKey('helmDiff')) {
53+
config.helmDiff = true
54+
}
55+
if (!config.helmPrivateKeyCredentialsId) {
56+
config.helmPrivateKeyCredentialsId = "${context.cdProject}-helm-private-key"
57+
}
58+
if (!config.containsKey('helmReleasesHistoryLimit')) {
59+
config.helmReleasesHistoryLimit = 5
60+
}
61+
}
62+
63+
}

src/org/ods/component/HelmDeploymentStrategy.groovy

Lines changed: 27 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package org.ods.component
22

33
import groovy.transform.TypeChecked
44
import groovy.transform.TypeCheckingMode
5+
import org.ods.orchestration.util.MROPipelineUtil
56
import org.ods.services.JenkinsService
67
import org.ods.services.OpenShiftService
78
import org.ods.util.HelmStatus
@@ -17,6 +18,8 @@ class HelmDeploymentStrategy extends AbstractDeploymentStrategy {
1718
private final JenkinsService jenkins
1819
private final ILogger logger
1920
private final IPipelineSteps steps
21+
private final IImageRepository imageRepository
22+
2023
// assigned in constructor
2124
private final RolloutOpenShiftDeploymentOptions options
2225

@@ -27,57 +30,17 @@ class HelmDeploymentStrategy extends AbstractDeploymentStrategy {
2730
Map<String, Object> config,
2831
OpenShiftService openShift,
2932
JenkinsService jenkins,
33+
IImageRepository imageRepository,
3034
ILogger logger
3135
) {
32-
if (!config.selector) {
33-
config.selector = context.selector
34-
}
35-
if (!config.imageTag) {
36-
config.imageTag = context.shortGitCommit
37-
}
38-
if (!config.deployTimeoutMinutes) {
39-
config.deployTimeoutMinutes = context.openshiftRolloutTimeout ?: 15
40-
}
41-
if (!config.deployTimeoutRetries) {
42-
config.deployTimeoutRetries = context.openshiftRolloutTimeoutRetries ?: 5
43-
}
44-
// Helm options
45-
if (!config.chartDir) {
46-
config.chartDir = 'chart'
47-
}
48-
if (!config.containsKey('helmReleaseName')) {
49-
config.helmReleaseName = context.componentId
50-
}
51-
if (!config.containsKey('helmValues')) {
52-
config.helmValues = [:]
53-
}
54-
if (!config.containsKey('helmValuesFiles')) {
55-
config.helmValuesFiles = ['values.yaml']
56-
}
57-
if (!config.containsKey('helmEnvBasedValuesFiles')) {
58-
config.helmEnvBasedValuesFiles = []
59-
}
60-
// helmDefaultFlags are always set and cannot be overridden
61-
config.helmDefaultFlags = ['--install', '--atomic']
62-
if (!config.containsKey('helmAdditionalFlags')) {
63-
config.helmAdditionalFlags = []
64-
}
65-
if (!config.containsKey('helmDiff')) {
66-
config.helmDiff = true
67-
}
68-
if (!config.helmPrivateKeyCredentialsId) {
69-
config.helmPrivateKeyCredentialsId = "${context.cdProject}-helm-private-key"
70-
}
71-
if (!config.containsKey('helmReleasesHistoryLimit')) {
72-
config.helmReleasesHistoryLimit = 5
73-
}
36+
HelmDeploymentConfig.applyDefaults(context, config)
7437
this.context = context
7538
this.logger = logger
7639
this.steps = steps
77-
7840
this.options = new RolloutOpenShiftDeploymentOptions(config)
7941
this.openShift = openShift
8042
this.jenkins = jenkins
43+
this.imageRepository = imageRepository
8144
}
8245

8346
@Override
@@ -86,13 +49,19 @@ class HelmDeploymentStrategy extends AbstractDeploymentStrategy {
8649
logger.warn 'Skipping because of empty (target) environment ...'
8750
return [:]
8851
}
89-
90-
// Tag images which have been built in this pipeline from cd project into target project
91-
retagImages(context.targetProject, getBuiltImages())
52+
// Maybe we need to deploy to another namespace
53+
// (ie we want to deploy a monitoring stack into a specific namespace)
54+
def targetProject = context.targetProject
55+
if (options.helmValues['namespaceOverride']) {
56+
targetProject = options.helmValues['namespaceOverride']
57+
logger.info("Override namespace deployment to ${targetProject} ")
58+
}
59+
logger.info("Retagging images for ${targetProject} ")
60+
imageRepository.retagImages(targetProject, getBuiltImages(), options.imageTag, options.imageTag)
9261

9362
logger.info("Rolling out ${context.componentId} with HELM, selector: ${options.selector}")
94-
helmUpgrade(context.targetProject)
95-
HelmStatus helmStatus = openShift.helmStatus(context.targetProject, options.helmReleaseName)
63+
helmUpgrade(targetProject)
64+
HelmStatus helmStatus = openShift.helmStatus(targetProject, options.helmReleaseName)
9665
if (logger.debugMode) {
9766
def helmStatusMap = helmStatus.toMap()
9867
logger.debug("${this.class.name} -- HELM STATUS: ${helmStatusMap}")
@@ -102,8 +71,12 @@ class HelmDeploymentStrategy extends AbstractDeploymentStrategy {
10271
// // we assume that Helm does "Deployment" that should work for most
10372
// // cases since they don't have triggers.
10473
// metadataSvc.updateMetadata(false, deploymentResources)
105-
def rolloutData = getRolloutData(helmStatus)
106-
return rolloutData
74+
Map<String, List<PodData>> rolloutData = [:]
75+
if (steps.env.repoType == MROPipelineUtil.PipelineConfig.REPO_TYPE_ODS_INFRA) {
76+
return rolloutData
77+
} else {
78+
return getRolloutData(helmStatus, targetProject)
79+
}
10780
}
10881

10982
private void helmUpgrade(String targetProject) {
@@ -167,7 +140,7 @@ class HelmDeploymentStrategy extends AbstractDeploymentStrategy {
167140
// ]
168141
@TypeChecked(TypeCheckingMode.SKIP)
169142
private Map<String, List<PodData>> getRolloutData(
170-
HelmStatus helmStatus
143+
HelmStatus helmStatus, String targetProject
171144
) {
172145
Map<String, List<PodData>> rolloutData = [:]
173146

@@ -183,7 +156,7 @@ class HelmDeploymentStrategy extends AbstractDeploymentStrategy {
183156
names.each { name ->
184157
// Get container images directly from the resource spec (deployment/statefulset/cronjob)
185158
def containers = openShift.getContainerImagesWithNameFromPodSpec(
186-
context.targetProject, kind, name
159+
targetProject, kind, name
187160
)
188161
logger.debug("Helm container images for ${kind}/${name}: ${containers}")
189162

@@ -201,7 +174,7 @@ class HelmDeploymentStrategy extends AbstractDeploymentStrategy {
201174
def deploymentMean = [
202175
type: 'helm',
203176
selector: options.selector,
204-
namespace: context.targetProject,
177+
namespace: targetProject,
205178
chartDir: options.chartDir,
206179
helmReleaseName: options.helmReleaseName,
207180
helmEnvBasedValuesFiles: options.helmEnvBasedValuesFiles,
@@ -252,4 +225,4 @@ class HelmDeploymentStrategy extends AbstractDeploymentStrategy {
252225
return rolloutData
253226
}
254227

255-
}
228+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.ods.component
2+
3+
interface IImageRepository {
4+
5+
void retagImages(String targetProject, Set<String> images, String sourceTag, String targetTag)
6+
7+
}

0 commit comments

Comments
 (0)