Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/logger/lib/loggers/ProjectBuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,24 @@ class ProjectBuild extends Logger {
this._log(level, `${this.#projectName}: Finished task ${taskName}`);
}
}

skipTask(taskName) {
if (!this.#tasksToRun || !this.#tasksToRun.includes(taskName)) {
throw new Error(`loggers/ProjectBuild#skipTask: Unknown task ${taskName}`);
}
const level = "info";
const hasListeners = this._emit(ProjectBuild.PROJECT_BUILD_STATUS_EVENT_NAME, {
level,
projectName: this.#projectName,
projectType: this.#projectType,
taskName,
status: "task-skip",
});

if (!hasListeners) {
this._log(level, `${this.#projectName}: Skipping task ${taskName}`);
}
}
}

export default ProjectBuild;
88 changes: 87 additions & 1 deletion packages/logger/lib/writers/Console.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class Console {
#progressBarContainer;
#progressBar;
#progressProjectWeight;
#moduleFilter;

constructor() {
this._handleLogEvent = this.#handleLogEvent.bind(this);
Expand All @@ -29,6 +30,72 @@ class Console {
this._handleBuildMetadataEvent = this.#handleBuildMetadataEvent.bind(this);
this._handleProjectBuildMetadataEvent = this.#handleProjectBuildMetadataEvent.bind(this);
this._handleStop = this.disable.bind(this);
this.#initFiters();
}

#initFiters() {
const modulesPatterns = process.env.UI5_LOG_MODULES;
if (!modulesPatterns) {
this.#moduleFilter = null;
return;
}
const enabledModules = [];
const enabledNamespaces = [];
const disabledModules = [];
const disabledNamespaces = [];
// Example of modulePattern: "module1,module2:submodule:subsubmodule,module3:*:-module3:submodule"
modulesPatterns.split(",").forEach((modulePattern) => {
const pattern = modulePattern.trim();
if (pattern.startsWith("-")) {
if (pattern.endsWith(":*")) {
disabledNamespaces.push(pattern.substring(1, pattern.length - 2));
} else {
disabledModules.push(pattern.substring(1));
}
} else {
if (pattern.endsWith(":*")) {
enabledNamespaces.push(pattern.substring(0, pattern.length - 2));
} else {
enabledModules.push(pattern);
}
}
});

this.#moduleFilter = {
enabledModules,
enabledNamespaces,
disabledModules,
disabledNamespaces,
};
}

#filterModule(moduleName) {
if (!this.#moduleFilter) {
return true;
}
if (this.#moduleFilter.disabledModules.includes(moduleName)) {
return false;
}
if (this.#moduleFilter.enabledModules.includes(moduleName)) {
return true;
}
const moduleParts = moduleName.split(":");
for (let i = moduleParts.length - 1; i > 0; i--) {
const namespace = moduleParts.slice(0, i).join(":");
if (this.#moduleFilter.disabledNamespaces.includes(namespace)) {
return false;
}
if (this.#moduleFilter.enabledNamespaces.includes(namespace)) {
return true;
}
}

// If any module or namespace is enabled, all other modules are disabled by default
if (this.#moduleFilter.enabledModules.length > 0 || this.#moduleFilter.enabledNamespaces.length > 0) {
return false;
}

return true;
}

/**
Expand Down Expand Up @@ -137,7 +204,9 @@ class Console {
}

#handleLogEvent({level, message, moduleName}) {
this.#writeMessage(level, `${chalk.blue(moduleName)} ${message}`);
if (this.#filterModule(moduleName)) {
this.#writeMessage(level, `${chalk.blue(moduleName)} ${message}`);
}
}

#handleBuildMetadataEvent({projectsToBuild}) {
Expand Down Expand Up @@ -328,6 +397,23 @@ class Console {
taskMetadata.executionEnded = true;
message = `${chalk.green(figures.tick)} Finished task ${chalk.bold(taskName)}`;

// Update progress bar (if used)
this._getProgressBar()?.increment(1);
break;
case "task-skip":
if (taskMetadata.executionEnded) {
throw new Error(`writers/Console: ` +
`Unexpected task-skip event for project ${projectName}, task ${taskName}. ` +
`Task execution already ended`);
}
if (taskMetadata.executionStarted) {
throw new Error(`writers/Console: ` +
`Unexpected task-skip event for project ${projectName}, task ${taskName}. ` +
`Task execution already started`);
}
taskMetadata.executionEnded = true;
message = `${chalk.green(figures.tick)} Skipping task ${chalk.bold(taskName)}`;

// Update progress bar (if used)
this._getProgressBar()?.increment(1);
break;
Expand Down
55 changes: 55 additions & 0 deletions packages/logger/test/lib/loggers/ProjectBuild.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,3 +228,58 @@ test.serial("End task: Unknown task", (t) => {
}, "Threw with expected error message");
});

test.serial("Skip task", (t) => {
const {projectBuildLogger, logHandler, metadataHandler, statusHandler, logStub} = t.context;
projectBuildLogger.setTasks(["task.a"]);

projectBuildLogger.skipTask("task.a");

t.is(statusHandler.callCount, 1, "One build-status event emitted");
t.deepEqual(statusHandler.getCall(0).args[0], {
level: "info",
projectName: "projectName",
projectType: "projectType",
status: "task-skip",
taskName: "task.a",
}, "Metadata event has expected payload");

t.is(logHandler.callCount, 0, "No log event emitted");
t.is(metadataHandler.callCount, 1, "One build-metadata event emitted");
t.is(logStub.callCount, 0, "_log was never called");
});

test.serial("No event listener: Skip task", (t) => {
const {projectBuildLogger, logHandler, metadataHandler, statusHandler, logStub} = t.context;
process.off(ProjectBuildLogger.PROJECT_BUILD_STATUS_EVENT_NAME, statusHandler);
projectBuildLogger.setTasks(["task.a"]);

projectBuildLogger.skipTask("task.a");
t.is(logStub.callCount, 1, "_log got called once");
t.is(logStub.getCall(0).args[0], "info", "Logged with expected log-level");
t.is(logStub.getCall(0).args[1],
"projectName: Skipping task task.a",
"Logged expected message");

t.is(logHandler.callCount, 0, "No log event emitted");
t.is(metadataHandler.callCount, 1, "One build-metadata event emitted");
});

test.serial("Skip task: Unknown task", (t) => {
const {projectBuildLogger} = t.context;

// Throws because no projects are set
t.throws(() => {
projectBuildLogger.skipTask("task.x");
}, {
message: `loggers/ProjectBuild#skipTask: Unknown task task.x`
}, "Threw with expected error message");

projectBuildLogger.setTasks(["task.a"]);
// Throws because given project is unknown
t.throws(() => {
projectBuildLogger.skipTask("task.x");
}, {
message: `loggers/ProjectBuild#skipTask: Unknown task task.x`
}, "Threw with expected error message");
});

108 changes: 108 additions & 0 deletions packages/logger/test/lib/writers/Console.js
Original file line number Diff line number Diff line change
Expand Up @@ -721,6 +721,114 @@ test.serial("ProjectBuild status (end): Task execution not started", (t) => {
t.is(stderrWriteStub.callCount, 0, "Logged zero messages");
});

test.serial("ProjectBuild status (skip)", (t) => {
const {stderrWriteStub} = t.context;
process.emit("ui5.build-metadata", {
projectsToBuild: ["project.a"]
});

process.emit("ui5.project-build-metadata", {
projectName: "project.a",
projectType: "project-type",
tasksToRun: ["task.a"]
});

process.emit("ui5.project-build-status", {
level: "info",
projectName: "project.a",
projectType: "project-type",
taskName: "task.a",
status: "task-skip",
});

t.is(stderrWriteStub.callCount, 1, "Logged one message");
t.is(stripAnsi(stderrWriteStub.getCall(0).args[0]),
`info project.a ${figures.tick} Skipping task task.a\n`,
"Logged expected message");
});

test.serial("ProjectBuild status (skip): Task execution already started", (t) => {
const {stderrWriteStub} = t.context;
process.emit("ui5.build-metadata", {
projectsToBuild: ["project.a"]
});

process.emit("ui5.project-build-metadata", {
projectName: "project.a",
projectType: "project-type",
tasksToRun: ["task.a"]
});

process.emit("ui5.project-build-status", {
level: "silly",
projectName: "project.a",
projectType: "project-type",
taskName: "task.a",
status: "task-start",
});

t.throws(() => {
process.emit("ui5.project-build-status", {
level: "info",
projectName: "project.a",
projectType: "project-type",
taskName: "task.a",
status: "task-skip",
});
}, {
message:
"writers/Console: Unexpected task-skip event for project project.a, task task.a. " +
"Task execution already started"
});

t.is(stderrWriteStub.callCount, 0, "Logged zero messages");
});

test.serial("ProjectBuild status (skip): Task execution already ended", (t) => {
const {stderrWriteStub} = t.context;
process.emit("ui5.build-metadata", {
projectsToBuild: ["project.a"]
});

process.emit("ui5.project-build-metadata", {
projectName: "project.a",
projectType: "project-type",
tasksToRun: ["task.a"]
});

process.emit("ui5.project-build-status", {
level: "silly",
projectName: "project.a",
projectType: "project-type",
taskName: "task.a",
status: "task-start",
});

process.emit("ui5.project-build-status", {
level: "silly",
projectName: "project.a",
projectType: "project-type",
taskName: "task.a",
status: "task-end",
});

t.throws(() => {
process.emit("ui5.project-build-status", {
level: "info",
projectName: "project.a",
projectType: "project-type",
taskName: "task.a",
status: "task-skip",
});
}, {
message:
"writers/Console: Unexpected task-skip event for project project.a, task task.a. " +
"Task execution already ended"
});

t.is(stderrWriteStub.callCount, 0, "Logged zero messages");
});

test.serial("ProjectBuild status: Unknown status", (t) => {
const {stderrWriteStub} = t.context;
process.emit("ui5.build-metadata", {
Expand Down
Loading
Loading