diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a0ffd173..0b908ef1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,15 @@ ## {{releaseVersion}} - {{releaseDate}} +### Added + +- New `swift.createTasksForLibraryProducts` setting that when enabled causes the extension to automatically create and provide tasks for library products ([#1741](https://github.com/swiftlang/vscode-swift/pull/1741)) + ## 2.10.0 - 2025-07-28 ### Added -- Added Swiftly toolchain management support `.swift-version` files, and integration with the toolchain selection UI ([#1717](https://github.com/swiftlang/vscode-swift/pull/1717) +- Added Swiftly toolchain management support `.swift-version` files, and integration with the toolchain selection UI ([#1717](https://github.com/swiftlang/vscode-swift/pull/1717)) - Added code lenses to run suites/tests, configurable with the `swift.showTestCodeLenses` setting ([#1698](https://github.com/swiftlang/vscode-swift/pull/1698)) - New `swift.excludePathsFromActivation` setting to ignore specified sub-folders from being activated as projects ([#1693](https://github.com/swiftlang/vscode-swift/pull/1693)) - New `swift.recordTestDuration` setting to disable capturing test durations, which can improve performance of heavy test runs ([#1745](https://github.com/swiftlang/vscode-swift/pull/1745)) diff --git a/assets/test/defaultPackage/Package.swift b/assets/test/defaultPackage/Package.swift index 6ea1984f1..9ff9be8dd 100644 --- a/assets/test/defaultPackage/Package.swift +++ b/assets/test/defaultPackage/Package.swift @@ -9,6 +9,10 @@ let package = Package( .library( name: "PackageLib", targets: ["PackageLib"]), + .library( + name: "PackageLib2", + type: .dynamic, + targets: ["PackageLib"]), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/assets/test/defaultPackage/Package@swift-6.0.swift b/assets/test/defaultPackage/Package@swift-6.0.swift index 838242e8c..2d84fcf9c 100644 --- a/assets/test/defaultPackage/Package@swift-6.0.swift +++ b/assets/test/defaultPackage/Package@swift-6.0.swift @@ -12,6 +12,10 @@ let package = Package( .library( name: "PackageLib", targets: ["PackageLib"]), + .library( + name: "PackageLib2", + type: .dynamic, + targets: ["PackageLib"]), ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. diff --git a/package.json b/package.json index ef1062af8..71ce5f3ef 100644 --- a/package.json +++ b/package.json @@ -657,6 +657,12 @@ ], "scope": "application" }, + "swift.createTasksForLibraryProducts": { + "type": "boolean", + "default": false, + "markdownDescription": "When enabled, the extension will create \"swift\" build tasks for library products in the package manifest. Note that automatic library products will not be included.", + "scope": "machine-overridable" + }, "swift.showCreateSwiftProjectInWelcomePage": { "type": "boolean", "default": true, diff --git a/src/SwiftPackage.ts b/src/SwiftPackage.ts index 939ae6e4d..905ea3da4 100644 --- a/src/SwiftPackage.ts +++ b/src/SwiftPackage.ts @@ -37,6 +37,10 @@ export interface Product { type: { executable?: null; library?: string[] }; } +export function isAutomatic(product: Product): boolean { + return (product.type.library || []).includes("automatic"); +} + /** Swift Package Manager target */ export interface Target { name: string; diff --git a/src/configuration.ts b/src/configuration.ts index 60423c042..89358d705 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -402,6 +402,12 @@ const configuration = { .getConfiguration("swift") .get("showBuildStatus", "swiftStatus"); }, + /** create build tasks for the library products of the package(s) */ + get createTasksForLibraryProducts(): boolean { + return vscode.workspace + .getConfiguration("swift") + .get("createTasksForLibraryProducts", false); + }, /** background compilation */ get backgroundCompilation(): boolean { return vscode.workspace diff --git a/src/tasks/SwiftTaskProvider.ts b/src/tasks/SwiftTaskProvider.ts index 765d50c3e..3065227af 100644 --- a/src/tasks/SwiftTaskProvider.ts +++ b/src/tasks/SwiftTaskProvider.ts @@ -15,7 +15,7 @@ import * as vscode from "vscode"; import { WorkspaceContext } from "../WorkspaceContext"; import { FolderContext } from "../FolderContext"; -import { Product } from "../SwiftPackage"; +import { isAutomatic, Product } from "../SwiftPackage"; import configuration, { ShowBuildStatusOptions, substituteVariablesInString, @@ -425,6 +425,16 @@ export class SwiftTaskProvider implements vscode.TaskProvider { for (const executable of executables) { tasks.push(...createBuildTasks(executable, folderContext)); } + + if (configuration.createTasksForLibraryProducts) { + const libraries = await folderContext.swiftPackage.libraryProducts; + for (const lib of libraries) { + if (isAutomatic(lib)) { + continue; + } + tasks.push(...createBuildTasks(lib, folderContext)); + } + } } return tasks; } diff --git a/test/integration-tests/tasks/SwiftTaskProvider.test.ts b/test/integration-tests/tasks/SwiftTaskProvider.test.ts index 2e90262b0..e2cd6f33e 100644 --- a/test/integration-tests/tasks/SwiftTaskProvider.test.ts +++ b/test/integration-tests/tasks/SwiftTaskProvider.test.ts @@ -26,7 +26,11 @@ import { executeTaskAndWaitForResult, waitForEndTaskProcess } from "../../utilit import { Version } from "../../../src/utilities/version"; import { FolderContext } from "../../../src/FolderContext"; import { mockGlobalObject } from "../../MockUtils"; -import { activateExtensionForSuite, folderInRootWorkspace } from "../utilities/testutilities"; +import { + activateExtensionForSuite, + folderInRootWorkspace, + updateSettings, +} from "../utilities/testutilities"; suite("SwiftTaskProvider Test Suite", () => { let workspaceContext: WorkspaceContext; @@ -92,6 +96,13 @@ suite("SwiftTaskProvider Test Suite", () => { }); suite("provideTasks", () => { + let resetSettings: (() => Promise) | undefined; + teardown(async () => { + if (resetSettings) { + await resetSettings(); + } + }); + suite("includes build all task from extension", () => { let task: vscode.Task | undefined; @@ -150,6 +161,41 @@ suite("SwiftTaskProvider Test Suite", () => { expect(task?.detail).to.include("swift build --product PackageExe"); }); + test("includes library build tasks task", async () => { + const taskProvider = workspaceContext.taskProvider; + let tasks = await taskProvider.provideTasks(new vscode.CancellationTokenSource().token); + let task = tasks.find(t => t.name === "Build Debug PackageLib2 (defaultPackage)"); + expect(task).to.be.undefined; + task = tasks.find(t => t.name === "Build Release PackageLib2 (defaultPackage)"); + expect(task).to.be.undefined; + + resetSettings = await updateSettings({ + "swift.createTasksForLibraryProducts": true, + }); + + tasks = await taskProvider.provideTasks(new vscode.CancellationTokenSource().token); + task = tasks.find(t => t.name === "Build Debug PackageLib2 (defaultPackage)"); + expect( + task, + 'expected to find a task named "Build Debug PackageLib2 (defaultPackage)", instead found ' + + tasks.map(t => t.name) + ).to.not.be.undefined; + expect(task?.detail).to.include("swift build --product PackageLib2"); + task = tasks.find(t => t.name === "Build Release PackageLib2 (defaultPackage)"); + expect( + task, + 'expected to find a task named "Build Release PackageLib2 (defaultPackage)", instead found ' + + tasks.map(t => t.name) + ).to.not.be.undefined; + expect(task?.detail).to.include("swift build -c release --product PackageLib2"); + + // Don't include automatic products + task = tasks.find(t => t.name === "Build Debug PackageLib (defaultPackage)"); + expect(task).to.be.undefined; + task = tasks.find(t => t.name === "Build Release PackageLib (defaultPackage)"); + expect(task).to.be.undefined; + }); + test("includes product release task", async () => { const taskProvider = workspaceContext.taskProvider; const tasks = await taskProvider.provideTasks( diff --git a/userdocs/userdocs.docc/Articles/Features/automatic-task-creation.md b/userdocs/userdocs.docc/Articles/Features/automatic-task-creation.md index b0b8cc5ed..4d08cd1e3 100644 --- a/userdocs/userdocs.docc/Articles/Features/automatic-task-creation.md +++ b/userdocs/userdocs.docc/Articles/Features/automatic-task-creation.md @@ -5,9 +5,17 @@ Add tasks for common operations with your Package. For workspaces that contain a `Package.swift` file, the Swift extension adds the following tasks: - **Build All**: Build all targets in the Package. -- **Build Debug **: Each executable in a Package.swift get a task for building a debug build. -- **Build Release **: Each executable in a Package.swift get a task for building a release build. +- **Build Debug \**: Each executable product in a Package.swift get a task for building a debug build. +- **Build Release \**: Each executable product in a Package.swift get a task for building a release build. > 💡 Tip: Tasks use workflows common to all VS Code extensions. For more information see [the VS Code documentation for tasks](https://code.visualstudio.com/docs/editor/tasks). These tasks are available via the commands **Terminal ▸ Run Task...** and **Terminal ▸ Run Build Task...** in the command palette. + +## Create tasks for library targets + +By default build tasks are only automatically created for executable products. If you set the `swift.createTasksForLibraryProducts` setting to true, then additional tasks will be created: +- **Build Debug \**: Each library product in a Package.swift get a task for building a debug build. +- **Build Release \**: Each library product in a Package.swift get a task for building a release build. + +> ⚠️ Important: Tasks will not be created for automatic library products, as you cannot specify a `--product` option for automatic products when building. For more information see the [Swift Package Manager documentation for Product definitions](https://docs.swift.org/package-manager/PackageDescription/PackageDescription.html#product). \ No newline at end of file