Skip to content

Commit a2db0cb

Browse files
Merge pull request #1764 from rundeck/5.19.0
5.19.0 Release Notes
2 parents 6f0e5a3 + e55ddb0 commit a2db0cb

File tree

10 files changed

+244
-31
lines changed

10 files changed

+244
-31
lines changed

docs/.vuepress/navbar-menus/about.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ export default [
2121
},
2222
{
2323
text: 'Release Notes',
24-
link: '/history/5_x/version-5.18.0.md'
24+
link: '/history/5_x/version-5.19.0.md'
2525
}
2626
]

docs/.vuepress/notes.mjs

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,16 @@ async function main() {
6565
console.log(`Comparing versions: ${fromVersion}${toVersion}\n`);
6666

6767
// Check if toVersion tag exists by attempting to fetch from main repos
68-
const gh = new Octokit({ auth: process.env.GH_API_TOKEN });
68+
// Use a quiet Octokit instance to avoid noisy 404 logs during tag detection
69+
const gh = new Octokit({
70+
auth: process.env.GH_API_TOKEN,
71+
log: {
72+
debug: () => {},
73+
info: () => {},
74+
warn: () => {},
75+
error: () => {}
76+
}
77+
});
6978
let tagExists = false;
7079
let useHead = false;
7180

@@ -79,6 +88,7 @@ async function main() {
7988
tag: tag
8089
});
8190
tagExists = true;
91+
console.log(`✓ Found release tag: ${tag}\n`);
8292
break;
8393
} catch (error) {
8494
if (error.status !== 404) {
@@ -90,6 +100,7 @@ async function main() {
90100
ref: `tags/${tag}`
91101
});
92102
tagExists = true;
103+
console.log(`✓ Found git tag: ${tag}\n`);
93104
break;
94105
} catch (refError) {
95106
// Continue to next format
@@ -101,22 +112,34 @@ async function main() {
101112
// Determine behavior based on tag existence and mode
102113
if (!tagExists) {
103114
if (argv.draft) {
104-
console.log(`\nWarning: Tag ${toVersion} not found, using HEAD for preview\n`);
115+
console.log(` Tag ${toVersion} not found, using HEAD for preview\n`);
105116
useHead = true;
106117
} else {
107-
console.error(`\nERROR: Tag ${toVersion} not found.`);
108-
console.error(` Create the tag first or use --draft mode to preview with HEAD.\n`);
109-
console.log(`Continuing with empty results to create placeholder file...\n`);
110-
// Continue execution but with empty results
118+
console.log(`⚠ Tag ${toVersion} not found - creating placeholder file without PR data`);
119+
console.log(` Tip: Use --draft mode to preview with HEAD, or create the tag first.\n`);
120+
// Continue execution but skip PR fetching
111121
}
112122
}
113123

114124
const context = {};
115-
context.core = await getRepoData({ repo: 'rundeck', owner: 'rundeck' }, fromVersion, toVersion, ['release-notes/include'], useHead);
116-
context.enterprise = await getRepoData({ repo: 'rundeckpro', owner: 'rundeckpro' }, fromVersion, toVersion, ['release-notes/include'], useHead);
117-
context.docs = await getRepoData({ repo: 'docs', owner: 'rundeck' }, fromVersion, toVersion, [], useHead); // No label filtering for docs (need all PRs for contributors)
118-
context.ansible = await getRepoData({ repo: 'ansible-plugin', owner: 'rundeck-plugins' }, fromVersion, toVersion, ['release-notes/include'], useHead);
119-
context.runner = await getRepoData({ repo: 'sidecar', owner: 'rundeckpro' }, fromVersion, toVersion, ['release-notes/include'], useHead);
125+
126+
// Skip PR fetching if tag doesn't exist and not in draft mode
127+
const skipPRs = !tagExists && !useHead;
128+
129+
if (skipPRs) {
130+
console.log('Skipping PR fetching (tag not found, not in draft mode)\n');
131+
context.core = { contributors: {}, pulls: [] };
132+
context.enterprise = { contributors: {}, pulls: [] };
133+
context.docs = { contributors: {}, pulls: [] };
134+
context.ansible = { contributors: {}, pulls: [] };
135+
context.runner = { contributors: {}, pulls: [] };
136+
} else {
137+
context.core = await getRepoData({ repo: 'rundeck', owner: 'rundeck' }, fromVersion, toVersion, ['release-notes/include'], useHead);
138+
context.enterprise = await getRepoData({ repo: 'rundeckpro', owner: 'rundeckpro' }, fromVersion, toVersion, ['release-notes/include'], useHead);
139+
context.docs = await getRepoData({ repo: 'docs', owner: 'rundeck' }, fromVersion, toVersion, [], useHead); // No label filtering for docs (need all PRs for contributors)
140+
context.ansible = await getRepoData({ repo: 'ansible-plugin', owner: 'rundeck-plugins' }, fromVersion, toVersion, ['release-notes/include'], useHead);
141+
context.runner = await getRepoData({ repo: 'sidecar', owner: 'rundeckpro' }, fromVersion, toVersion, ['release-notes/include'], useHead);
142+
}
120143
context.contributors = { ...context.core.contributors, ...context.docs.contributors, ...context.ansible.contributors };
121144

122145
context.version = new RundeckVersion({ versionString: argv.milestone });
@@ -155,13 +178,22 @@ async function main() {
155178

156179
// Only run update functions if not a draft
157180
if (!argv.draft) {
158-
//Turning off docsearch update for version specific page
159-
//updateDocsearchVersion(argv.milestone);
181+
console.log('\n=== Updating Configuration Files ===\n');
182+
// Turning off docsearch update for version specific page
183+
// updateDocsearchVersion(argv.milestone);
160184
updateSetupJs(argv.milestone);
161185
addSidebarVersion(argv.milestone);
162186
updateLatestReleaseLink(argv.milestone);
163187
updateNavbarReleaseLink(argv.milestone);
164188
updatePRFeedConfig(argv.milestone);
189+
190+
console.log('\n✓ Successfully generated release notes and updated all configuration files!');
191+
console.log(` File: ${outPath}`);
192+
if (!tagExists && !useHead) {
193+
console.log('\n Note: PR data not included (tag not found). Re-run after creating the tag to populate PR details.');
194+
}
195+
} else {
196+
console.log(`\n✓ Draft release notes generated: ${outPath}`);
165197
}
166198
}
167199

@@ -237,7 +269,16 @@ function updateNavbarReleaseLink(version) {
237269
}
238270

239271
async function getRepoData(repo, fromVersion, toVersion, includeLabels, useHead = false) {
240-
const gh = new Octokit({ auth: process.env.GH_API_TOKEN });
272+
// Use quiet logging to avoid noisy 404 errors during tag format attempts
273+
const gh = new Octokit({
274+
auth: process.env.GH_API_TOKEN,
275+
log: {
276+
debug: () => {},
277+
info: () => {},
278+
warn: () => {},
279+
error: () => {}
280+
}
281+
});
241282

242283
console.log(`Fetching PRs from ${repo.owner}/${repo.repo}...`);
243284

docs/.vuepress/pr-feed-config.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
{
22
"lastSelfHostedRelease": {
3-
"version": "5.18.0",
4-
"lastSelfHostedDate": "2025-12-16",
3+
"version": "5.19.0",
4+
"lastSelfHostedDate": "2026-02-02",
5+
"lastSaasRelease": "2025-01-26",
56
"lastSaasCut": "rba/5.19-RBA-20260122-adc13ef-8e5597d",
6-
"description": "Last self-hosted GA release version and date"
7+
"description": "Last self-hosted release version and date"
78
}
89
}

docs/.vuepress/pr-utils.mjs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ export async function fetchPRsBetweenTags(octokit, owner, repo, fromVersion, toV
5252
let baseTagUsed = null;
5353
let headTagUsed = null;
5454

55-
// Try to find valid base tag
55+
// Try to find valid base tag (silently try different formats)
5656
for (const baseTag of baseTagFormats) {
5757
for (const headTag of headTagFormats) {
5858
try {
@@ -65,11 +65,11 @@ export async function fetchPRsBetweenTags(octokit, owner, repo, fromVersion, toV
6565
});
6666
baseTagUsed = baseTag;
6767
headTagUsed = headTag;
68-
console.log(` Found tags ${baseTag}...${headTag}, ${comparison.data.ahead_by} commits ahead`);
68+
console.log(` Found tags ${baseTag}...${headTag}, ${comparison.data.ahead_by} commits ahead`);
6969
break;
7070
} catch (error) {
7171
if (error.status === 404) {
72-
continue; // Try next format
72+
continue; // Try next format silently
7373
}
7474
throw error;
7575
}
@@ -78,8 +78,7 @@ export async function fetchPRsBetweenTags(octokit, owner, repo, fromVersion, toV
7878
}
7979

8080
if (!comparison) {
81-
const errorMsg = `Tags for versions ${fromVersion}...${toVersion} not found in ${owner}/${repo}`;
82-
console.warn(` Warning: ${errorMsg} - skipping this repository`);
81+
console.log(` ⚠ Tags ${fromVersion}...${toVersion} not found - skipping ${owner}/${repo}`);
8382
return [];
8483
}
8584

docs/.vuepress/setup.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { BaseTransition } from "vue"
22

3-
const RUNDECK_VERSION='5.18.0'
4-
const RUNDECK_VERSION_FULL='5.18.0-SNAPSHOT'
5-
const API_VERSION='56'
3+
const RUNDECK_VERSION='5.19.0'
4+
const RUNDECK_VERSION_FULL='5.19.0-SNAPSHOT'
5+
const API_VERSION='57'
66
const API_DEP_REL='6.0.0'
77
const API_DEP_VER='17'
88
const API_MIN_VER='14'

docs/.vuepress/sidebar-menus/history.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ export default [
66
{
77
text: 'Latest Release',
88
collapsible: false,
9-
link: '/history/5_x/version-5.18.0.md',
9+
link: '/history/5_x/version-5.19.0.md',
1010
},
1111
{
1212
text: 'Recent Changes',
@@ -86,6 +86,11 @@ export default [
8686
text: 'Version 5.x',
8787
collapsible: true,
8888
children: [
89+
{
90+
text: "5.19.0",
91+
link: "https://docs.rundeck.com/5.19.0/"
92+
},
93+
8994
{
9095
text: "5.18.0",
9196
link: "https://docs.rundeck.com/5.18.0/"

docs/api/index.md

Lines changed: 65 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3911,10 +3911,16 @@ To narrow down the result set over which the metrics will be calculated, you can
39113911

39123912
Paging parameters `max` and `offset` will have no effect on the result.
39133913

3914-
**Response**
3914+
**Additional Parameters (API v57+):**
3915+
3916+
* `useStats` (boolean): If `true`, use snapshot-based metrics from SCHEDULED_EXECUTION_STATS table. If `false` or not provided, use execution table query. When `useStats=true`, the `jobIdListFilter` parameter is required unless `groupByJob=true`.
3917+
* `groupByJob` (boolean): If `true` with `useStats=true`, returns metrics for all jobs in a single project (batch mode). The metrics query must be scoped to one project, either by using the project-specific endpoint (`/api/29/project/[PROJECT]/executions/metrics`) or by including a `project` query parameter when calling the global endpoint (`/api/29/executions/metrics`). Returns format: `{jobs: {uuid1: metrics, uuid2: metrics, ...}}`.
3918+
* `begin` (string): When using `useStats=true`, filter metrics to include only executions that completed on or after this date. Format: `yyyy-MM-ddTHH:mm:ssZ` (ISO8601).
3919+
* `end` (string): When using `useStats=true`, filter metrics to include only executions that completed on or before this date. Format: `yyyy-MM-ddTHH:mm:ssZ` (ISO8601).
39153920

3921+
**Response**
39163922

3917-
An object with `duration` entry containing duration stats, and a `total` entry with total executions.
3923+
When `groupByJob` is not used, the response is an object with `duration` entry containing duration stats, and a `total` entry with total executions:
39183924

39193925
``` json
39203926
{
@@ -3927,6 +3933,33 @@ An object with `duration` entry containing duration stats, and a `total` entry w
39273933
}
39283934
```
39293935

3936+
When `groupByJob=true` with `useStats=true` (API v57+), the response format is:
3937+
3938+
``` json
3939+
{
3940+
"jobs": {
3941+
"uuid1": {
3942+
"total": 100,
3943+
"succeeded": 95,
3944+
"failed": 5,
3945+
"duration": {
3946+
"average": "5s"
3947+
},
3948+
...
3949+
},
3950+
"uuid2": {
3951+
"total": 50,
3952+
"succeeded": 48,
3953+
"failed": 2,
3954+
"duration": {
3955+
"average": "3s"
3956+
},
3957+
...
3958+
}
3959+
}
3960+
}
3961+
```
3962+
39303963

39313964
### Execution State
39323965

@@ -6319,7 +6352,26 @@ Same response as [Setup SCM Plugin for a Project](#setup-scm-plugin-for-a-projec
63196352
"service": "NodeExecutor",
63206353
"title": "Kubernetes / Pods / Node Executor",
63216354
"iconUrl": "...",
6322-
"providerMetadata": { }
6355+
"providerMetadata": {
6356+
"groupBy": "Kubernetes",
6357+
"groupIconUrl": "/path/to/kubernetes-icon.svg"
6358+
}
6359+
},
6360+
{
6361+
"artifactName": "aws-vm-plugin",
6362+
"author": "Rundeck",
6363+
"builtin": false,
6364+
"description": "AWS VM management plugin",
6365+
"id": "abc123def456",
6366+
"name": "AwsVmStartPlugin",
6367+
"pluginVersion": "2.0.0",
6368+
"service": "WorkflowStep",
6369+
"title": "AWS VM Start",
6370+
"iconUrl": "...",
6371+
"providerMetadata": {
6372+
"groupBy": "AWS VM",
6373+
"groupIconUrl": "/path/to/aws-icon.svg"
6374+
}
63236375
},
63246376
{
63256377
"artifactName": "py-winrm-plugin",
@@ -6340,6 +6392,8 @@ Same response as [Setup SCM Plugin for a Project](#setup-scm-plugin-for-a-projec
63406392

63416393
* `iconUrl` - URL to icon file for the plugin if present. **since V40**
63426394
* `providerMetadata` - Map of metadata about the plugin if present. **since V40**
6395+
* `groupBy` - The group name for the plugin, used for UI grouping. Plugins with the same `groupBy` value will be grouped together in the UI. **since V57**
6396+
* `groupIconUrl` - The icon URL for the plugin group. This may be explicitly defined for the group or automatically determined from the first plugin in the group. **since V57**
63436397

63446398
### Get Plugin Detail
63456399

@@ -6361,7 +6415,10 @@ Since: v49
63616415
"targetHostCompatibility": "all",
63626416
"ver": null,
63636417
"id": "d36b17dfae7b",
6364-
"providerMetadata": {},
6418+
"providerMetadata": {
6419+
"groupBy": "MyGroup",
6420+
"groupIconUrl": "/path/to/group-icon.svg"
6421+
},
63656422
"dynamicProps": null,
63666423
"thirdPartyDependencies": null,
63676424
"name": "<provider-name>",
@@ -6395,6 +6452,10 @@ Since: v49
63956452
}
63966453
```
63976454

6455+
The `providerMetadata` object may contain:
6456+
* `groupBy` - The group name for the plugin, used for UI grouping. **since V57**
6457+
* `groupIconUrl` - The icon URL for the plugin group. **since V57**
6458+
63986459
## Webhooks
63996460

64006461
### List Project Webhooks

docs/api/rundeck-api-versions.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,20 @@ Changes introduced by API Version number:
3535
API versions below `{{$apiDepVersion}}` are *deprecated*. Clients using earlier versions should upgrade to use `{{$apiDepVersion}}` as the minimum version before release `{{ $apiDepRelease }}` to avoid errors.
3636
:::
3737

38+
### Version 57
39+
40+
* Updated Endpoints:
41+
* [`GET /api/V/plugin/list`][GET /api/V/plugin/list] - Plugin list response `providerMetadata` now includes `groupBy` and `groupIconUrl` fields for plugin UI grouping
42+
* [`GET /api/V/plugin/detail/[SERVICE]/[PROVIDER]`][GET /api/V/plugin/detail/\[SERVICE\]/\[PROVIDER\]] - Plugin detail response `providerMetadata` now includes `groupBy` and `groupIconUrl` fields for plugin UI grouping
43+
* [`GET /api/V/executions/metrics`][/api/V/executions/metrics]
44+
* Added `useStats` parameter: if `true`, use snapshot-based metrics from `SCHEDULED_EXECUTION_STATS` table. If `false` or not provided, use execution table query.
45+
* Added `groupByJob` parameter: if `true` with `useStats=true`, returns metrics for all jobs in the project (batch mode). Requires `project` parameter.
46+
* Added `begin` and `end` parameters for date range filtering when using `useStats=true`.
47+
* [`GET /api/V/project/[PROJECT]/executions/metrics`][/api/V/project/\[PROJECT\]/executions/metrics]
48+
* Added `useStats` parameter: if `true`, use snapshot-based metrics from `SCHEDULED_EXECUTION_STATS` table. If `false` or not provided, use execution table query.
49+
* Added `groupByJob` parameter: if `true` with `useStats=true`, returns metrics for all jobs in the project (batch mode).
50+
* Added `begin` and `end` parameters for date range filtering when using `useStats=true`.
51+
3852
### Version 56
3953

4054
* Updated Endpoints:

0 commit comments

Comments
 (0)