A Swift compiler plugin to propagate CODEOWNERS attribution to Swift types
Setup the compiler plugin and the runtime library in your project:
In your Package.swift add the plugin dependency:
let package = Package(
name: "MyProject",
dependencies: [
.package(url: "https://github.com/gmazzo/swift-codeowners-plugin", from: "x.y.z"),
],
targets: [
.target(
name: "MyProjectTarget",
dependencies: [
.product(name: "CodeOwnersAPI", package: "swift-codeowners-plugin")
],
plugins: [
.plugin(name: "CodeOwnersPlugin", package: "swift-codeowners-plugin")
]
)
]
)Then you can use the codeOwnersOf function on any struct, class or enum to query their owners at runtime:
struct MyType {
func printOwner() {
print("This type is owned by \(codeOwnersOf(self))") // or
print("This type is owned by \(codeOwnersOf(MyType.self))") // or
print("This type is owned by \(codeOwnersOf(MyType()))") // or
}
}As an alternative or complementary approach, can you also define and use a #codeowners embed the owners of a file at compile time:
class MyClass {
static let owners = #codeowners
func printOwner() {
print("This file is owned by \(#owners)")
}
}
Note
Due Swift macros limitations, the #codeowners macro can not be provided out-of-the-box,
and it requires instead to define an ad-hoc .macro target in your project.
First, declare a new macro target in your Package.swift (if you don't have one yet):
targets: [
.macro(
name: "MyMacros",
dependencies: [
.product(name: "CodeOwnersMacro", package: "swift-codeowners-plugin"),
],
plugins: [
.plugin(name: "CodeOwnersMacroPlugin", package: "swift-codeowners-plugin")
]
)
]And make sure you define a CompilerPlugin exposing the CodeOwnersMacro:
import SwiftCompilerPlugin
import SwiftSyntaxMacros
@main
struct MacrosPlugin: CompilerPlugin {
let providingMacros: [Macro.Type] = [ CodeOwnersMacro.self ]
}Note
The CodeOwnersMacro type will be generated by the CodeOwnersMacroPlugin plugin
Then let your main target depend on the macro target:
targets: [
.target(
name: "MyProject",
dependencies: [
"MyMacros" // <-- add this line
]
)
]Finally, import the macro module and use the #codeowners macro in your code:
@freestanding(expression)
public macro codeOwners() -> [String]? = #externalMacro(module: "MyMacros", type: "CodeOwnersMacro")The expected format is the same as GitHub's and it can be located at any of the following paths:
$rootDir/CODEOWNERS$rootDir/.github/CODEOWNERS$rootDir/.gitlab/CODEOWNERS$rootDir/docs/CODEOWNERS
Where rootDir is either project's or GIT's root directory
The .codeowners-tool.json configuration file
You can customize the plugin behavior by adding a .codeowners-tool.json file:
{
"codeOwners": {
"root": ".", // The root directory where the CODEOWNERS file patterns are based from.
"file": ".github/CODEOWNERS" // The CODEOWNERS file to use for determining ownership.
},
"renames": {
"regEx": "replacement" // Regex pattern to rename ownership names, in <regex>=<replacement> format)
},
"verbose": true, // Enable verbose output for debugging purposes.
"quiet": true // Suppress non-error output.
}