Skip to content

Commit e1bba4f

Browse files
merllsvcAPLBot
andauthored
ci: update apps.yaml with charts (#2270)
Co-authored-by: svcAPLBot <[email protected]>
1 parent 044a662 commit e1bba4f

File tree

2 files changed

+80
-13
lines changed

2 files changed

+80
-13
lines changed

apps.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ appsInfo:
4242
license: Apache 2.0
4343
about: CloudNative PostgreSQL is an open source operator designed to manage PostgreSQL workloads on any supported Kubernetes cluster running in private, public, hybrid, or multi-cloud environments.
4444
integration: CloudNativePG is used by APL to provide Postgresql database for various applications. In the values you can configure a storageprovider for backups. The backups can be enabled in settings.
45+
chartName: cloudnative-pg
4546
drone:
4647
title: Drone
4748
appVersion: 2.7.3
@@ -153,6 +154,7 @@ appsInfo:
153154
license: Apache 2.0
154155
about: Istio is an open platform for providing a uniform way to integrate microservices, manage traffic flow across microservices, enforce policies and aggregate telemetry data. Istio's control plane provides an abstraction layer over the underlying cluster management platform.
155156
integration: APL has security best practices built in, and is designed for intrusion. Istio is used by APL as a service mesh to deliver mTLS enforcement for all traffic that is deemed compromisable, egress control to force teams to choose explicit egress endpoints, and advanced routing capabilities such as weight based load balancing (A/B or blue/green testing). Istio is part of the core of APL and can not be disabled.
157+
chartName: istiod
156158
jaeger:
157159
title: Jaeger Operator
158160
dependencies: Open Telemetry (otel)
@@ -186,6 +188,7 @@ appsInfo:
186188
dependencies: Prometheus
187189
about: Kiali is a management console for Istio to manage, visualize, validate and troubleshoot the service mesh.
188190
integration: Kiali can be activated to gain observability insights on its network traffic. Kiali runs in anonymous mode and each authenticated user is given the same authorization, allowing them to see everything.
191+
chartName: kiali-operator
189192
knative:
190193
title: Knative Operator
191194
appVersion: 1.18.1
@@ -196,6 +199,7 @@ appsInfo:
196199
license: Apache 2.0
197200
about: Knative Serving builds on Kubernetes to support deploying and serving of applications and functions as serverless containers. Serving is easy to get started with and scales to support advanced scenarios.
198201
integration: Knative serving can be activated to deliver Container-as-a-Service (CaaS) functionality with a scale-to-zero option. It can be compared to Functions-as-a-service (FaaS) but is container oriented, and takes only one manifest to configure an auto scaling service based on a container image of choice. APL offers an on-the-fly Knative service deployment, making it very easy to deploy containerized services without the hassle of providing all the supporting resources involved with Helm charts. Istio Virtual Services are used to route traffic coming in for a public domain to its backing Knative Service, allowing it to set a custom domain.
202+
chartName: knative-operator
199203
kyverno:
200204
title: Kyverno
201205
appVersion: 1.11.4
@@ -229,6 +233,7 @@ appsInfo:
229233
dependencies: Harbor
230234
about: Tekton Pipelines provides Kubernetes custom resources for declaring CI/CD-style pipelines.
231235
integration: APL uses Tekton to proivide pre-build pipelines using the git-clone, buildpacks and kaniko tasks to build images from source code and push the created images to Harbor.
236+
chartName: tekton-pipelines
232237
loki:
233238
title: Loki
234239
appVersion: 2.9.10
@@ -317,6 +322,7 @@ appsInfo:
317322
dependencies: Prometheus, Grafana
318323
about: Trivy Operator continuously scans your Kubernetes cluster for security issues, and generates security reports as Kubernetes Custom Resources. It does it by watching Kubernetes for state changes and automatically triggering scans in response to changes.
319324
integration: APL installs and configures Trivy Operator to scan all resources deployed by a team and makes results visible in a Grafana dashboard.
325+
chartName: trivy-operator
320326
otel:
321327
title: Open Telemetry Operator
322328
appVersion: 0.80.0
@@ -328,6 +334,7 @@ appsInfo:
328334
dependencies: Prometheus, Grafana, Loki, Tempo
329335
about: The OpenTelemetry Collector offers a vendor-agnostic implementation on how to receive, process and export telemetry data. In addition, it removes the need to run, operate and maintain multiple agents/collectors in order to support open-source telemetry data formats (e.g. Jaeger, Prometheus, etc.) to multiple open-source or commercial back-ends.
330336
integration: OpenTelemetry Collector is used to receive telementry data from Istio Envoy access logs and export this data to Tempo.
337+
chartName: otel-operator
331338
velero:
332339
title: Velero
333340
appVersion: 1.9.0

ci/src/update-helm-chart-deps.mjs

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import yaml from 'js-yaml'
77
import semver from 'semver'
88
import { $ } from 'zx'
99

10-
export function isVersionApplicable(currentVersion, version, allowedUpgradeType) {
10+
function isVersionApplicable(currentVersion, version, allowedUpgradeType) {
1111
if (semver.lte(version, currentVersion)) {
1212
return false // Ignore versions that are <= current version
1313
}
@@ -22,6 +22,16 @@ export function isVersionApplicable(currentVersion, version, allowedUpgradeType)
2222
return true // Default: Allow all upgrades
2323
}
2424

25+
async function loadYamlFile(fileName) {
26+
const yamlContent = await fs.readFile(fileName, 'utf8')
27+
return yaml.load(yamlContent)
28+
}
29+
30+
async function writeYamlFile(fileName, data) {
31+
const yamlContent = yaml.dump(data, { lineWidth: 1000 })
32+
await fs.writeFile(fileName, yamlContent, 'utf8')
33+
}
34+
2535
async function main() {
2636
config()
2737
const env = envalid.cleanEnv(process.env, {
@@ -39,6 +49,7 @@ async function main() {
3949
// Path to the Chart.yaml file
4050
const chartFile = '../chart/chart-index/Chart.yaml'
4151
const chartsDir = '../charts'
52+
const appsFile = '../apps.yaml'
4253

4354
// Specify allowed upgrade types: 'minor', 'patch', or leave undefined for all
4455
const allowedUpgradeType = env.CI_UPDATE_TYPE
@@ -51,30 +62,39 @@ async function main() {
5162

5263
try {
5364
// Read the Chart.yaml file
54-
const chartContent = await fs.readFile(chartFile, 'utf8')
55-
const chart = yaml.load(chartContent)
65+
const chart = await loadYamlFile(chartFile)
5666
const dependencyErrors = {}
5767
const fixedChartVersions = {}
5868

59-
if (!chart.dependencies || !Array.isArray(chart.dependencies)) {
69+
if (!Array.isArray(chart.dependencies) || chart.dependencies.length === 0) {
6070
console.error('No dependencies found in Chart.yaml')
6171
process.exit(1)
6272
}
6373

74+
const apps = await loadYamlFile(appsFile)
75+
const appsInfo = apps.appsInfo
76+
if (!appsInfo || Object.keys(appsInfo).length === 0) {
77+
console.error('No app information found in apps.yaml')
78+
process.exit(1)
79+
}
80+
// Mapping to look up / update apps info by chart
81+
const chartApps = Object.fromEntries(
82+
Object.entries(appsInfo).map(([appName, appInfo]) => [appInfo.chartName || appName, appInfo])
83+
)
84+
6485
for (const dependency of chart.dependencies) {
6586
const currentDependencyVersion = dependency.version
66-
if (dependencyNameFilter.length != 0 && !dependencyNameFilter.includes(dependency.name)) {
87+
if (dependencyNameFilter.length !== 0 && !dependencyNameFilter.includes(dependency.name)) {
6788
console.log(
6889
`Skipping updates for dependency: ${dependency.name} due to dependencyNameFilter: ${dependencyNameFilter} `,
6990
)
7091
continue
7192
}
7293

7394
console.log(`Pre-check for dependency ${dependency.name}`)
95+
const dependencyFileName = `${chartsDir}/${dependency.alias || dependency.name}/Chart.yaml`
7496
try {
75-
const dependencyFileName = `${chartsDir}/${dependency.alias || dependency.name}/Chart.yaml`
76-
const dependencyFile = await fs.readFile(dependencyFileName, 'utf8')
77-
const dependencyChart = yaml.load(dependencyFile)
97+
const dependencyChart = await loadYamlFile(dependencyFileName)
7898
if (dependencyChart.version !== currentDependencyVersion) {
7999
console.error(`Skipping update, indexed version of dependency ${dependency.name} is not consistent with chart version.`)
80100
dependencyErrors[dependency.name] = 'Indexed version of dependency is not consistent with chart version.'
@@ -143,8 +163,7 @@ async function main() {
143163
}
144164

145165
// Write the updated Chart.yaml file
146-
const updatedChart = yaml.dump(chart)
147-
await fs.writeFile(chartFile, updatedChart, 'utf8')
166+
await writeYamlFile(chartFile, chart)
148167
// Fetch and unpack the new chart version
149168
const tempDir = `./tmp/charts/${dependency.name}`
150169
await $`mkdir -p ${tempDir}`
@@ -159,6 +178,35 @@ async function main() {
159178
await $`tar -xzvf ${tempDir}/${dependency.name}-${latestVersion}.tgz -C ${chartsDir}`
160179
}
161180

181+
const appInfo = chartApps[dependency.name]
182+
// By default create a draft PR only if appInfo is not found for chart
183+
let setPrDraft = Boolean(!appInfo)
184+
if (appInfo) {
185+
console.log(`Chart ${dependency.name} assigned to app – looking up new version`)
186+
try {
187+
const dependencyChart = await loadYamlFile(dependencyFileName)
188+
const updatedAppVersion = dependencyChart?.appVersion
189+
if (updatedAppVersion) {
190+
appInfo.appVersion = updatedAppVersion.replace(/^v/, '')
191+
try {
192+
await writeYamlFile(appsFile, apps)
193+
await $`git add ${appsFile}`
194+
} catch (error) {
195+
console.error(`Error updating app version for ${dependency.name}:`, error)
196+
setPrDraft = true
197+
}
198+
} else {
199+
console.info(`Updated app version not found in chart ${dependency.name}`)
200+
setPrDraft = true
201+
}
202+
} catch (error) {
203+
console.error(`Error checking dependency app version ${dependency.name}:`, error)
204+
setPrDraft = true
205+
}
206+
} else {
207+
console.log(`No app found for ${dependency.name}`)
208+
}
209+
162210
if (ciCreateFeatureBranch) {
163211
await $`git add ${chartFile}`
164212
await $`git add ${chartsDir}`
@@ -171,7 +219,20 @@ async function main() {
171219
if (ciCreateGithubPr) {
172220
// Create a pull request
173221
const prBody = `This PR updates the dependency **${dependency.name}** to version **${latestVersion}**.`
174-
await $`gh pr create --title ${commitMessage} --body "${prBody}" --base ${baseBranch} --head ${branchName}`
222+
const args = [
223+
'--title',
224+
commitMessage,
225+
'--body',
226+
prBody,
227+
'--base',
228+
baseBranch,
229+
'--head',
230+
branchName,
231+
]
232+
if (setPrDraft) {
233+
args.push('--draft')
234+
}
235+
await $`gh pr create ${args}`
175236
}
176237
} catch (error) {
177238
console.error('Error updating dependencies:', error)
@@ -203,8 +264,7 @@ async function main() {
203264
}
204265
}
205266
// Write the updated Chart.yaml file
206-
const updatedChart = yaml.dump(chart)
207-
await fs.writeFile(chartFile, updatedChart, 'utf8')
267+
await writeYamlFile(chartFile, chart)
208268
}
209269
} catch (error) {
210270
console.error('Error updating dependencies:', error)

0 commit comments

Comments
 (0)