Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Fixed
- Library ownership: version-less `group:artifact` patterns now match any version of the artifact. Previously they matched nothing, silently leaving such libraries unattributed (`NA`), since real coordinates always carry a version

## [0.2.0-alpha03] - 2026-07-29

### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,17 @@ class YmlTeamMapping(


private fun findBestPatternMatch(coordinate: String, teamMapping: Map<String, List<String>>): String? {
// Priority: exact > artifact wildcard > group wildcard
// Within a team: exact > version-less coordinate > artifact wildcard > group wildcard.
// Teams are checked in file order; the first team with any matching pattern wins.
for ((team, patterns) in teamMapping) {
// Check exact match first
if (coordinate in patterns) return team

// Check version-less coordinates (com.example:library): any version of exactly that artifact
patterns.filter { !it.contains("*") && it.count { c -> c == ':' } == 1 }.forEach { pattern ->
if (coordinate.startsWith("$pattern:")) return team
}

// Check artifact wildcards (com.example:library:*)
patterns.filter { it.contains(":*") }.forEach { pattern ->
val prefix = pattern.substringBeforeLast(":*")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,31 @@ class YmlTeamMappingTest {
assertEquals(setOf("Team1", "Platform", "Networking"), teamMapping.getAllTeams())
}

@Test
fun testLibraryOwnershipVersionlessCoordinate() {
val moduleYml = tempFolder.newFile("modules.yml").apply {
writeText("Team1:\n - :module1")
}
val libraryYml = tempFolder.newFile("libraries.yml").apply {
writeText("""
Media:
- com.example.media:player
Messaging:
- com.example.media:chat-ui
""".trimIndent())
}

val teamMapping = YmlTeamMapping(moduleYml, libraryYml)

// A version-less group:artifact pattern matches any version of that artifact
assertEquals("Media", teamMapping.getLibraryOwner("com.example.media:player:1.2.3"))
assertEquals("Media", teamMapping.getLibraryOwner("com.example.media:player:2.0.0"))
assertEquals("Messaging", teamMapping.getLibraryOwner("com.example.media:chat-ui:0.9.0"))
// It must not match a different artifact sharing the name as a prefix, nor siblings
assertNull(teamMapping.getLibraryOwner("com.example.media:player-extras:1.0.0"))
assertNull(teamMapping.getLibraryOwner("com.example.media:contacts:1.0.0"))
}

@Test
fun testLibraryOwnershipArtifactWildcard() {
val moduleYml = tempFolder.newFile("modules.yml").apply {
Expand Down
5 changes: 3 additions & 2 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,9 @@ Team2:
Pattern matching is evaluated in this order; the first match wins:

1. **Exact coordinate** — e.g. `androidx.core:core-ktx:1.13.1`
2. **Group wildcard** using `:*` — e.g. `androidx.core:*` (matches any artifact under `androidx.core`)
3. **Group wildcard** using `.*` — e.g. `androidx.*` (matches any group beginning with `androidx.`)
2. **Version-less coordinate** — e.g. `androidx.core:core-ktx` (matches any version of that artifact)
3. **Group wildcard** using `:*` — e.g. `androidx.core:*` (matches any artifact under `androidx.core`)
4. **Group wildcard** using `.*` — e.g. `androidx.*` (matches any group beginning with `androidx.`)

Libraries that do not match any pattern are reported as `NA` in team reports (see [Limitations](./limitation.md)).

Expand Down
5 changes: 3 additions & 2 deletions docs/plugin.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,9 @@ Team2:
Pattern matching is evaluated in this order; the first match wins:

1. **Exact coordinate** — e.g. `androidx.core:core-ktx:1.13.1`
2. **Group wildcard** using `:*` — e.g. `androidx.core:*` (matches any artifact under `androidx.core`)
3. **Group wildcard** using `.*` — e.g. `androidx.*` (matches any group beginning with `androidx.`)
2. **Version-less coordinate** — e.g. `androidx.core:core-ktx` (matches any version of that artifact)
3. **Group wildcard** using `:*` — e.g. `androidx.core:*` (matches any artifact under `androidx.core`)
4. **Group wildcard** using `.*` — e.g. `androidx.*` (matches any group beginning with `androidx.`)

Libraries that do not match any pattern are reported as `NA` in team reports (see [Limitations](./limitation.md)).

Expand Down
Loading