Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Default to all targets when plugin --target parameter missing. Fix #483 #608

Merged
merged 3 commits into from
Sep 6, 2023

Conversation

BrianHenryIE
Copy link
Contributor

@BrianHenryIE BrianHenryIE commented Sep 3, 2023

When either of the swift-format plugins is run without the --target parameter, an error is returned. This PR implements the fix by @soumyamahunt in the #483 discussion, default to all targets when none is set:

let targetsToFormat = targetNames.isEmpty ? context.package.targets : try context.package.targets(named: targetNames)

Before:

$ swift package lint-source-code                                          
Building for debugging...
Build complete! (2.15s)
Error: '--recursive' is only valid when formatting or linting files
Usage: swift-format lint [--configuration <configuration>] [--assume-filename <assume-filename>] [--recursive] [--ignore-unparsable-files] [--parallel] [--color-diagnostics] [--no-color-diagnostics] [<paths> ...] [--strict]
  See 'swift-format lint --help' for more information.
error: swift-format invocation failed: NSTaskTerminationReason(rawValue: 1):64

After:

$ swift package lint-source-code  
Building for debugging...
Build complete! (2.28s)
Linted the source code.

The test works, but maybe there's a BDD library I should be using instead. It sets up a project in a tmp dir with swift-format as a dependency, then confirms the error is absent from the stderr output.

In the sample SPM project I included one each of executable, library, test, plugin targets. AIUI, context.package.targets does not return the plugin target. I.e. as this fix stands, omitting --target plugin parameter and expecting "all" targets to be linted, does not lint any plugin target.

I tried various ways to unit-test the plugin first. Discussion on the Swift forums says it cannot be done! I symlinked the plugin file into the test target and added SPM as a dependency but got blocked by access control levels as I tried to mock a PluginContext.

I also tried to implement the tests the same as SPM's own fixtures tests but didn't manage to get that working either.

With the current setup (write Package.swift to a temp dir, run swift package ... in a NSTask Process) I was only able to verify the output of stdout and stderr. I tried a few ways to determine what parameters the swift-format plugin was calling the executable – subscribing to NSWorkspace.willLaunchApplicationNotification, looping NSWorkspace.shared.runningApplications, and an attempt to implement ps -ax -o command | grep swift-format. I couldn't find any way to determine sub-processes of the Process the test was creating.

So, this does fix #483, but I'm open to changes to the tests if there's a more conventional way to write them.

@allevato
Copy link
Member

allevato commented Sep 6, 2023

I'm a bit nervous about the complexity of that test. Setting up a new SPM workspace, running SPM, and then checking output feels like it's a recipe for flakiness or potential problems if SPM upstream ever changes their behavior.

I'm good with the change to the plugin itself, but can you drop the test? I'd like to think more holistically about how to get better coverage there and in other parts of the codebase that have historically been lacking it.

@BrianHenryIE
Copy link
Contributor Author

I've deleted the test. I think half the value in tests is that they make you proof-read your code again and again, so we did get at least that benefit from it.

SPM's PluginTests::testCommandPluginInvocation() does exactly that – creates a package in a temp dir from a string and executes the plugin. It also has a Fixtures/Plugins directory which are the projects used in other tests in that class.

It's definitely nicer than what I wrote!

// Invoke the command plugin that prints out various things it was given, and check them.
testCommand(package: package, plugin: "PluginPrintingInfo", targets: ["MyLibrary"], arguments: ["veni", "vidi", "vici"]) { output in
  output.check(diagnostic: .equal("Root package is MyPackage."), severity: .info)
  output.check(diagnostic: .and(.prefix("Found the swiftc tool"), .suffix(".")), severity: .info)
}

Sources/SPMTestSupport/misc.swift is the set of functions for working with the fixtures. The SPMTestSupport library .target is not published as a product in SPM's Package.swift and AIUI, that's preventing me from setting it as a dependency for the .testTarget I had added here.

Maybe all it would take to use it here would be to add this to SPM's Package.swift:

.library(
  name: "SPMTestSupport",
  targets: ["SPMTestSupport"]
),

I'll take another look at using it – I'll try symlinking it or checking out and editing SPM – and if it works well for this test case I'll open an issue in the SPM repo to start a discussion.

@allevato
Copy link
Member

allevato commented Sep 6, 2023

Sources/SPMTestSupport/misc.swift is the set of functions for working with the fixtures. The SPMTestSupport library .target is not published as a product in SPM's Package.swift and AIUI, that's preventing me from setting it as a dependency for the .testTarget I had added here.

Maybe all it would take to use it here would be to add this to SPM's Package.swift:

The problem with this approach is that depending on that would make all of the swift-package-manager repository a dependency of swift-format, which we wouldn't want.

I suppose that could be partially solved by making a completely separate test package in a subdirectory, but then you have to remember to run those tests separately since swift test in the repo root wouldn't do it.

This feels like an area that SwiftPM needs to come up with a good solution for. While it would be nice to have total coverage here, I also don't feel that we should go to heroics if it's not easy to do or would be potentially fragile. (It's easier for SPM to do those full integration tests by constructing packages in a temp dir because if they change something under the hood, that project's own tests would catch it and be modified to support it. It's less easy for a downstream project.)

@BrianHenryIE
Copy link
Contributor Author

This feels like an area that SwiftPM needs to come up with a good solution for.

Agreed. I hope the SPM maintainers already have it on their mind to spin SPMTestSupport into its own package. Rewriting the test at this stage is almost more for the benefit of the swift-package-manager repository than swift-format!

Copy link
Member

@allevato allevato left a comment

Choose a reason for hiding this comment

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

Thanks for the fix! Merging now.

@allevato allevato merged commit 4bb5728 into swiftlang:main Sep 6, 2023
allevato added a commit to allevato/swift-format that referenced this pull request Sep 14, 2023
…s-fix-483

Default to all targets when plugin `--target` parameter missing. Fix swiftlang#483
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot invoke plugins from command line
2 participants