You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Introduce a phase: namespace prefix within the existing tags property of repository plugins to cleanly separate bnd lifecycle roles (phases) from user-defined categorization tags. This is a planned breaking-change improvement targeted at bnd 8.0.0.
The current tags property on repository plugins (introduced in bnd 7.1.0) serves two conflicting purposes:
Lifecycle control — the reserved resolve tag controls which repos participate in OSGi resolution (-runrepos, BndrunResolveContext). There is currently no equivalent tag for controlling which repos contribute to -buildpath, -testpath, -baseline, or -releaserepo.
User categorization — users can add arbitrary tags (e.g. team-a, qa, snapshots) for their own filtering needs.
This conflation causes several problems:
Missing lifecycle axes: there is no way to express "this repo is for baseline checks only" or "this repo should be on the compile classpath but not in the OSGi resolver" using tags today.
Opt-in silent cliff: once any repo in the workspace gets a resolve tag, all untagged repos silently drop out of OSGi resolution — a confusing and hard-to-diagnose behavior.
Hack workarounds: users resort to tags = "<<EMPTY>>" or assigning meaningless tags just to exclude a repo from resolution.
-runrepos is name-based only: filtering run repositories requires listing fragile repo names; there is no way to filter by semantic intent or category.
Proposed Solution: phase: Namespace Prefix in tags
Keep the single tags property, but introduce a phase: prefix convention to distinguish bnd-owned lifecycle roles from user-defined tags.
Syntax
tags = "phase:resolve, phase:compile, team-a, qa"
Tags starting with phase: are reserved by bnd and control lifecycle participation.
All other tags are user-defined and have no built-in bnd semantics.
Reserved Phase Tags
Tag
Meaning
phase:resolve
Repo participates in OSGi resolution (-runrepos / BndrunResolveContext)
phase:compile
Repo contributes to -buildpath / Eclipse classpath (Project.getRepositories())
phase:test
Repo contributes to -testpath
phase:baseline
Repo is considered for -baseline version checks
phase:release
Repo is a target for -releaserepo
phase:none
Explicit sentinel: repo participates in no bnd lifecycle phase
Backward Compatibility Rules
The new method Tags.includesPhase(String phase) replaces the current Tags.includesAny(String... tags) for all internal phase checks, with the following logic:
Repo tags value
includesPhase("compile")
Rationale
(not set / empty)
true
Untagged repos participate in all phases — unchanged behavior
Treated as a plain user tag — warn that "resolve" no longer has lifecycle meaning
"phase:compile, phase:resolve"
true
Explicit phase opt-in
"phase:resolve"
false
Only in resolver, not on compile classpath
"phase:none, research"
false
Explicitly excluded from all lifecycle phases
This means zero migration is required for existing workspaces that do not use phase: prefixed tags. The new behavior only activates when a repo has at least one phase: tag.
Implementation Sketch
Tags.java
Add to aQute.bnd.service.tags.Tags:
privatestaticfinalStringPHASE_PREFIX = "phase:";
/** * Phase-aware inclusion check (bnd 8.0.0). * Rules: * 1. Empty tags → true (untagged = all phases, backward compat) * 2. No phase: tags present → true (user-only tags = all phases, backward compat) * 3. "phase:none" present → false (explicit exclusion) * 4. Otherwise → check if "phase:<phase>" is in the set */publicbooleanincludesPhase(Stringphase) {
if (isEmpty()) returntrue;
booleanhasAnyPhaseTag = internalSet.stream().anyMatch(t -> t.startsWith(PHASE_PREFIX));
if (!hasAnyPhaseTag) returntrue;
if (internalSet.contains(PHASE_PREFIX + "none")) returnfalse;
returninternalSet.contains(PHASE_PREFIX + phase);
}
/** Returns only the phase: tags */publicTagsphases() {
returnnewTags(internalSet.stream()
.filter(t -> t.startsWith(PHASE_PREFIX))
.collect(Collectors.toList()));
}
/** Returns only the user-defined tags (non-phase:) */publicTagsuserTags() {
returnnewTags(internalSet.stream()
.filter(t -> !t.startsWith(PHASE_PREFIX))
.collect(Collectors.toList()));
}
Summary
Introduce a
phase:namespace prefix within the existingtagsproperty of repository plugins to cleanly separate bnd lifecycle roles (phases) from user-defined categorization tags. This is a planned breaking-change improvement targeted at bnd 8.0.0.Related draft PR (earlier approach, now superseded by this design): #6612
Related forum discussion: https://bnd.discourse.group/t/baseline-repo-exclude-from-the-build-path/391/2
Problem
The current
tagsproperty on repository plugins (introduced in bnd 7.1.0) serves two conflicting purposes:resolvetag controls which repos participate in OSGi resolution (-runrepos,BndrunResolveContext). There is currently no equivalent tag for controlling which repos contribute to-buildpath,-testpath,-baseline, or-releaserepo.team-a,qa,snapshots) for their own filtering needs.This conflation causes several problems:
resolvetag, all untagged repos silently drop out of OSGi resolution — a confusing and hard-to-diagnose behavior.tags = "<<EMPTY>>"or assigning meaningless tags just to exclude a repo from resolution.Project.getRepositories()gap: there is currently no tag-based way to exclude a repo from-buildpath/ the Eclipse classpath (this is what PR allow excluding repositories from Project -buildpath via tags #6612 attempted to solve).-runreposis name-based only: filtering run repositories requires listing fragile repo names; there is no way to filter by semantic intent or category.Proposed Solution:
phase:Namespace Prefix intagsKeep the single
tagsproperty, but introduce aphase:prefix convention to distinguish bnd-owned lifecycle roles from user-defined tags.Syntax
phase:are reserved by bnd and control lifecycle participation.Reserved Phase Tags
phase:resolve-runrepos/BndrunResolveContext)phase:compile-buildpath/ Eclipse classpath (Project.getRepositories())phase:test-testpathphase:baseline-baselineversion checksphase:release-releaserepophase:noneBackward Compatibility Rules
The new method
Tags.includesPhase(String phase)replaces the currentTags.includesAny(String... tags)for all internal phase checks, with the following logic:tagsvalueincludesPhase("compile")true"team-a, qa"(user tags only, nophase:)true"resolve"(legacy, no prefix)true"resolve"no longer has lifecycle meaning"phase:compile, phase:resolve"true"phase:resolve"false"phase:none, research"falseThis means zero migration is required for existing workspaces that do not use
phase:prefixed tags. The new behavior only activates when a repo has at least onephase:tag.Implementation Sketch
Tags.javaAdd to
aQute.bnd.service.tags.Tags:Constants.javaProject.javaBndrunResolveContext.javaChange
getPlugins(Repository.class, Constants.REPOTAGS_RESOLVE)to useincludesPhase("resolve")consistently.-runrepostag-based filtering (optional / future)Extend
-runreposto support filtering by user tags in addition to repo names:This allows
.bndrunfiles to select repos by semantic intent rather than fragile names.Usage Examples
Research/browsing repo — excluded from all lifecycle
Standard workspace repo
Baseline-only repo
QA snapshot repo — filtered in bndrun by user tag
Acceptance Criteria
Tags.includesPhase(String phase)method added with the backward-compatible rules described aboveTags.phases()andTags.userTags()helper methods addedConstants.java(REPOTAG_PHASE_RESOLVE,REPOTAG_PHASE_COMPILE, etc.)Project.getRepositories()filters byphase:compileBndrunResolveContextusesphase:resolve/includesPhase()phase:tags are presenttags = "resolve"(without prefix) is used, guiding migration870-plugins.md,-runreposinstruction pagephase:none, mixed phase+user tags, per-phase filteringDisclaimer: Above is the result and conclusion of a Copilot session which I found fits quite good as a base for discussion.