Skip to content

Commit 8db8fe8

Browse files
authored
[CI] support sending a PR to each ecs logging agent when spec changes (#47)
1 parent c7184a6 commit 8db8fe8

File tree

3 files changed

+225
-0
lines changed

3 files changed

+225
-0
lines changed

.ci/.jenkins-loggers.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
loggers:
3+
- REPO: "ecs-dotnet"
4+
SPEC_FILEPATH: "tests/Elastic.CommonSchema.Tests/Specs/spec.json"
5+
- REPO: "ecs-logging-go-logrus"
6+
SPEC_FILEPATH: "internal/spec/v1.json"
7+
- REPO: "ecs-logging-go-zap"
8+
SPEC_FILEPATH: "internal/spec/v1.json"
9+
- REPO: "ecs-logging-java"
10+
SPEC_FILEPATH: "ecs-logging-core/src/test/resources/spec/spec.json"
11+
- REPO: "ecs-logging-nodejs"
12+
SPEC_FILEPATH: "utils/ecs-logging/spec.json"
13+
- REPO: "ecs-logging-python"
14+
SPEC_FILEPATH: "tests/resources/spec.json"
15+
- REPO: "ecs-logging-ruby"
16+
SPEC_FILEPATH: "spec/fixtures/spec/spec.json"

.ci/Jenkinsfile

Lines changed: 187 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,187 @@
1+
// Licensed to Elasticsearch B.V. under one or more contributor
2+
// license agreements. See the NOTICE file distributed with
3+
// this work for additional information regarding copyright
4+
// ownership. Elasticsearch B.V. licenses this file to you under
5+
// the Apache License, Version 2.0 (the "License"); you may
6+
// not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
@Library('apm@current') _
19+
20+
pipeline {
21+
agent { label 'linux && immutable' }
22+
environment {
23+
REPO = 'ecs-logging'
24+
BASE_DIR = "src/github.com/elastic/${env.REPO}"
25+
HOME = "${env.WORKSPACE}"
26+
NOTIFY_TO = credentials('notify-to')
27+
JOB_GCS_BUCKET = credentials('gcs-bucket')
28+
JOB_GIT_CREDENTIALS = "f6c7695a-671e-4f4f-a331-acdce44ff9ba"
29+
PATH = "${env.PATH}:${env.WORKSPACE}/bin"
30+
PIPELINE_LOG_LEVEL = 'INFO'
31+
ECS_REPO = "${params?.ECS_REPO}"
32+
}
33+
options {
34+
timeout(time: 3, unit: 'HOURS')
35+
buildDiscarder(logRotator(numToKeepStr: '5', artifactNumToKeepStr: '5'))
36+
timestamps()
37+
ansiColor('xterm')
38+
disableResume()
39+
durabilityHint('PERFORMANCE_OPTIMIZED')
40+
}
41+
triggers {
42+
cron('H H(4-5) * * 1,5')
43+
}
44+
parameters {
45+
booleanParam(name: 'DRY_RUN_MODE', defaultValue: false, description: 'If true, allows to execute this pipeline in dry run mode, without sending a PR.')
46+
booleanParam(name: 'FORCE_SEND_PR', defaultValue: false, description: 'If true, will force sending a PR, although it could be affected by the value off the DRY_RUN parameter: if the latter is true, a message will be printed in the console.')
47+
choice(name: 'ECS_REPO', choices: ['all',
48+
'ecs-dotnet',
49+
'ecs-logging-go-logrus',
50+
'ecs-logging-go-zap',
51+
'ecs-logging-java',
52+
'ecs-logging-nodejs',
53+
'ecs-logging-python',
54+
'ecs-logging-ruby'], description: 'Name of the ECS repo you want to update its specs.')
55+
}
56+
stages {
57+
stage('Checkout'){
58+
steps {
59+
deleteDir()
60+
gitCheckout(basedir: "${BASE_DIR}",
61+
repo: "[email protected]:elastic/${REPO}.git",
62+
credentialsId: "${JOB_GIT_CREDENTIALS}"
63+
)
64+
stash allowEmpty: true, name: 'source', useDefaultExcludes: false
65+
}
66+
}
67+
// This stage will populate the environment, and will only be executed under any of the
68+
// following conditions:
69+
// 1. we run the pipeline NOT in DRY_RUN_MODE, because we want to send real PRs
70+
// 2. we run the pipeline forcing sending real PRs, because we want so
71+
// Because the rest of the following stages will need these variables to check for changes,
72+
// skipping this stage would not take effect in them, as they are covered by the
73+
// FORCE_SEND_PR check.
74+
stage('Check for spec changes'){
75+
when {
76+
beforeAgent true
77+
anyOf {
78+
expression { return env.DRY_RUN_MODE == "false" }
79+
expression { return params.FORCE_SEND_PR }
80+
}
81+
}
82+
environment {
83+
// GIT_PREVIOUS_SUCCESSFUL_COMMIT might point to a local merge commit instead a commit in the
84+
// origin, then let's use the target branch for PRs and the GIT_PREVIOUS_SUCCESSFUL_COMMIT for
85+
// branches.
86+
COMMIT_FROM = """${isPR() ? "origin/${env.CHANGE_TARGET}" : "${env.GIT_PREVIOUS_SUCCESSFUL_COMMIT}"}"""
87+
}
88+
steps {
89+
deleteDir()
90+
unstash 'source'
91+
script {
92+
dir("${BASE_DIR}"){
93+
regexps =[
94+
"^spec/spec.json"
95+
]
96+
env.SPECS_UPDATED = isGitRegionMatch(
97+
from: "${env.COMMIT_FROM}",
98+
patterns: regexps)
99+
env.PR_DESCRIPTION = createPRDescription(env.COMMIT_FROM)
100+
}
101+
}
102+
}
103+
}
104+
stage('Send Pull Request for JSON specs'){
105+
options {
106+
warnError('Pull Requests to ECS logging repos failed')
107+
}
108+
when {
109+
beforeAgent true
110+
anyOf {
111+
expression { return env.SPECS_UPDATED == "true" }
112+
expression { return params.FORCE_SEND_PR }
113+
}
114+
}
115+
steps {
116+
deleteDir()
117+
unstash 'source'
118+
dir("${BASE_DIR}"){
119+
generateSteps()
120+
}
121+
}
122+
}
123+
}
124+
post {
125+
cleanup {
126+
notifyBuildResult()
127+
}
128+
}
129+
}
130+
131+
def generateSteps() {
132+
def loggers = readYaml(file: '.ci/.jenkins-loggers.yml')
133+
def parallelTasks = [:]
134+
loggers['loggers'].each { logger ->
135+
if (logger.SPEC_FILEPATH.trim()) {
136+
if (env.ECS_REPO == 'all' || env.ECS_REPO == logger.REPO) {
137+
parallelTasks["${logger.REPO}"] = generateStep(repo: "${logger.REPO}", filePath: "${logger.SPEC_FILEPATH}")
138+
}
139+
}
140+
}
141+
parallel(parallelTasks)
142+
}
143+
144+
def generateStep(Map args = [:]){
145+
def repo = args.containsKey('repo') ? args.get('repo') : error('generateStep: repo argument is required')
146+
def filePath = args.containsKey('filePath') ? args.get('filePath') : error('generateStep: filePath argument is required')
147+
return {
148+
node('linux && immutable') {
149+
catchError(buildResult: 'SUCCESS', stageResult: 'UNSTABLE') {
150+
deleteDir()
151+
unstash 'source'
152+
dir("${BASE_DIR}"){
153+
setupAPMGitEmail(global: true)
154+
sh script: """.ci/scripts/prepare-spec-changes.sh "${repo}" "${filePath}" """, label: "Prepare changes for ${repo}"
155+
dir(".ci/${repo}") {
156+
if (params.DRY_RUN_MODE || isPR()) {
157+
echo "DRY-RUN: ${repo} with description: '${env.PR_DESCRIPTION}'"
158+
} else {
159+
githubCreatePullRequest(title: "test: synchronizing spec", labels: 'automation', description: "${env.PR_DESCRIPTION}")
160+
}
161+
}
162+
}
163+
}
164+
}
165+
}
166+
}
167+
168+
def createPRDescription(commit) {
169+
def message = """
170+
### What
171+
ECS logging specs automatic sync
172+
173+
### Why
174+
"""
175+
if (params.FORCE_SEND_PR) {
176+
message += "*Manually forced with the CI automation job.*"
177+
}
178+
if (env?.SPEC_UPDATED?.equals('true')){
179+
def gitLog = sh(script: """
180+
git log --pretty=format:'* https://github.com/${env.ORG_NAME}/${env.ECS_REPO}/commit/%h %s' \
181+
${commit}...HEAD \
182+
--follow -- spec \
183+
| sed 's/#\\([0-9]\\+\\)/https:\\/\\/github.com\\/${env.ORG_NAME}\\/${env.ECS_REPO}\\/pull\\/\\1/g' || true""", returnStdout: true)
184+
message += "*Changeset*\n${gitLog}"
185+
}
186+
return message
187+
}

.ci/scripts/prepare-spec-changes.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/usr/bin/env bash
2+
3+
set -uexo pipefail
4+
5+
readonly REPO_NAME=${1}
6+
readonly SPECS_FILEPATH=${2}
7+
readonly REPO_DIR=".ci/${REPO_NAME}"
8+
9+
git clone "https://github.com/elastic/${REPO_NAME}" "${REPO_DIR}"
10+
11+
SPECS_DIR=$(dirname "${SPECS_FILEPATH}")
12+
mkdir -p "${REPO_DIR}/${SPECS_DIR}"
13+
14+
echo "Copying files to the ${REPO_NAME} repo"
15+
cp -f spec/spec.json "${REPO_DIR}/${SPECS_FILEPATH}"
16+
17+
cd "${REPO_DIR}"
18+
git config user.email
19+
git checkout -b "update-spec-files-$(date "+%Y%m%d%H%M%S")"
20+
git add "${SPECS_FILEPATH}"
21+
git commit -m "test: synchronizing specs"
22+
git --no-pager log -1

0 commit comments

Comments
 (0)