Add command to lint the projects
This commit is contained in:
parent
9803ab6290
commit
8370f38cf0
|
@ -116,7 +116,7 @@ public class Generator: Generating {
|
|||
|
||||
public func generateProject(at path: AbsolutePath) throws -> (AbsolutePath, Graphing) {
|
||||
let tuistConfig = try graphLoader.loadTuistConfig(path: path)
|
||||
try environmentLinter.lint(config: tuistConfig)
|
||||
try environmentLinter.lint(config: tuistConfig).printAndThrowIfNeeded()
|
||||
|
||||
let (graph, project) = try graphLoader.loadProject(path: path)
|
||||
try graphLinter.lint(graph: graph).printAndThrowIfNeeded()
|
||||
|
@ -131,7 +131,7 @@ public class Generator: Generating {
|
|||
public func generateProjectWorkspace(at path: AbsolutePath,
|
||||
workspaceFiles: [AbsolutePath]) throws -> (AbsolutePath, Graphing) {
|
||||
let tuistConfig = try graphLoader.loadTuistConfig(path: path)
|
||||
try environmentLinter.lint(config: tuistConfig)
|
||||
try environmentLinter.lint(config: tuistConfig).printAndThrowIfNeeded()
|
||||
|
||||
let (graph, project) = try graphLoader.loadProject(path: path)
|
||||
try graphLinter.lint(graph: graph).printAndThrowIfNeeded()
|
||||
|
@ -151,7 +151,7 @@ public class Generator: Generating {
|
|||
public func generateWorkspace(at path: AbsolutePath,
|
||||
workspaceFiles: [AbsolutePath]) throws -> (AbsolutePath, Graphing) {
|
||||
let tuistConfig = try graphLoader.loadTuistConfig(path: path)
|
||||
try environmentLinter.lint(config: tuistConfig)
|
||||
try environmentLinter.lint(config: tuistConfig).printAndThrowIfNeeded()
|
||||
let (graph, workspace) = try graphLoader.loadWorkspace(path: path)
|
||||
try graphLinter.lint(graph: graph).printAndThrowIfNeeded()
|
||||
|
||||
|
|
|
@ -2,25 +2,24 @@ import Foundation
|
|||
import TuistCore
|
||||
import TuistSupport
|
||||
|
||||
protocol EnvironmentLinting {
|
||||
public protocol EnvironmentLinting {
|
||||
/// Lints a given Tuist configuration.
|
||||
///
|
||||
/// - Parameter config: Tuist configuration to be linted against the system.
|
||||
/// - Throws: An error if the validation fails.
|
||||
func lint(config: TuistConfig) throws
|
||||
/// - Returns: A list of linting issues.
|
||||
func lint(config: TuistConfig) throws -> [LintingIssue]
|
||||
}
|
||||
|
||||
class EnvironmentLinter: EnvironmentLinting {
|
||||
/// Lints a given Tuist configuration.
|
||||
///
|
||||
/// - Parameter config: Tuist configuration to be linted against the system.
|
||||
/// - Throws: An error if the validation fails.
|
||||
func lint(config: TuistConfig) throws {
|
||||
public class EnvironmentLinter: EnvironmentLinting {
|
||||
/// Default constructor.
|
||||
public init() {}
|
||||
|
||||
public func lint(config: TuistConfig) throws -> [LintingIssue] {
|
||||
var issues = [LintingIssue]()
|
||||
|
||||
issues.append(contentsOf: try lintXcodeVersion(config: config))
|
||||
|
||||
try issues.printAndThrowIfNeeded()
|
||||
return issues
|
||||
}
|
||||
|
||||
/// Returns a linting issue if the selected version of Xcode is not compatible with the
|
||||
|
|
|
@ -3,12 +3,12 @@ import SPMUtility
|
|||
import TuistCore
|
||||
import TuistSupport
|
||||
|
||||
protocol GraphLinting: AnyObject {
|
||||
public protocol GraphLinting: AnyObject {
|
||||
func lint(graph: Graphing) -> [LintingIssue]
|
||||
}
|
||||
|
||||
// swiftlint:disable type_body_length
|
||||
class GraphLinter: GraphLinting {
|
||||
public class GraphLinter: GraphLinting {
|
||||
// MARK: - Attributes
|
||||
|
||||
private let projectLinter: ProjectLinting
|
||||
|
@ -16,15 +16,20 @@ class GraphLinter: GraphLinting {
|
|||
|
||||
// MARK: - Init
|
||||
|
||||
init(projectLinter: ProjectLinting = ProjectLinter(),
|
||||
staticProductsLinter: StaticProductsGraphLinting = StaticProductsGraphLinter()) {
|
||||
public convenience init() {
|
||||
self.init(projectLinter: ProjectLinter(),
|
||||
staticProductsLinter: StaticProductsGraphLinter())
|
||||
}
|
||||
|
||||
init(projectLinter: ProjectLinting,
|
||||
staticProductsLinter: StaticProductsGraphLinting) {
|
||||
self.projectLinter = projectLinter
|
||||
self.staticProductsLinter = staticProductsLinter
|
||||
}
|
||||
|
||||
// MARK: - GraphLinting
|
||||
|
||||
func lint(graph: Graphing) -> [LintingIssue] {
|
||||
public func lint(graph: Graphing) -> [LintingIssue] {
|
||||
var issues: [LintingIssue] = []
|
||||
issues.append(contentsOf: graph.projects.flatMap(projectLinter.lint))
|
||||
issues.append(contentsOf: lintDependencies(graph: graph))
|
||||
|
|
|
@ -28,6 +28,7 @@ public final class CommandRegistry {
|
|||
register(command: GraphCommand.self)
|
||||
register(command: EditCommand.self)
|
||||
register(command: CacheCommand.self)
|
||||
register(command: LintCommand.self)
|
||||
register(rawCommand: BuildCommand.self)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
import Basic
|
||||
import Foundation
|
||||
import SPMUtility
|
||||
import TuistCore
|
||||
import TuistGenerator
|
||||
import TuistLoader
|
||||
import TuistSupport
|
||||
|
||||
enum LintCommandError: FatalError, Equatable {
|
||||
/// Thrown when neither a workspace or a project is found in the given path.
|
||||
case manifestNotFound(AbsolutePath)
|
||||
|
||||
/// Error type.
|
||||
var type: ErrorType {
|
||||
switch self {
|
||||
case .manifestNotFound:
|
||||
return .abort
|
||||
}
|
||||
}
|
||||
|
||||
/// Description
|
||||
var description: String {
|
||||
switch self {
|
||||
case let .manifestNotFound(path):
|
||||
return "Couldn't find Project.swift nor Workspace.swift at \(path.pathString)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Command that builds a target from the project in the current directory.
|
||||
class LintCommand: NSObject, Command {
|
||||
/// Command name.
|
||||
static var command: String = "lint"
|
||||
|
||||
/// Command description.
|
||||
static var overview: String = "Lints a workspace or a project that check whether they are well configured."
|
||||
|
||||
/// Graph linter
|
||||
private let graphLinter: GraphLinting
|
||||
private let environmentLinter: EnvironmentLinting
|
||||
private let manifestLoading: ManifestLoading
|
||||
private let graphLoader: GraphLoading
|
||||
let pathArgument: OptionArgument<String>
|
||||
|
||||
/// Default constructor.
|
||||
public required convenience init(parser: ArgumentParser) {
|
||||
let manifestLoader = ManifestLoader()
|
||||
let generatorModelLoader = GeneratorModelLoader(manifestLoader: manifestLoader,
|
||||
manifestLinter: AnyManifestLinter())
|
||||
self.init(graphLinter: GraphLinter(),
|
||||
environmentLinter: EnvironmentLinter(),
|
||||
manifestLoading: manifestLoader,
|
||||
graphLoader: GraphLoader(modelLoader: generatorModelLoader),
|
||||
parser: parser)
|
||||
}
|
||||
|
||||
init(graphLinter: GraphLinting,
|
||||
environmentLinter: EnvironmentLinting,
|
||||
manifestLoading: ManifestLoading,
|
||||
graphLoader: GraphLoading,
|
||||
parser: ArgumentParser) {
|
||||
let subParser = parser.add(subparser: LintCommand.command, overview: LintCommand.overview)
|
||||
self.graphLinter = graphLinter
|
||||
self.environmentLinter = environmentLinter
|
||||
self.manifestLoading = manifestLoading
|
||||
self.graphLoader = graphLoader
|
||||
pathArgument = subParser.add(option: "--path",
|
||||
shortName: "-p",
|
||||
kind: String.self,
|
||||
usage: "The path to the directory that contains the workspace or project to be linted",
|
||||
completion: .filename)
|
||||
}
|
||||
|
||||
func run(with arguments: ArgumentParser.Result) throws {
|
||||
let path = self.path(arguments: arguments)
|
||||
|
||||
// Load graph
|
||||
let manifests = manifestLoading.manifests(at: path)
|
||||
var graph: Graphing!
|
||||
|
||||
Printer.shared.print(section: "Loading the dependency graph")
|
||||
if manifests.contains(.workspace) {
|
||||
Printer.shared.print("Loading workspace at \(path.pathString)")
|
||||
(graph, _) = try graphLoader.loadWorkspace(path: path)
|
||||
} else if manifests.contains(.project) {
|
||||
Printer.shared.print("Loading project at \(path.pathString)")
|
||||
(graph, _) = try graphLoader.loadProject(path: path)
|
||||
} else {
|
||||
throw LintCommandError.manifestNotFound(path)
|
||||
}
|
||||
|
||||
Printer.shared.print(section: "Running linters")
|
||||
let config = try graphLoader.loadTuistConfig(path: path)
|
||||
|
||||
var issues: [LintingIssue] = []
|
||||
Printer.shared.print("Linting the environment")
|
||||
issues.append(contentsOf: try environmentLinter.lint(config: config))
|
||||
Printer.shared.print("Linting the loaded dependency graph")
|
||||
issues.append(contentsOf: graphLinter.lint(graph: graph))
|
||||
|
||||
if issues.isEmpty {
|
||||
Printer.shared.print(success: "No linting issues found")
|
||||
} else {
|
||||
try issues.printAndThrowIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
private func path(arguments: ArgumentParser.Result) -> AbsolutePath {
|
||||
if let path = arguments.get(pathArgument) {
|
||||
return AbsolutePath(path, relativeTo: FileHandler.shared.currentPath)
|
||||
} else {
|
||||
return FileHandler.shared.currentPath
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,6 +7,22 @@ public protocol ManifestLinting {
|
|||
func lint(project: ProjectDescription.Project) -> [LintingIssue]
|
||||
}
|
||||
|
||||
public class AnyManifestLinter: ManifestLinting {
|
||||
let lint: ((ProjectDescription.Project) -> [LintingIssue])?
|
||||
|
||||
public init(lint: ((ProjectDescription.Project) -> [LintingIssue])? = nil) {
|
||||
self.lint = lint
|
||||
}
|
||||
|
||||
public func lint(project: ProjectDescription.Project) -> [LintingIssue] {
|
||||
if let lint = self.lint {
|
||||
return lint(project)
|
||||
} else {
|
||||
return []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ManifestLinter: ManifestLinting {
|
||||
public init() {}
|
||||
|
||||
|
|
|
@ -3,13 +3,11 @@ import TuistCore
|
|||
@testable import TuistGenerator
|
||||
|
||||
final class MockEnvironmentLinter: EnvironmentLinting {
|
||||
var lintStub: Error?
|
||||
var lintStub: [LintingIssue]?
|
||||
var lintArgs: [TuistConfig] = []
|
||||
|
||||
func lint(config: TuistConfig) throws {
|
||||
func lint(config: TuistConfig) throws -> [LintingIssue] {
|
||||
lintArgs.append(config)
|
||||
if let error = lintStub {
|
||||
throw error
|
||||
}
|
||||
return lintStub ?? []
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue