Skip to content
5 changes: 3 additions & 2 deletions internal/documentation/docs/pages/Builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ All available standard tasks are documented [in the API reference](https://ui5.g
| generateBundle | *disabled* <sup>4</sup> | *disabled* <sup>4</sup> | *disabled* <sup>4</sup> | |
| buildThemes | | | enabled | enabled |
| generateThemeDesignerResources | | | *disabled* <sup>5</sup> | *disabled* <sup>5</sup> |
| generateVersionInfo | *disabled* <sup>1</sup> | | | |
| generateVersionInfo | enabled <sup>6</sup> | | | |
| generateCachebusterInfo | *disabled* | *disabled* | | |
| generateApiIndex | *disabled* <sup>1</sup> | | | |
| generateResourcesJson | *disabled* | *disabled* | *disabled* | *disabled* |
Expand All @@ -57,7 +57,8 @@ All available standard tasks are documented [in the API reference](https://ui5.g
<sup>2</sup> Enabled for projects defining a [component preload configuration](./Configuration.md#component-preload-generation)
<sup>3</sup> Enabled in `self-contained` build, which disables `generateComponentPreload` and `generateLibraryPreload`
<sup>4</sup> Enabled for projects defining a [bundle configuration](./Configuration.md#custom-bundling)
<sup>5</sup> Can be enabled for framework projects via the `includeTask` option. For other projects, this task is skipped
<sup>5</sup> Can be enabled for framework projects via the `includeTask` option. For other projects, this task is skipped
<sup>6</sup> Disabled for the server due to a corresponding middleware producing the same output

### minify

Expand Down
4 changes: 4 additions & 0 deletions internal/documentation/docs/pages/Server.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,10 @@ In case a directory has been requested, this middleware renders an HTML with a l
## Standard Tasks
As with the UI5 Builder, a set of standard tasks is being executed during a server build. Individual tasks can be included or excluded using the respective CLI options `--include-task` and `--exclude-task`.

::: info Exception
For the server, task [`generateVersionInfo`](../api/module-@ui5_builder_tasks_generateVersionInfo.md) is not executed because the corresponding middleware [`versionInfo`](#versioninfo) creates the same output file `sap-ui-version.json`.
:::

::: info
See [Builder Standard Tasks](./Builder.md#standard-tasks) for more explanation about each task.
:::
Expand Down
6 changes: 6 additions & 0 deletions internal/documentation/docs/updates/migrate-v5.md
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,12 @@ Update your `ui5.yaml` configuration to reference an existing middleware instead
| `serveThemes` | CSS files pre-built by `buildThemes` task and served via `serveResources` | `serveResources` |
| `testRunner` | TestRunner resources served via `serveResources` from the UI5 framework | `serveResources` |

## `sap-ui-version.json`

When running `ui5 build`, the standard task [`generateVersionInfo`](../api/module-@ui5_builder_tasks_generateVersionInfo) (producing a `sap-ui-version.json` file under `resources/`) is now **executed by default**. This applies to every build type (default, jsdoc, and self-contained) for projects of type `application`. For projects of other types (e.g. `library`), the behavior remains the same and [`generateVersionInfo`](../api/module-@ui5_builder_tasks_generateVersionInfo) is not executed.

To see which standard tasks are executed for each project type, check out the [Standard Tasks](../pages/Builder#standard-tasks) table in the UI5 Builder page.

## Learn More

- [Project: Type `component`](../pages/Project#component)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "application.m",
"version": "1.0.0",
"buildTimestamp": "WILL_BE_IGNORED_BY_TESTS",
"scmRevision": "",
"libraries": []
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"name": "application.o",
"version": "1.0.0",
"buildTimestamp": "WILL_BE_IGNORED_BY_TESTS",
"scmRevision": "",
"libraries": []
}
18 changes: 12 additions & 6 deletions packages/builder/test/lib/builder/builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,14 +71,20 @@ async function checkFileContentsIgnoreLineFeeds(t, expectedFiles, expectedPath,
currentContent = JSON.parse(currentContent.replace(/(:\s+)(\d+)/g, ": 0"));
expectedContent = JSON.parse(expectedContent.replace(/(:\s+)(\d+)/g, ": 0"));
t.deepEqual(currentContent, expectedContent);
} else {
if (expectedFile.endsWith(".json")) {
try {
t.deepEqual(JSON.parse(currentContent), JSON.parse(expectedContent), expectedFile);
} catch (e) {
t.falsy(e, expectedFile);
} else if (expectedFile.endsWith(".json")) {
try {
const currentJson = JSON.parse(currentContent);
const expectedJson = JSON.parse(expectedContent);
// Check if file is "sap-ui-version.json" and ignore the buildTimestamp property for comparison:
if (expectedFile.endsWith("sap-ui-version.json")) {
delete currentJson.buildTimestamp;
delete expectedJson.buildTimestamp;
}
t.deepEqual(currentJson, expectedJson, expectedFile);
} catch (e) {
t.falsy(e, expectedFile);
}
} else {
t.is(currentContent.replace(newLineRegexp, "\n"),
expectedContent.replace(newLineRegexp, "\n"),
relativeFile);
Expand Down
2 changes: 0 additions & 2 deletions packages/project/lib/build/helpers/composeTaskList.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ export default function composeTaskList(allTasks, {selfContained, jsdoc, include
selectedTasks.generateCachebusterInfo = false;
selectedTasks.generateApiIndex = false;
selectedTasks.generateThemeDesignerResources = false;
selectedTasks.generateVersionInfo = false;

// Disable generateResourcesJson due to performance.
// When executed it analyzes each module's AST and therefore
Expand All @@ -45,7 +44,6 @@ export default function composeTaskList(allTasks, {selfContained, jsdoc, include
selectedTasks.generateJsdoc = true;
selectedTasks.executeJsdocSdkTransformation = true;
selectedTasks.generateApiIndex = true;
selectedTasks.generateVersionInfo = true;

// Include theme build as required for SDK
selectedTasks.buildThemes = true;
Expand Down
9 changes: 9 additions & 0 deletions packages/project/lib/graph/ProjectGraph.js
Original file line number Diff line number Diff line change
Expand Up @@ -768,6 +768,15 @@ class ProjectGraph {
cache = Cache.Default,
ui5DataDir,
}) {
// Explicitly exclude task "generateVersionInfo" for Server builds
// because middleware "versionInfo" will generate the version info anyways.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handling should be moved to into the @ui5/server code in packages/server/lib/server.js, which does provide an HTTP server with the mentioned versionInfo middleware.

This @ui5/project API only returns the BuildServer, which is the underlying functionality, but it is not opinionated about the integration, and does not know about the versionInfo middleware.

This means that the BuildServer integration tests are likely unaffected by this change, which is fine.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This means that the BuildServer integration tests are likely unaffected by this change, which is fine.

I understand why to move the logic to server.js (originally I also thought about this). But isn't it also fine in ProjectGraph.js? I mean, it'd be in the dedicated serve() function outside of build() and we would have more realistic tests in BuildServer.integration.js. With the other way, the tests are logically correct but tend to be more unit test like.

if (!Array.isArray(excludedTasks)) {
excludedTasks = [];
}
if (!excludedTasks.includes("generateVersionInfo")) {
excludedTasks.push("generateVersionInfo");
}

this.seal(); // Do not allow further changes to the graph
if (this._builtOrServed) {
throw new Error(
Expand Down
46 changes: 44 additions & 2 deletions packages/project/test/lib/build/BuildServer.integration.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ test.serial("Serve application.a, create and delete a source file", async (t) =>
// #5 the second file is no longer served, but requesting it triggers a build of the dependencies
// because the file is not known anymore and might come from a different project.
// Note: This is special for applications, which are served at root level. For libraries, the server
// can determine whether a resources is inside a project namespace and only trigger a build for the affected
// can determine whether a resource is inside a project namespace and only trigger a build for the affected
// project. The logic could be improved, especially like in this case where the requested resource is outside
// of /resources or /test-resources.
await fixtureTester.requestResource({
Expand Down Expand Up @@ -614,7 +614,7 @@ test.serial("Serve application.a with --cache=Off", async (t) => {
}
});

// #2: Request with cache=Off (again) --> all tasks execute again (no cache reuse)
// #2: Request with cache=Off (again) --> nothing rebuilds (cache not written, but no changes)
await fixtureTester.requestResource({
resource: "/test.js",
assertions: {
Expand Down Expand Up @@ -1027,6 +1027,36 @@ test.serial("Source change during second build retries cleanly without no_cache
"Retry served content reflecting the mid-build-2 change");
});

test.serial("Serve application.a (test exclusion of generateVersionInfo)", async (t) => {
// This test verifies that task "generateVersionInfo" is excluded
// (default for server builds).

const fixtureTester = t.context.fixtureTester = await FixtureTester.create(t, "application.a");

await fixtureTester.serveProject();

// Request a resource to trigger the build:
await fixtureTester.requestResource({
resource: "/test.js",
assertions: {
projects: {
"application.a": {
executedTasks: [
"escapeNonAsciiCharacters",
"replaceCopyright",
"replaceVersion",
"minify",
"generateFlexChangesBundle",
"enhanceManifest",
"generateComponentPreload"
// no "generateVersionInfo" as expected
],
},
}
},
});
});

function getFixturePath(fixtureName) {
return fileURLToPath(new URL(`../../fixtures/${fixtureName}`, import.meta.url));
}
Expand Down Expand Up @@ -1159,6 +1189,18 @@ class FixtureTester {
const expectedProjects = Object.keys(projects);
this._t.deepEqual(projectsInOrder, expectedProjects);

// Optional check: Assert executed tasks
for (const [projectName, expected] of Object.entries(projects)) {
if (!expected.executedTasks) {
continue; // no executedTasks specified -> skip the check
}
const expectedExecuted = expected.executedTasks || [];
const actualExecuted = (tasksByProject[projectName]?.executed || []).sort();
const expectedArray = expectedExecuted.sort();
this._t.deepEqual(actualExecuted, expectedArray,
"All executed tasks of all projects should match expected");
}

// Assert skipped tasks per project
for (const [projectName, expectedSkipped] of Object.entries(projects)) {
const skippedTasks = expectedSkipped.skippedTasks || [];
Expand Down
Loading
Loading