Skip to content

Commit

Permalink
shared_schemes rule
Browse files Browse the repository at this point in the history
  • Loading branch information
mattmassicotte committed Feb 19, 2024
1 parent aaba185 commit b869601
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 2 deletions.
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/tuist/XcodeProj",
"state" : {
"revision" : "a3e5d54f8c8a2964ee54870fda33b28651416581",
"version" : "8.17.0"
"revision" : "e29e0db843062f5157f77d5b68f237eb5aa43f12",
"version" : "8.18.0"
}
},
{
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ opt_in_rules:
- targets_use_xcconfig # checks for any targets without a XCConfig file set
- projects_use_xcconfig # checks for any projects without a XCConfig file set
- shared_scheme_skips_tests # checks for any shared schemes that have disabled tests
- shared_schemes # checks that all targets have a shared scheme present

# Other rules make sense for all projects by default. You must opt-out of those.
disabled_rules:
Expand Down
37 changes: 37 additions & 0 deletions Sources/XCLinting/Rules/HasSharedSchemeRule.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation

import XcodeProj
import XCConfig

/// Ensure that targets have a shared scheme on disk.
struct SharedSchemesRule {
func run(_ environment: XCLinter.Environment) throws -> [Violation] {
let sharedSchemesURL = environment
.projectRootURL
.appendingPathComponent("xcshareddata/xcschemes", isDirectory: true)
.standardizedFileURL

let fileManager = FileManager.default

guard fileManager.isReadableFile(atPath: sharedSchemesURL.path) else {
return [.init("Shared scheme directory not found")]
}

let schemes = Set(try fileManager.contentsOfDirectory(atPath: sharedSchemesURL.path))

var violations = [Violation]()

// check targets
environment.project.pbxproj.enumerateBuildConfigurations { name, configList in
let schemeName = name + ".xcscheme"

if schemes.contains(schemeName) {
return
}

violations.append(.init("No shared scheme found for \"\(name)\""))
}

return violations
}
}
1 change: 1 addition & 0 deletions Sources/XCLinting/XCLinter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,6 @@ extension XCLinter {
"projects_use_xcconfig": { try ProjectsUseXCConfigRule().run($0) },
"shared_scheme_skips_tests": { try SharedSchemeSkipsTestsRule().run($0) },
"relative_paths": { try RelativePathsRule().run($0) },
"shared_schemes": { try SharedSchemesRule().run($0) },
]
}
38 changes: 38 additions & 0 deletions Tests/XCLintTests/SharedSchemesRuleTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import XCTest

@testable import XCLinting
import XcodeProj

final class SharedSchemesRuleTests: XCTestCase {
func testProjectWithSharedSchemes() throws {
let url = try Bundle.module.testDataURL(named: "StockMacOSApp.xcodeproj")

let project = try XcodeProj(pathString: url.path)

let env = XCLinter.Environment(
project: project,
projectRootURL: url,
configuration: Configuration()
)

let violations = try SharedSchemesRule().run(env)

XCTAssertTrue(violations.isEmpty)
}

func testProjectWithMissingSharedSchemes() throws {
let url = try Bundle.module.testDataURL(named: "SchemeSkipsTests.xcodeproj")

let project = try XcodeProj(pathString: url.path)

let env = XCLinter.Environment(
project: project,
projectRootURL: url,
configuration: Configuration()
)

let violations = try SharedSchemesRule().run(env)

XCTAssertFalse(violations.isEmpty)
}
}

0 comments on commit b869601

Please sign in to comment.