Skip to content

Commit 2708573

Browse files
committed
Merge branch 'master' into sarahchen6/implement-48h-cooldown-for-gradle-dependencies
2 parents 012c4d9 + 15141ae commit 2708573

86 files changed

Lines changed: 1014 additions & 67 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@
2121
/dd-smoke-tests/vertx-*/ @DataDog/apm-idm-java
2222
/dd-smoke-tests/wildfly/ @DataDog/apm-idm-java
2323

24-
# @DataDog/apm-release-platform
25-
/.gitlab/ @DataDog/apm-release-platform
26-
/.gitlab-ci.yml @DataDog/apm-release-platform
27-
2824
# @DataDog/apm-sdk-capabilities-java
2925
/dd-java-agent/agent-otel @DataDog/apm-sdk-capabilities-java
3026
/dd-smoke-tests/log-injection @DataDog/apm-sdk-capabilities-java
@@ -56,6 +52,8 @@
5652

5753
# @DataDog/apm-lang-platform-java
5854
/.github/ @DataDog/apm-lang-platform-java
55+
/.gitlab/ @DataDog/apm-lang-platform-java
56+
/.gitlab-ci.yml @DataDog/apm-lang-platform-java
5957
/benchmark/ @DataDog/apm-lang-platform-java
6058
/components/ @DataDog/apm-lang-platform-java
6159
/dd-java-agent/instrumentation/java/ @DataDog/apm-lang-platform-java

.github/scripts/dependency_age.py

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ def parse_args() -> argparse.Namespace:
6767
def add_common_selection_args(parser: argparse.ArgumentParser) -> None:
6868
parser.add_argument("--min-age-hours", type=int, default=default_min_age_hours())
6969
parser.add_argument("--now")
70+
parser.add_argument("--current-version", default=None)
7071
parser.add_argument("--github-output", default=None)
7172

7273

@@ -117,6 +118,11 @@ def format_datetime(value: datetime) -> str:
117118
return value.astimezone(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
118119

119120

121+
# normalize datetime to YYYY-MM-DD date for more readable PR comment outputs
122+
def format_date(value: datetime) -> str:
123+
return value.astimezone(timezone.utc).strftime("%Y-%m-%d")
124+
125+
120126
# emit key=value lines to stdout and GitHub Actions output file
121127
def emit_outputs(outputs: dict[str, Any], github_output: str | None) -> None:
122128
lines = [f"{key}={'' if value is None else value}" for key, value in outputs.items()]
@@ -166,6 +172,7 @@ def select_gradle_release(args: argparse.Namespace) -> int:
166172
not_found_reason=(
167173
f"No eligible stable Gradle release is at least {args.min_age_hours} hours old."
168174
),
175+
current_version=args.current_version,
169176
)
170177

171178

@@ -199,6 +206,7 @@ def select_maven_release(args: argparse.Namespace) -> int:
199206
f"No eligible stable release found for {args.group_id}:{args.artifact_id} "
200207
f"that is at least {args.min_age_hours} hours old."
201208
),
209+
current_version=args.current_version,
202210
)
203211

204212

@@ -250,15 +258,24 @@ def load_maven_documents(
250258

251259
# parse a version string into a sortable tuple for comparison; numeric segments sort before non-numeric
252260
def _version_sort_key(version: str) -> tuple:
253-
parts = []
261+
segments = []
254262
for segment in re.split(r"([.\-])", version):
255263
if segment in {"", ".", "-"}:
256264
continue
257265
try:
258-
parts.append((0, int(segment)))
266+
segments.append((0, int(segment)))
259267
except ValueError:
260-
parts.append((1, segment))
261-
return tuple(parts)
268+
segments.append((1, segment))
269+
270+
release = []
271+
prerelease = []
272+
for i, seg in enumerate(segments):
273+
if seg[0] == 1: # first string segment starts the prerelease part
274+
prerelease = segments[i:]
275+
break
276+
release.append(seg)
277+
278+
return (tuple(release), not bool(prerelease), tuple(prerelease))
262279

263280

264281
# emit selection result to stdout and GitHub Actions output file for select-gradle and select-maven
@@ -269,11 +286,37 @@ def emit_selection_result(
269286
github_output: str | None,
270287
candidates: list[Candidate],
271288
not_found_reason: str,
289+
current_version: str | None = None,
272290
) -> int:
273291
selected = max(candidates, key=lambda candidate: _version_sort_key(candidate.version), default=None)
274-
outputs: dict[str, Any] = {
275-
"cutoff_at": format_datetime(cutoff),
276-
}
292+
outputs: dict[str, Any] = {}
293+
294+
# If the current version is already >= the best candidate, keep it
295+
if current_version and (
296+
not selected
297+
or _version_sort_key(current_version) >= _version_sort_key(selected.version)
298+
):
299+
outputs.update(
300+
{
301+
"found": "true",
302+
"version": current_version,
303+
"published_at": "",
304+
"reason": "",
305+
}
306+
)
307+
emit_outputs(outputs, github_output)
308+
if selected:
309+
print(
310+
f"Current version {current_version} for {label} is already >= "
311+
f"latest eligible {selected.version}; keeping current version."
312+
)
313+
else:
314+
print(
315+
f"No eligible version found for {label}; "
316+
f"keeping current version {current_version}."
317+
)
318+
return 0
319+
277320
if not selected:
278321
outputs.update(
279322
{
@@ -291,14 +334,14 @@ def emit_selection_result(
291334
{
292335
"found": "true",
293336
"version": selected.version,
294-
"published_at": format_datetime(selected.published_at),
337+
"published_at": format_date(selected.published_at),
295338
"reason": "",
296339
}
297340
)
298341
emit_outputs(outputs, github_output)
299342
print(
300343
f"Selected latest eligible stable version for {label}: "
301-
f"{selected.version} (published {format_datetime(selected.published_at)}, cutoff {format_datetime(cutoff)})"
344+
f"{selected.version} (published {format_date(selected.published_at)})"
302345
)
303346
return 0
304347

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"response": {
3+
"docs": [
4+
{
5+
"v": "4.0.0",
6+
"timestamp": "2026-04-20T12:00:00Z"
7+
},
8+
{
9+
"v": "4.0.0-beta-3",
10+
"timestamp": "2026-04-18T12:00:00Z"
11+
},
12+
{
13+
"v": "3.9.8",
14+
"timestamp": "2026-04-15T12:00:00Z"
15+
}
16+
]
17+
}
18+
}

.github/scripts/tests/test_dependency_age.py

Lines changed: 99 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ def test_selects_previous_gradle_release_when_newest_is_too_new(self) -> None:
5151
self.assertEqual(result.returncode, 0, result.stderr)
5252
outputs = self.parse_outputs(result.stdout)
5353
self.assertEqual(outputs["version"], "9.4.1")
54-
self.assertEqual(outputs["published_at"], "2026-04-22T11:00:00Z")
55-
self.assertEqual(outputs["cutoff_at"], "2026-04-22T12:00:00Z")
54+
self.assertEqual(outputs["published_at"], "2026-04-22")
5655

5756
def test_reports_when_no_eligible_gradle_release_exists(self) -> None:
5857
result = self.run_script(
@@ -124,7 +123,104 @@ def test_exact_48_hour_boundary_is_accepted(self) -> None:
124123
self.assertEqual(result.returncode, 0, result.stderr)
125124
outputs = self.parse_outputs(result.stdout)
126125
self.assertEqual(outputs["version"], "3.5.5")
127-
self.assertEqual(outputs["published_at"], "2026-04-22T12:00:00Z")
126+
self.assertEqual(outputs["published_at"], "2026-04-22")
127+
128+
129+
def test_ga_version_overrides_current_prerelease(self) -> None:
130+
result = self.run_script(
131+
"select-maven",
132+
"--now",
133+
NOW,
134+
"--group-id",
135+
"org.apache.maven",
136+
"--artifact-id",
137+
"apache-maven",
138+
"--search-response-file",
139+
str(FIXTURES / "maven-ga-replaces-beta.json"),
140+
"--prerelease-pattern",
141+
"alpha",
142+
"--prerelease-pattern",
143+
"beta",
144+
"--prerelease-pattern",
145+
"rc",
146+
"--current-version",
147+
"4.0.0-beta-3",
148+
)
149+
150+
self.assertEqual(result.returncode, 0, result.stderr)
151+
outputs = self.parse_outputs(result.stdout)
152+
self.assertEqual(outputs["found"], "true")
153+
self.assertEqual(outputs["version"], "4.0.0")
154+
self.assertEqual(outputs["published_at"], "2026-04-20")
155+
156+
def test_keeps_current_version_when_higher_than_eligible(self) -> None:
157+
result = self.run_script(
158+
"select-maven",
159+
"--now",
160+
NOW,
161+
"--group-id",
162+
"org.apache.maven",
163+
"--artifact-id",
164+
"apache-maven",
165+
"--search-response-file",
166+
str(FIXTURES / "maven-newest-too-new.json"),
167+
"--prerelease-pattern",
168+
"alpha",
169+
"--prerelease-pattern",
170+
"beta",
171+
"--prerelease-pattern",
172+
"rc",
173+
"--current-version",
174+
"4.0.0-beta-3",
175+
)
176+
177+
self.assertEqual(result.returncode, 0, result.stderr)
178+
outputs = self.parse_outputs(result.stdout)
179+
self.assertEqual(outputs["found"], "true")
180+
self.assertEqual(outputs["version"], "4.0.0-beta-3")
181+
self.assertEqual(outputs["published_at"], "")
182+
183+
def test_updates_when_eligible_version_is_higher_than_current(self) -> None:
184+
result = self.run_script(
185+
"select-maven",
186+
"--now",
187+
NOW,
188+
"--group-id",
189+
"org.apache.maven.plugins",
190+
"--artifact-id",
191+
"maven-surefire-plugin",
192+
"--search-response-file",
193+
str(FIXTURES / "surefire-boundary.json"),
194+
"--prerelease-pattern",
195+
"alpha",
196+
"--prerelease-pattern",
197+
"beta",
198+
"--current-version",
199+
"3.5.4",
200+
)
201+
202+
self.assertEqual(result.returncode, 0, result.stderr)
203+
outputs = self.parse_outputs(result.stdout)
204+
self.assertEqual(outputs["found"], "true")
205+
self.assertEqual(outputs["version"], "3.5.5")
206+
self.assertEqual(outputs["published_at"], "2026-04-22")
207+
208+
def test_keeps_current_version_when_no_eligible_version_exists(self) -> None:
209+
result = self.run_script(
210+
"select-gradle",
211+
"--now",
212+
NOW,
213+
"--versions-file",
214+
str(FIXTURES / "gradle-no-eligible.json"),
215+
"--current-version",
216+
"9.0.0",
217+
)
218+
219+
self.assertEqual(result.returncode, 0, result.stderr)
220+
outputs = self.parse_outputs(result.stdout)
221+
self.assertEqual(outputs["found"], "true")
222+
self.assertEqual(outputs["version"], "9.0.0")
223+
self.assertEqual(outputs["published_at"], "")
128224

129225

130226
def run_validate_lockfiles(

.github/workflows/check-pull-request-labels.yaml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,11 @@ jobs:
141141
'performance:', // To refactor to 'ci: ' in the future
142142
'run-tests:' // Unused since GitLab migration
143143
]
144+
// Exact-match labels that don't fit a category prefix (e.g. labels applied
145+
// by external automation tooling).
146+
const exactAllowlist = [
147+
'campaigner-automated-change'
148+
]
144149
// Re-fetch labels only if the previous step modified them (ex: "Bits AI" removal)
145150
let prLabels
146151
if (process.env.LABELS_STALE === 'true') {
@@ -156,7 +161,10 @@ jobs:
156161
// Look for invalid labels
157162
const invalidLabels = prLabels
158163
.map(label => label.name)
159-
.filter(label => validCategories.every(prefix => !label.startsWith(prefix)))
164+
.filter(label =>
165+
!exactAllowlist.includes(label) &&
166+
validCategories.every(prefix => !label.startsWith(prefix))
167+
)
160168
const hasInvalidLabels = invalidLabels.length > 0
161169
// Get existing comments to check for blocking comment
162170
const comments = await github.rest.issues.listComments({

.github/workflows/update-smoke-test-latest-versions.yaml

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,22 @@ jobs:
2929
DATE=$(date +'%Y%m%d')
3030
echo "branch=ci/update-smoke-test-latest-versions-${DATE}" >> "$GITHUB_OUTPUT"
3131
32+
- name: Read current pinned versions
33+
id: current
34+
run: |
35+
gradle_props="dd-smoke-tests/gradle/src/test/resources/latest-tool-versions.properties"
36+
maven_props="dd-smoke-tests/maven/src/test/resources/latest-tool-versions.properties"
37+
get_prop() { grep "^$1=" "$2" 2>/dev/null | cut -d= -f2 || true; }
38+
echo "gradle_version=$(get_prop gradle.version "$gradle_props")" >> "$GITHUB_OUTPUT"
39+
echo "maven_version=$(get_prop maven.version "$maven_props")" >> "$GITHUB_OUTPUT"
40+
echo "surefire_version=$(get_prop maven-surefire.version "$maven_props")" >> "$GITHUB_OUTPUT"
41+
3242
- name: Resolve latest eligible Gradle version
3343
id: gradle
3444
run: |
3545
python3 .github/scripts/dependency_age.py select-gradle \
3646
--min-age-hours "${MIN_DEPENDENCY_AGE_HOURS}" \
47+
--current-version "${{ steps.current.outputs.gradle_version }}" \
3748
--github-output "$GITHUB_OUTPUT"
3849
3950
- name: Resolve latest eligible stable Maven version
@@ -46,6 +57,7 @@ jobs:
4657
--prerelease-pattern beta \
4758
--prerelease-pattern rc \
4859
--min-age-hours "${MIN_DEPENDENCY_AGE_HOURS}" \
60+
--current-version "${{ steps.current.outputs.maven_version }}" \
4961
--github-output "$GITHUB_OUTPUT"
5062
5163
- name: Resolve latest eligible stable Maven Surefire version
@@ -57,19 +69,29 @@ jobs:
5769
--prerelease-pattern alpha \
5870
--prerelease-pattern beta \
5971
--min-age-hours "${MIN_DEPENDENCY_AGE_HOURS}" \
72+
--current-version "${{ steps.current.outputs.surefire_version }}" \
6073
--github-output "$GITHUB_OUTPUT"
6174
6275
- name: Update properties files
76+
id: update
6377
env:
6478
GRADLE_VERSION: ${{ steps.gradle.outputs.version }}
79+
GRADLE_PUBLISHED: ${{ steps.gradle.outputs.published_at }}
6580
MAVEN_VERSION: ${{ steps.maven.outputs.version }}
81+
MAVEN_PUBLISHED: ${{ steps.maven.outputs.published_at }}
6682
SUREFIRE_VERSION: ${{ steps.surefire.outputs.version }}
83+
SUREFIRE_PUBLISHED: ${{ steps.surefire.outputs.published_at }}
6784
run: |
85+
version_line() { if [ -n "$2" ]; then echo "$1 (published $2)"; else echo "$1 (unchanged)"; fi; }
6886
echo "Writing latest eligible stable versions (>=${MIN_DEPENDENCY_AGE_HOURS}h old) to properties files:"
69-
echo " Gradle: ${GRADLE_VERSION} (published ${{ steps.gradle.outputs.published_at }})"
70-
echo " Maven: ${MAVEN_VERSION} (published ${{ steps.maven.outputs.published_at }})"
71-
echo " Maven Surefire: ${SUREFIRE_VERSION} (published ${{ steps.surefire.outputs.published_at }})"
72-
echo " Eligibility cutoff: ${{ steps.gradle.outputs.cutoff_at }}"
87+
echo " Gradle: $(version_line "${GRADLE_VERSION}" "${GRADLE_PUBLISHED}")"
88+
echo " Maven: $(version_line "${MAVEN_VERSION}" "${MAVEN_PUBLISHED}")"
89+
echo " Maven Surefire: $(version_line "${SUREFIRE_VERSION}" "${SUREFIRE_PUBLISHED}")"
90+
91+
# Build version lines for PR body
92+
echo "gradle_line=$(version_line "${GRADLE_VERSION}" "${GRADLE_PUBLISHED}")" >> "$GITHUB_OUTPUT"
93+
echo "maven_line=$(version_line "${MAVEN_VERSION}" "${MAVEN_PUBLISHED}")" >> "$GITHUB_OUTPUT"
94+
echo "surefire_line=$(version_line "${SUREFIRE_VERSION}" "${SUREFIRE_PUBLISHED}")" >> "$GITHUB_OUTPUT"
7395
7496
printf '%s\n' \
7597
"# Pinned latest eligible stable versions (>=${MIN_DEPENDENCY_AGE_HOURS}h old) for CI Visibility Gradle smoke tests." \
@@ -138,10 +160,9 @@ jobs:
138160
This PR updates the pinned latest eligible stable tool versions used by CI Visibility smoke tests.
139161
Only releases at least ${{ env.MIN_DEPENDENCY_AGE_HOURS }} hours old are eligible.
140162
141-
- Gradle: ${{ steps.gradle.outputs.version }} (published ${{ steps.gradle.outputs.published_at }})
142-
- Maven: ${{ steps.maven.outputs.version }} (published ${{ steps.maven.outputs.published_at }})
143-
- Maven Surefire: ${{ steps.surefire.outputs.version }} (published ${{ steps.surefire.outputs.published_at }})
144-
- Eligibility cutoff: ${{ steps.gradle.outputs.cutoff_at }}
163+
- Gradle: ${{ steps.update.outputs.gradle_line }}
164+
- Maven: ${{ steps.update.outputs.maven_line }}
165+
- Maven Surefire: ${{ steps.update.outputs.surefire_line }}
145166
146167
# Motivation
147168

0 commit comments

Comments
 (0)