Skip to content

Commit dcfb2b8

Browse files
Merge remote-tracking branch 'origin/main' into tenants-api
# Conflicts: # docs/self-managed/components/orchestration-cluster/core-settings/configuration/partials/_api.md # docs/self-managed/components/orchestration-cluster/core-settings/configuration/partials/_processing.md Co-authored-by: christinaausley <84338309+christinaausley@users.noreply.github.com>
2 parents 1ce12d1 + 8ea6b36 commit dcfb2b8

282 files changed

Lines changed: 13122 additions & 864 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/workflows/sync-hub-rest-api-docs.yaml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,14 @@ jobs:
9494
9595
# Format spec files
9696
npm ci
97-
npx prettier --write api/hubsm/v2/*.yaml
9897
9998
cd api/hubsm/v2
10099
mv rest-api.yaml camunda-openapi.yaml
101100
npm run api:generate:hubsm
102101
102+
# Generate modifies the yaml files
103+
npx prettier --write *.yaml
104+
103105
- name: Upload Self-Managed changes
104106
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
105107
with:
@@ -156,12 +158,14 @@ jobs:
156158
157159
# Format spec files
158160
npm ci
159-
npx prettier --write api/hubsaas/v2/*.yaml
160161
161162
cd api/hubsaas/v2
162163
mv rest-api.yaml camunda-openapi.yaml
163164
npm run api:generate:hubsaas
164165
166+
# Generate modifies the yaml files
167+
npx prettier --write *.yaml
168+
165169
- name: Upload SaaS changes
166170
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
167171
with:
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# Runs the Hub API filtering tests, but only when the files they cover change,
2+
# instead of on every PR (see test.yaml, which excludes this spec).
3+
name: test-hub-generation
4+
5+
on:
6+
pull_request:
7+
paths:
8+
- "api/filter-availability.js"
9+
- "api/hub-generation-strategy.js"
10+
- "api/hubsm/generation-strategy.js"
11+
- "api/hubsaas/generation-strategy.js"
12+
- "api/tests/filter-availability.spec.js"
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
test:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- name: Checkout code
22+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
23+
24+
- name: Setup Node.js
25+
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
26+
with:
27+
node-version-file: ".nvmrc"
28+
cache: "npm"
29+
30+
- name: Install dependencies
31+
run: npm ci
32+
33+
- name: Run hub generation tests
34+
run: npx jest api/tests/filter-availability.spec.js

.github/workflows/test.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# This workflow runs tests on pull requests to ensure that the code changes do not break existing functionality.
22
# Currently, it runs basic regressions testing of the docusaurus site.
3+
# The hub API filtering tests are excluded here and run only when relevant
4+
# files change, via test-hub-generation.yaml.
35
name: test
46

57
on: pull_request
@@ -24,4 +26,4 @@ jobs:
2426
run: npm ci
2527

2628
- name: Run tests
27-
run: npm test
29+
run: npm test -- --testPathIgnorePatterns="api/tests/filter-availability.spec.js"

api/filter-availability.js

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Keep only APIs available for a given deployment type: endpoints with no
2+
// x-availability property, or whose x-availability matches the requested value.
3+
4+
const fs = require("fs");
5+
const path = require("path");
6+
const yaml = require("js-yaml");
7+
8+
const HTTP_METHODS = ["get", "post", "put", "patch", "delete"];
9+
10+
function isHTTPMethod(metadata) {
11+
return HTTP_METHODS.includes(metadata[0]);
12+
}
13+
14+
function isAvailableInEnvironment(metadata, environment) {
15+
const available =
16+
!Object.hasOwn(metadata, "x-availability") ||
17+
metadata["x-availability"].toLowerCase() === environment.toLowerCase();
18+
return available;
19+
}
20+
21+
function hasOperationOrRef(pathData) {
22+
return Object.keys(pathData).some(
23+
(key) => HTTP_METHODS.includes(key) || key === "$ref"
24+
);
25+
}
26+
27+
function filterMethodsForEnvironment(pathData, environment) {
28+
return Object.fromEntries(
29+
Object.entries(pathData)
30+
.filter(isHTTPMethod)
31+
.filter(([_, metadata]) =>
32+
isAvailableInEnvironment(metadata, environment)
33+
)
34+
);
35+
}
36+
37+
function otherMetadata(pathData) {
38+
return Object.fromEntries(
39+
Object.entries(pathData).filter((d) => !isHTTPMethod(d))
40+
);
41+
}
42+
43+
function refsOnly(metadata) {
44+
return Object.fromEntries(
45+
Object.entries(metadata).filter(([key]) => key === "$ref")
46+
);
47+
}
48+
49+
function filterPathDataForEnvironment(pathData, environment) {
50+
const methodsForEnvironment = filterMethodsForEnvironment(
51+
pathData,
52+
environment
53+
);
54+
55+
if (Object.keys(methodsForEnvironment).length === 0) {
56+
// when there are no available methods, drop all other metadata except
57+
// $ref, which will be cleaned up later
58+
return refsOnly(otherMetadata(pathData));
59+
}
60+
61+
// when there are available methods, return all other metadata too
62+
return { ...methodsForEnvironment, ...otherMetadata(pathData) };
63+
}
64+
65+
// we need to escape routes to match spec refs
66+
// https://swagger.io/docs/specification/v3_0/using-ref/#escape-characters
67+
function escapeRoute(route) {
68+
return route.replace(/\~/g, "~0").replace(/\//g, "~1");
69+
}
70+
71+
function filterPaths(paths, environment) {
72+
const filtered = {};
73+
const removedRoutes = [];
74+
75+
if (paths) {
76+
for (const [route, pathData] of Object.entries(paths)) {
77+
const filteredPathData = filterPathDataForEnvironment(
78+
pathData,
79+
environment
80+
);
81+
82+
// a path is worth keeping only if it still has an operation or a $ref to one.
83+
// other metadata (summary/description/parameters) shouldn't keep an
84+
// operation-less path alive
85+
if (hasOperationOrRef(filteredPathData)) {
86+
filtered[route] = filteredPathData;
87+
} else {
88+
removedRoutes.push(escapeRoute(route));
89+
}
90+
}
91+
}
92+
93+
return [filtered, removedRoutes];
94+
}
95+
96+
function isDanglingRef(pathData, allRemovedRoutes) {
97+
return (
98+
Object.hasOwn(pathData, "$ref") && allRemovedRoutes.has(pathData["$ref"])
99+
);
100+
}
101+
102+
function pruneRefs(paths, allRemovedRoutes) {
103+
return Object.fromEntries(
104+
Object.entries(paths).filter(
105+
([, pathData]) => !isDanglingRef(pathData, allRemovedRoutes)
106+
)
107+
);
108+
}
109+
110+
// js-yaml drops comments on load/dump, so we should capture the leading
111+
// comment block separately and re-prepend.
112+
function extractHeaderComments(content) {
113+
const lines = content.split("\n");
114+
let end = 0;
115+
while (
116+
end < lines.length &&
117+
(lines[end] === "" || lines[end].trimStart().startsWith("#"))
118+
) {
119+
end++;
120+
}
121+
return end === 0 ? "" : lines.slice(0, end).join("\n") + "\n";
122+
}
123+
124+
function loadSpecFile(filePath) {
125+
const content = fs.readFileSync(filePath, "utf8");
126+
127+
return {
128+
path: filePath,
129+
header: extractHeaderComments(content),
130+
spec: yaml.load(content),
131+
};
132+
}
133+
134+
function getYamlFiles(specDir) {
135+
return fs
136+
.readdirSync(specDir)
137+
.filter((file) => file.endsWith(".yaml") || file.endsWith(".yml"))
138+
.map((file) => path.join(specDir, file));
139+
}
140+
141+
function writeFile(filePath, fileData) {
142+
fs.writeFileSync(filePath, fileData.header + yaml.dump(fileData.spec));
143+
}
144+
145+
// compare against the original paths to know whether a file needs rewriting,
146+
// instead of threading a "changed" flag through every filtering step
147+
function pathsChanged(before, after) {
148+
return JSON.stringify(before ?? {}) !== JSON.stringify(after);
149+
}
150+
151+
function filterByAvailability(specDir, environment) {
152+
const files = getYamlFiles(specDir).map((filePath) => loadSpecFile(filePath));
153+
154+
const mapping = {};
155+
const allRemovedRoutes = new Set();
156+
for (const file of files) {
157+
const originalPaths = file.spec.paths;
158+
159+
// filter methods by x-availability
160+
const [filteredPaths, removedRoutes] = filterPaths(
161+
originalPaths,
162+
environment
163+
);
164+
file.spec.paths = filteredPaths;
165+
166+
// store removed routes for pruning refs later
167+
const fileName = file.path.split("/").at(-1);
168+
removedRoutes.forEach((e) =>
169+
allRemovedRoutes.add(`${fileName}#/paths/${e}`)
170+
);
171+
172+
// store file, data mapping for tracking/writing file changes later
173+
mapping[file.path] = {
174+
spec: file.spec,
175+
header: file.header,
176+
originalPaths,
177+
};
178+
}
179+
180+
// prune dangling refs
181+
for (const fileData of Object.values(mapping)) {
182+
fileData.spec.paths = pruneRefs(fileData.spec.paths, allRemovedRoutes);
183+
}
184+
185+
// write files whose paths actually changed
186+
Object.entries(mapping).forEach(([filePath, fileData]) => {
187+
if (pathsChanged(fileData.originalPaths, fileData.spec.paths)) {
188+
writeFile(filePath, fileData);
189+
}
190+
});
191+
}
192+
193+
module.exports = {
194+
isAvailableInEnvironment,
195+
filterByAvailability,
196+
filterPaths,
197+
filterPathDataForEnvironment,
198+
extractHeaderComments,
199+
escapeRoute,
200+
pruneRefs,
201+
pathsChanged,
202+
};

api/hub-generation-strategy.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
const path = require("path");
2+
const { makeServerDynamic } = require("./make-server-dynamic");
3+
const removeDuplicateVersionBadge = require("./remove-duplicate-version-badge");
4+
const { filterByAvailability } = require("./filter-availability");
5+
6+
function createHubGenerationStrategy(environment) {
7+
function preGenerateDocs(config) {
8+
const specFilePath = config.specPath;
9+
const specDir = path.dirname(specFilePath);
10+
11+
makeServerDynamic(specFilePath);
12+
filterByAvailability(specDir, environment);
13+
}
14+
15+
function postGenerateDocs(config) {
16+
removeDuplicateVersionBadge(`${config.outputDir}/hub-api.info.mdx`);
17+
}
18+
19+
return { preGenerateDocs, postGenerateDocs };
20+
}
21+
22+
module.exports = createHubGenerationStrategy;

api/hubsaas/generation-strategy.js

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1 @@
1-
const { makeServerDynamic } = require("../make-server-dynamic");
2-
const removeDuplicateVersionBadge = require("../remove-duplicate-version-badge");
3-
4-
function preGenerateDocs(config) {
5-
makeServerDynamic(config.specPath);
6-
}
7-
8-
function postGenerateDocs(config) {
9-
removeDuplicateVersionBadge(`${config.outputDir}/hub-api.info.mdx`);
10-
}
11-
12-
module.exports = {
13-
preGenerateDocs,
14-
postGenerateDocs,
15-
};
1+
module.exports = require("../hub-generation-strategy")("saas");

api/hubsaas/v2/camunda-openapi.yaml

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
22
# one or more contributor license agreements. See the NOTICE file distributed
33
# with this work for additional information regarding copyright ownership.
4-
# Licensed under the Camunda License 1.0. You may not use this file
5-
# except in compliance with the Camunda License 1.0.
4+
# Licensed under a proprietary license. See the LICENSE.txt file for more
5+
# information. You may not use this file except in compliance with the
6+
# proprietary license.
67

78
openapi: 3.0.3
89
info:
@@ -55,8 +56,7 @@ info:
5556
name: Camunda
5657
url: https://docs.camunda.io
5758
license:
58-
name: Camunda License 1.0
59-
url: https://legal.camunda.com/licensing-and-other-legal-terms#702a69c4-3932-47b3-ac74-3b557feeda58
59+
name: Proprietary
6060

6161
servers:
6262
- url: "{schema}://{host}:{port}/api/v2"
@@ -127,6 +127,10 @@ paths:
127127
$ref: "folders.yaml#/paths/~1folders~1{folderKey}"
128128
/folders/{folderKey}/permanent:
129129
$ref: "folders.yaml#/paths/~1folders~1{folderKey}~1permanent"
130+
/folders/recently-deleted/search:
131+
$ref: "folders.yaml#/paths/~1folders~1recently-deleted~1search"
132+
/folders/{folderKey}/restoration:
133+
$ref: "folders.yaml#/paths/~1folders~1{folderKey}~1restoration"
130134
/info:
131135
$ref: "info.yaml#/paths/~1info"
132136
/projects:
@@ -137,6 +141,10 @@ paths:
137141
$ref: "projects.yaml#/paths/~1projects~1{projectKey}~1permanent"
138142
/projects/search:
139143
$ref: "projects.yaml#/paths/~1projects~1search"
144+
/projects/recently-deleted/search:
145+
$ref: "projects.yaml#/paths/~1projects~1recently-deleted~1search"
146+
/projects/{projectKey}/restoration:
147+
$ref: "projects.yaml#/paths/~1projects~1{projectKey}~1restoration"
140148
/versions:
141149
$ref: "versions.yaml#/paths/~1versions"
142150
/versions/{versionKey}:
@@ -153,6 +161,10 @@ paths:
153161
$ref: "workspaces.yaml#/paths/~1workspaces~1{workspaceKey}~1permanent"
154162
/workspaces/search:
155163
$ref: "workspaces.yaml#/paths/~1workspaces~1search"
164+
/workspaces/recently-deleted/search:
165+
$ref: "workspaces.yaml#/paths/~1workspaces~1recently-deleted~1search"
166+
/workspaces/{workspaceKey}/restoration:
167+
$ref: "workspaces.yaml#/paths/~1workspaces~1{workspaceKey}~1restoration"
156168
/workspaces/{workspaceKey}/members:
157169
$ref: "members.yaml#/paths/~1workspaces~1{workspaceKey}~1members"
158170
/workspaces/{workspaceKey}/members/{email}:

api/hubsaas/v2/catalog.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
# Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH under
22
# one or more contributor license agreements. See the NOTICE file distributed
33
# with this work for additional information regarding copyright ownership.
4-
# Licensed under the Camunda License 1.0. You may not use this file
5-
# except in compliance with the Camunda License 1.0.
4+
# Licensed under a proprietary license. See the LICENSE.txt file for more
5+
# information. You may not use this file except in compliance with the
6+
# proprietary license.
67

78
# Catalog resource paths and schemas
89
paths:

0 commit comments

Comments
 (0)