Add team property to all modules.
This allows vendors (like google) to specify which team owns the test module and code. Team is a commonProperty on modules and points to the designate "team" module. The DepsMutator adds the dependency on the "team" module and "GenerateBuildActions" write the team data to intermediate files. A new singleton rule, all_teams visits all modules and writes out the proto containing the team for each module. If a module doesn't have a team, then it finds the package in the blueprint file and parent directory blueprint files that have a default_team and uses that team. Test: m all_teams Test: go test ./python ./java ./cc ./rust ./android Test: added team to HelloWorldHostTest and built the new asciiproto target Test: added package default_team and checkout output proto. Change-Id: I5c07bf489de460a04fc540f5fff0394f39f574a7
This commit is contained in:
parent
ee18a66643
commit
73b08ffd0d
13 changed files with 878 additions and 0 deletions
|
@ -11,6 +11,7 @@ bootstrap_go_package {
|
|||
"blueprint-metrics",
|
||||
"sbox_proto",
|
||||
"soong",
|
||||
"soong-android_team_proto",
|
||||
"soong-android-soongconfig",
|
||||
"soong-remoteexec",
|
||||
"soong-response",
|
||||
|
@ -28,6 +29,7 @@ bootstrap_go_package {
|
|||
],
|
||||
srcs: [
|
||||
"aconfig_providers.go",
|
||||
"all_teams.go",
|
||||
"androidmk.go",
|
||||
"apex.go",
|
||||
"apex_contributions.go",
|
||||
|
@ -91,6 +93,7 @@ bootstrap_go_package {
|
|||
"singleton.go",
|
||||
"singleton_module.go",
|
||||
"soong_config_modules.go",
|
||||
"team.go",
|
||||
"test_asserts.go",
|
||||
"test_suites.go",
|
||||
"testing.go",
|
||||
|
|
158
android/all_teams.go
Normal file
158
android/all_teams.go
Normal file
|
@ -0,0 +1,158 @@
|
|||
package android
|
||||
|
||||
import (
|
||||
"android/soong/android/team_proto"
|
||||
"path/filepath"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const ownershipDirectory = "ownership"
|
||||
const allTeamsFile = "all_teams.pb"
|
||||
|
||||
func AllTeamsFactory() Singleton {
|
||||
return &allTeamsSingleton{}
|
||||
}
|
||||
|
||||
func init() {
|
||||
registerAllTeamBuildComponents(InitRegistrationContext)
|
||||
}
|
||||
|
||||
func registerAllTeamBuildComponents(ctx RegistrationContext) {
|
||||
ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
|
||||
}
|
||||
|
||||
// For each module, list the team or the bpFile the module is defined in.
|
||||
type moduleTeamInfo struct {
|
||||
teamName string
|
||||
bpFile string
|
||||
}
|
||||
|
||||
type allTeamsSingleton struct {
|
||||
// Path where the collected metadata is stored after successful validation.
|
||||
outputPath OutputPath
|
||||
|
||||
// Map of all package modules we visit during GenerateBuildActions
|
||||
packages map[string]packageProperties
|
||||
// Map of all team modules we visit during GenerateBuildActions
|
||||
teams map[string]teamProperties
|
||||
// Keeps track of team information or bp file for each module we visit.
|
||||
teams_for_mods map[string]moduleTeamInfo
|
||||
}
|
||||
|
||||
// See if there is a package module for the given bpFilePath with a team defined, if so return the team.
|
||||
// If not ascend up to the parent directory and do the same.
|
||||
func (this *allTeamsSingleton) lookupDefaultTeam(bpFilePath string) (teamProperties, bool) {
|
||||
// return the Default_team listed in the package if is there.
|
||||
if p, ok := this.packages[bpFilePath]; ok {
|
||||
if t := p.Default_team; t != nil {
|
||||
return this.teams[*p.Default_team], true
|
||||
}
|
||||
}
|
||||
// Strip a directory and go up.
|
||||
// Does android/paths.go basePath,SourcePath help?
|
||||
current, base := filepath.Split(bpFilePath)
|
||||
current = filepath.Clean(current) // removes trailing slash, convert "" -> "."
|
||||
parent, _ := filepath.Split(current)
|
||||
if current == "." {
|
||||
return teamProperties{}, false
|
||||
}
|
||||
return this.lookupDefaultTeam(filepath.Join(parent, base))
|
||||
}
|
||||
|
||||
// Create a rule to run a tool to collect all the intermediate files
|
||||
// which list the team per module into one proto file.
|
||||
func (this *allTeamsSingleton) GenerateBuildActions(ctx SingletonContext) {
|
||||
this.packages = make(map[string]packageProperties)
|
||||
this.teams = make(map[string]teamProperties)
|
||||
this.teams_for_mods = make(map[string]moduleTeamInfo)
|
||||
|
||||
ctx.VisitAllModules(func(module Module) {
|
||||
if !module.Enabled() {
|
||||
return
|
||||
}
|
||||
|
||||
bpFile := ctx.BlueprintFile(module)
|
||||
|
||||
// Package Modules and Team Modules are stored in a map so we can look them up by name for
|
||||
// modules without a team.
|
||||
if pack, ok := module.(*packageModule); ok {
|
||||
// Packages don't have names, use the blueprint file as the key. we can't get qualifiedModuleId in this context.
|
||||
pkgKey := bpFile
|
||||
this.packages[pkgKey] = pack.properties
|
||||
return
|
||||
}
|
||||
if team, ok := module.(*teamModule); ok {
|
||||
this.teams[team.Name()] = team.properties
|
||||
return
|
||||
}
|
||||
|
||||
// If a team name is given for a module, store it.
|
||||
// Otherwise store the bpFile so we can do a package walk later.
|
||||
if module.base().Team() != "" {
|
||||
this.teams_for_mods[module.Name()] = moduleTeamInfo{teamName: module.base().Team(), bpFile: bpFile}
|
||||
} else {
|
||||
this.teams_for_mods[module.Name()] = moduleTeamInfo{bpFile: bpFile}
|
||||
}
|
||||
})
|
||||
|
||||
// Visit all modules again and lookup the team name in the package or parent package if the team
|
||||
// isn't assignged at the module level.
|
||||
allTeams := this.lookupTeamForAllModules()
|
||||
|
||||
this.outputPath = PathForOutput(ctx, ownershipDirectory, allTeamsFile)
|
||||
data, err := proto.Marshal(allTeams)
|
||||
if err != nil {
|
||||
ctx.Errorf("Unable to marshal team data. %s", err)
|
||||
}
|
||||
|
||||
WriteFileRuleVerbatim(ctx, this.outputPath, string(data))
|
||||
ctx.Phony("all_teams", this.outputPath)
|
||||
}
|
||||
|
||||
func (this *allTeamsSingleton) MakeVars(ctx MakeVarsContext) {
|
||||
ctx.DistForGoal("all_teams", this.outputPath)
|
||||
}
|
||||
|
||||
// Visit every (non-package, non-team) module and write out a proto containing
|
||||
// either the declared team data for that module or the package default team data for that module.
|
||||
func (this *allTeamsSingleton) lookupTeamForAllModules() *team_proto.AllTeams {
|
||||
teamsProto := make([]*team_proto.Team, len(this.teams_for_mods))
|
||||
i := 0
|
||||
for moduleName, m := range this.teams_for_mods {
|
||||
teamName := m.teamName
|
||||
var teamProperties teamProperties
|
||||
found := false
|
||||
if teamName != "" {
|
||||
teamProperties, found = this.teams[teamName]
|
||||
} else {
|
||||
teamProperties, found = this.lookupDefaultTeam(m.bpFile)
|
||||
}
|
||||
|
||||
trendy_team_id := ""
|
||||
if found {
|
||||
trendy_team_id = *teamProperties.Trendy_team_id
|
||||
}
|
||||
|
||||
var files []string
|
||||
teamData := new(team_proto.Team)
|
||||
if trendy_team_id != "" {
|
||||
*teamData = team_proto.Team{
|
||||
TrendyTeamId: proto.String(trendy_team_id),
|
||||
TargetName: proto.String(moduleName),
|
||||
Path: proto.String(m.bpFile),
|
||||
File: files,
|
||||
}
|
||||
} else {
|
||||
// Clients rely on the TrendyTeamId optional field not being set.
|
||||
*teamData = team_proto.Team{
|
||||
TargetName: proto.String(moduleName),
|
||||
Path: proto.String(m.bpFile),
|
||||
File: files,
|
||||
}
|
||||
}
|
||||
teamsProto[i] = teamData
|
||||
i++
|
||||
}
|
||||
return &team_proto.AllTeams{Teams: teamsProto}
|
||||
}
|
208
android/all_teams_test.go
Normal file
208
android/all_teams_test.go
Normal file
|
@ -0,0 +1,208 @@
|
|||
// Copyright 2024 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package android
|
||||
|
||||
import (
|
||||
"android/soong/android/team_proto"
|
||||
"log"
|
||||
"testing"
|
||||
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
func TestAllTeams(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := GroupFixturePreparers(
|
||||
PrepareForTestWithTeamBuildComponents,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("fake", fakeModuleFactory)
|
||||
ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
|
||||
}),
|
||||
).RunTestWithBp(t, `
|
||||
fake {
|
||||
name: "main_test",
|
||||
team: "someteam",
|
||||
}
|
||||
team {
|
||||
name: "someteam",
|
||||
trendy_team_id: "cool_team",
|
||||
}
|
||||
|
||||
team {
|
||||
name: "team2",
|
||||
trendy_team_id: "22222",
|
||||
}
|
||||
|
||||
fake {
|
||||
name: "tool",
|
||||
team: "team2",
|
||||
}
|
||||
|
||||
fake {
|
||||
name: "noteam",
|
||||
}
|
||||
`)
|
||||
|
||||
var teams *team_proto.AllTeams
|
||||
teams = getTeamProtoOutput(t, ctx)
|
||||
|
||||
// map of module name -> trendy team name.
|
||||
actualTeams := make(map[string]*string)
|
||||
for _, teamProto := range teams.Teams {
|
||||
actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId
|
||||
}
|
||||
expectedTeams := map[string]*string{
|
||||
"main_test": proto.String("cool_team"),
|
||||
"tool": proto.String("22222"),
|
||||
"noteam": nil,
|
||||
}
|
||||
|
||||
AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
|
||||
}
|
||||
|
||||
func getTeamProtoOutput(t *testing.T, ctx *TestResult) *team_proto.AllTeams {
|
||||
teams := new(team_proto.AllTeams)
|
||||
config := ctx.SingletonForTests("all_teams")
|
||||
allOutputs := config.AllOutputs()
|
||||
|
||||
protoPath := allOutputs[0]
|
||||
|
||||
out := config.MaybeOutput(protoPath)
|
||||
outProto := []byte(ContentFromFileRuleForTests(t, ctx.TestContext, out))
|
||||
if err := proto.Unmarshal(outProto, teams); err != nil {
|
||||
log.Fatalln("Failed to parse teams proto:", err)
|
||||
}
|
||||
return teams
|
||||
}
|
||||
|
||||
// Android.bp
|
||||
//
|
||||
// team: team_top
|
||||
//
|
||||
// # dir1 has no modules with teams,
|
||||
// # but has a dir with no Android.bp
|
||||
// dir1/Android.bp
|
||||
//
|
||||
// module_dir1
|
||||
//
|
||||
// # dirs without and Android.bp should be fine.
|
||||
// dir1/dir2/dir3/Android.bp
|
||||
//
|
||||
// package {}
|
||||
// module_dir123
|
||||
//
|
||||
// teams_dir/Android.bp
|
||||
//
|
||||
// module_with_team1: team1
|
||||
// team1: 111
|
||||
//
|
||||
// # team comes from upper package default
|
||||
// teams_dir/deeper/Android.bp
|
||||
//
|
||||
// module2_with_team1: team1
|
||||
//
|
||||
// package_defaults/Android.bp
|
||||
// package_defaults/pd2/Android.bp
|
||||
//
|
||||
// package{ default_team: team_top}
|
||||
// module_pd2 ## should get team_top
|
||||
//
|
||||
// package_defaults/pd2/pd3/Android.bp
|
||||
//
|
||||
// module_pd3 ## should get team_top
|
||||
func TestPackageLookup(t *testing.T) {
|
||||
t.Parallel()
|
||||
rootBp := `
|
||||
team {
|
||||
name: "team_top",
|
||||
trendy_team_id: "trendy://team_top",
|
||||
} `
|
||||
|
||||
dir1Bp := `
|
||||
fake {
|
||||
name: "module_dir1",
|
||||
} `
|
||||
dir3Bp := `
|
||||
package {}
|
||||
fake {
|
||||
name: "module_dir123",
|
||||
} `
|
||||
teamsDirBp := `
|
||||
fake {
|
||||
name: "module_with_team1",
|
||||
team: "team1"
|
||||
|
||||
}
|
||||
team {
|
||||
name: "team1",
|
||||
trendy_team_id: "111",
|
||||
} `
|
||||
teamsDirDeeper := `
|
||||
fake {
|
||||
name: "module2_with_team1",
|
||||
team: "team1"
|
||||
} `
|
||||
// create an empty one.
|
||||
packageDefaultsBp := ""
|
||||
packageDefaultspd2 := `
|
||||
package { default_team: "team_top"}
|
||||
fake {
|
||||
name: "modulepd2",
|
||||
} `
|
||||
|
||||
packageDefaultspd3 := `
|
||||
fake {
|
||||
name: "modulepd3",
|
||||
}
|
||||
fake {
|
||||
name: "modulepd3b",
|
||||
team: "team1"
|
||||
} `
|
||||
|
||||
ctx := GroupFixturePreparers(
|
||||
PrepareForTestWithTeamBuildComponents,
|
||||
PrepareForTestWithPackageModule,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("fake", fakeModuleFactory)
|
||||
ctx.RegisterParallelSingletonType("all_teams", AllTeamsFactory)
|
||||
}),
|
||||
FixtureAddTextFile("Android.bp", rootBp),
|
||||
FixtureAddTextFile("dir1/Android.bp", dir1Bp),
|
||||
FixtureAddTextFile("dir1/dir2/dir3/Android.bp", dir3Bp),
|
||||
FixtureAddTextFile("teams_dir/Android.bp", teamsDirBp),
|
||||
FixtureAddTextFile("teams_dir/deeper/Android.bp", teamsDirDeeper),
|
||||
FixtureAddTextFile("package_defaults/Android.bp", packageDefaultsBp),
|
||||
FixtureAddTextFile("package_defaults/pd2/Android.bp", packageDefaultspd2),
|
||||
FixtureAddTextFile("package_defaults/pd2/pd3/Android.bp", packageDefaultspd3),
|
||||
).RunTest(t)
|
||||
|
||||
var teams *team_proto.AllTeams
|
||||
teams = getTeamProtoOutput(t, ctx)
|
||||
|
||||
// map of module name -> trendy team name.
|
||||
actualTeams := make(map[string]*string)
|
||||
for _, teamProto := range teams.Teams {
|
||||
actualTeams[teamProto.GetTargetName()] = teamProto.TrendyTeamId
|
||||
}
|
||||
expectedTeams := map[string]*string{
|
||||
"module_with_team1": proto.String("111"),
|
||||
"module2_with_team1": proto.String("111"),
|
||||
"modulepd2": proto.String("trendy://team_top"),
|
||||
"modulepd3": proto.String("trendy://team_top"),
|
||||
"modulepd3b": proto.String("111"),
|
||||
"module_dir1": nil,
|
||||
"module_dir123": nil,
|
||||
}
|
||||
AssertDeepEquals(t, "compare maps", expectedTeams, actualTeams)
|
||||
}
|
|
@ -519,6 +519,9 @@ type commonProperties struct {
|
|||
// trace, but influence modules among products.
|
||||
SoongConfigTrace soongConfigTrace `blueprint:"mutated"`
|
||||
SoongConfigTraceHash string `blueprint:"mutated"`
|
||||
|
||||
// The team (defined by the owner/vendor) who owns the property.
|
||||
Team *string `android:"path"`
|
||||
}
|
||||
|
||||
type distProperties struct {
|
||||
|
@ -531,6 +534,12 @@ type distProperties struct {
|
|||
Dists []Dist `android:"arch_variant"`
|
||||
}
|
||||
|
||||
type TeamDepTagType struct {
|
||||
blueprint.BaseDependencyTag
|
||||
}
|
||||
|
||||
var teamDepTag = TeamDepTagType{}
|
||||
|
||||
// CommonTestOptions represents the common `test_options` properties in
|
||||
// Android.bp.
|
||||
type CommonTestOptions struct {
|
||||
|
@ -992,6 +1001,12 @@ func (m *ModuleBase) ComponentDepsMutator(BottomUpMutatorContext) {}
|
|||
|
||||
func (m *ModuleBase) DepsMutator(BottomUpMutatorContext) {}
|
||||
|
||||
func (m *ModuleBase) baseDepsMutator(ctx BottomUpMutatorContext) {
|
||||
if m.Team() != "" {
|
||||
ctx.AddDependency(ctx.Module(), teamDepTag, m.Team())
|
||||
}
|
||||
}
|
||||
|
||||
// AddProperties "registers" the provided props
|
||||
// each value in props MUST be a pointer to a struct
|
||||
func (m *ModuleBase) AddProperties(props ...interface{}) {
|
||||
|
@ -1437,6 +1452,10 @@ func (m *ModuleBase) Owner() string {
|
|||
return String(m.commonProperties.Owner)
|
||||
}
|
||||
|
||||
func (m *ModuleBase) Team() string {
|
||||
return String(m.commonProperties.Team)
|
||||
}
|
||||
|
||||
func (m *ModuleBase) setImageVariation(variant string) {
|
||||
m.commonProperties.ImageVariation = variant
|
||||
}
|
||||
|
|
|
@ -600,6 +600,7 @@ func componentDepsMutator(ctx BottomUpMutatorContext) {
|
|||
|
||||
func depsMutator(ctx BottomUpMutatorContext) {
|
||||
if m := ctx.Module(); m.Enabled() {
|
||||
m.base().baseDepsMutator(ctx)
|
||||
m.DepsMutator(ctx)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ type packageProperties struct {
|
|||
Default_visibility []string
|
||||
// Specifies the default license terms for all modules defined in this package.
|
||||
Default_applicable_licenses []string
|
||||
Default_team *string `android:"path"`
|
||||
}
|
||||
|
||||
type packageModule struct {
|
||||
|
@ -47,6 +48,13 @@ func (p *packageModule) GenerateAndroidBuildActions(ModuleContext) {
|
|||
// Nothing to do.
|
||||
}
|
||||
|
||||
func (p *packageModule) DepsMutator(ctx BottomUpMutatorContext) {
|
||||
// Add the dependency to do a validity check
|
||||
if p.properties.Default_team != nil {
|
||||
ctx.AddDependency(ctx.Module(), nil, *p.properties.Default_team)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *packageModule) GenerateBuildActions(ctx blueprint.ModuleContext) {
|
||||
// Nothing to do.
|
||||
}
|
||||
|
|
58
android/team.go
Normal file
58
android/team.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
// Copyright 2020 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package android
|
||||
|
||||
func init() {
|
||||
RegisterTeamBuildComponents(InitRegistrationContext)
|
||||
}
|
||||
|
||||
func RegisterTeamBuildComponents(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("team", TeamFactory)
|
||||
}
|
||||
|
||||
var PrepareForTestWithTeamBuildComponents = GroupFixturePreparers(
|
||||
FixtureRegisterWithContext(RegisterTeamBuildComponents),
|
||||
)
|
||||
|
||||
type teamProperties struct {
|
||||
Trendy_team_id *string `json:"trendy_team_id"`
|
||||
}
|
||||
|
||||
type teamModule struct {
|
||||
ModuleBase
|
||||
DefaultableModuleBase
|
||||
|
||||
properties teamProperties
|
||||
}
|
||||
|
||||
// Real work is done for the module that depends on us.
|
||||
// If needed, the team can serialize the config to json/proto file as well.
|
||||
func (t *teamModule) GenerateAndroidBuildActions(ctx ModuleContext) {}
|
||||
|
||||
func (t *teamModule) TrendyTeamId(ctx ModuleContext) string {
|
||||
return *t.properties.Trendy_team_id
|
||||
}
|
||||
|
||||
func TeamFactory() Module {
|
||||
module := &teamModule{}
|
||||
|
||||
base := module.base()
|
||||
module.AddProperties(&base.nameProperties, &module.properties)
|
||||
|
||||
InitAndroidModule(module)
|
||||
InitDefaultableModule(module)
|
||||
|
||||
return module
|
||||
}
|
29
android/team_proto/Android.bp
Normal file
29
android/team_proto/Android.bp
Normal file
|
@ -0,0 +1,29 @@
|
|||
// Copyright 2022 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package {
|
||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
||||
}
|
||||
|
||||
bootstrap_go_package {
|
||||
name: "soong-android_team_proto",
|
||||
pkgPath: "android/soong/android/team_proto",
|
||||
deps: [
|
||||
"golang-protobuf-reflect-protoreflect",
|
||||
"golang-protobuf-runtime-protoimpl",
|
||||
],
|
||||
srcs: [
|
||||
"team.pb.go",
|
||||
],
|
||||
}
|
5
android/team_proto/OWNERS
Normal file
5
android/team_proto/OWNERS
Normal file
|
@ -0,0 +1,5 @@
|
|||
dariofreni@google.com
|
||||
joeo@google.com
|
||||
ronish@google.com
|
||||
caditya@google.com
|
||||
rbraunstein@google.com
|
3
android/team_proto/regen.sh
Executable file
3
android/team_proto/regen.sh
Executable file
|
@ -0,0 +1,3 @@
|
|||
#!/bin/bash
|
||||
|
||||
aprotoc --go_out=paths=source_relative:. team.proto
|
253
android/team_proto/team.pb.go
Normal file
253
android/team_proto/team.pb.go
Normal file
|
@ -0,0 +1,253 @@
|
|||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.30.0
|
||||
// protoc v3.21.12
|
||||
// source: team.proto
|
||||
|
||||
package team_proto
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type Team struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
// REQUIRED: Name of the build target
|
||||
TargetName *string `protobuf:"bytes,1,opt,name=target_name,json=targetName" json:"target_name,omitempty"`
|
||||
// REQUIRED: Code location of the target.
|
||||
// To be used to support legacy/backup systems that use OWNERS file and is
|
||||
// also required for our dashboard to support per code location basis UI
|
||||
Path *string `protobuf:"bytes,2,opt,name=path" json:"path,omitempty"`
|
||||
// REQUIRED: Team ID of the team that owns this target.
|
||||
TrendyTeamId *string `protobuf:"bytes,3,opt,name=trendy_team_id,json=trendyTeamId" json:"trendy_team_id,omitempty"`
|
||||
// OPTIONAL: Files directly owned by this module.
|
||||
File []string `protobuf:"bytes,4,rep,name=file" json:"file,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Team) Reset() {
|
||||
*x = Team{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_team_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Team) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Team) ProtoMessage() {}
|
||||
|
||||
func (x *Team) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_team_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Team.ProtoReflect.Descriptor instead.
|
||||
func (*Team) Descriptor() ([]byte, []int) {
|
||||
return file_team_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *Team) GetTargetName() string {
|
||||
if x != nil && x.TargetName != nil {
|
||||
return *x.TargetName
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Team) GetPath() string {
|
||||
if x != nil && x.Path != nil {
|
||||
return *x.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Team) GetTrendyTeamId() string {
|
||||
if x != nil && x.TrendyTeamId != nil {
|
||||
return *x.TrendyTeamId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *Team) GetFile() []string {
|
||||
if x != nil {
|
||||
return x.File
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type AllTeams struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Teams []*Team `protobuf:"bytes,1,rep,name=teams" json:"teams,omitempty"`
|
||||
}
|
||||
|
||||
func (x *AllTeams) Reset() {
|
||||
*x = AllTeams{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_team_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *AllTeams) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*AllTeams) ProtoMessage() {}
|
||||
|
||||
func (x *AllTeams) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_team_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use AllTeams.ProtoReflect.Descriptor instead.
|
||||
func (*AllTeams) Descriptor() ([]byte, []int) {
|
||||
return file_team_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *AllTeams) GetTeams() []*Team {
|
||||
if x != nil {
|
||||
return x.Teams
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_team_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_team_proto_rawDesc = []byte{
|
||||
0x0a, 0x0a, 0x74, 0x65, 0x61, 0x6d, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0a, 0x74, 0x65,
|
||||
0x61, 0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x75, 0x0a, 0x04, 0x54, 0x65, 0x61, 0x6d,
|
||||
0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
|
||||
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4e, 0x61, 0x6d,
|
||||
0x65, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x04, 0x70, 0x61, 0x74, 0x68, 0x12, 0x24, 0x0a, 0x0e, 0x74, 0x72, 0x65, 0x6e, 0x64, 0x79, 0x5f,
|
||||
0x74, 0x65, 0x61, 0x6d, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74,
|
||||
0x72, 0x65, 0x6e, 0x64, 0x79, 0x54, 0x65, 0x61, 0x6d, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x66,
|
||||
0x69, 0x6c, 0x65, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x66, 0x69, 0x6c, 0x65, 0x22,
|
||||
0x32, 0x0a, 0x08, 0x41, 0x6c, 0x6c, 0x54, 0x65, 0x61, 0x6d, 0x73, 0x12, 0x26, 0x0a, 0x05, 0x74,
|
||||
0x65, 0x61, 0x6d, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x74, 0x65, 0x61,
|
||||
0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x54, 0x65, 0x61, 0x6d, 0x52, 0x05, 0x74, 0x65,
|
||||
0x61, 0x6d, 0x73, 0x42, 0x22, 0x5a, 0x20, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x73,
|
||||
0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f, 0x74, 0x65, 0x61,
|
||||
0x6d, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
}
|
||||
|
||||
var (
|
||||
file_team_proto_rawDescOnce sync.Once
|
||||
file_team_proto_rawDescData = file_team_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_team_proto_rawDescGZIP() []byte {
|
||||
file_team_proto_rawDescOnce.Do(func() {
|
||||
file_team_proto_rawDescData = protoimpl.X.CompressGZIP(file_team_proto_rawDescData)
|
||||
})
|
||||
return file_team_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_team_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_team_proto_goTypes = []interface{}{
|
||||
(*Team)(nil), // 0: team_proto.Team
|
||||
(*AllTeams)(nil), // 1: team_proto.AllTeams
|
||||
}
|
||||
var file_team_proto_depIdxs = []int32{
|
||||
0, // 0: team_proto.AllTeams.teams:type_name -> team_proto.Team
|
||||
1, // [1:1] is the sub-list for method output_type
|
||||
1, // [1:1] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_team_proto_init() }
|
||||
func file_team_proto_init() {
|
||||
if File_team_proto != nil {
|
||||
return
|
||||
}
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_team_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Team); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_team_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*AllTeams); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_team_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 0,
|
||||
},
|
||||
GoTypes: file_team_proto_goTypes,
|
||||
DependencyIndexes: file_team_proto_depIdxs,
|
||||
MessageInfos: file_team_proto_msgTypes,
|
||||
}.Build()
|
||||
File_team_proto = out.File
|
||||
file_team_proto_rawDesc = nil
|
||||
file_team_proto_goTypes = nil
|
||||
file_team_proto_depIdxs = nil
|
||||
}
|
34
android/team_proto/team.proto
Normal file
34
android/team_proto/team.proto
Normal file
|
@ -0,0 +1,34 @@
|
|||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
syntax = "proto2";
|
||||
package team_proto;
|
||||
option go_package = "android/soong/android/team_proto";
|
||||
|
||||
message Team {
|
||||
// REQUIRED: Name of the build target
|
||||
optional string target_name = 1;
|
||||
|
||||
// REQUIRED: Code location of the target.
|
||||
// To be used to support legacy/backup systems that use OWNERS file and is
|
||||
// also required for our dashboard to support per code location basis UI
|
||||
optional string path = 2;
|
||||
|
||||
// REQUIRED: Team ID of the team that owns this target.
|
||||
optional string trendy_team_id = 3;
|
||||
|
||||
// OPTIONAL: Files directly owned by this module.
|
||||
repeated string file = 4;
|
||||
}
|
||||
|
||||
message AllTeams {
|
||||
repeated Team teams = 1;
|
||||
}
|
99
android/team_test.go
Normal file
99
android/team_test.go
Normal file
|
@ -0,0 +1,99 @@
|
|||
// Copyright 2024 Google Inc. All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
package android
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
type fakeModuleForTests struct {
|
||||
ModuleBase
|
||||
}
|
||||
|
||||
func fakeModuleFactory() Module {
|
||||
module := &fakeModuleForTests{}
|
||||
InitAndroidModule(module)
|
||||
return module
|
||||
}
|
||||
|
||||
func (*fakeModuleForTests) GenerateAndroidBuildActions(ModuleContext) {}
|
||||
|
||||
func TestTeam(t *testing.T) {
|
||||
t.Parallel()
|
||||
ctx := GroupFixturePreparers(
|
||||
PrepareForTestWithTeamBuildComponents,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("fake", fakeModuleFactory)
|
||||
}),
|
||||
).RunTestWithBp(t, `
|
||||
fake {
|
||||
name: "main_test",
|
||||
team: "someteam",
|
||||
}
|
||||
team {
|
||||
name: "someteam",
|
||||
trendy_team_id: "cool_team",
|
||||
}
|
||||
|
||||
team {
|
||||
name: "team2",
|
||||
trendy_team_id: "22222",
|
||||
}
|
||||
|
||||
fake {
|
||||
name: "tool",
|
||||
team: "team2",
|
||||
}
|
||||
`)
|
||||
|
||||
// Assert the rule from GenerateAndroidBuildActions exists.
|
||||
m := ctx.ModuleForTests("main_test", "")
|
||||
AssertStringEquals(t, "msg", m.Module().base().Team(), "someteam")
|
||||
m = ctx.ModuleForTests("tool", "")
|
||||
AssertStringEquals(t, "msg", m.Module().base().Team(), "team2")
|
||||
}
|
||||
|
||||
func TestMissingTeamFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
GroupFixturePreparers(
|
||||
PrepareForTestWithTeamBuildComponents,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("fake", fakeModuleFactory)
|
||||
}),
|
||||
).
|
||||
ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern("depends on undefined module \"ring-bearer")).
|
||||
RunTestWithBp(t, `
|
||||
fake {
|
||||
name: "you_cannot_pass",
|
||||
team: "ring-bearer",
|
||||
}
|
||||
`)
|
||||
}
|
||||
|
||||
func TestPackageBadTeamNameFails(t *testing.T) {
|
||||
t.Parallel()
|
||||
GroupFixturePreparers(
|
||||
PrepareForTestWithTeamBuildComponents,
|
||||
PrepareForTestWithPackageModule,
|
||||
FixtureRegisterWithContext(func(ctx RegistrationContext) {
|
||||
ctx.RegisterModuleType("fake", fakeModuleFactory)
|
||||
}),
|
||||
).
|
||||
ExtendWithErrorHandler(FixtureExpectsAtLeastOneErrorMatchingPattern("depends on undefined module \"ring-bearer")).
|
||||
RunTestWithBp(t, `
|
||||
package {
|
||||
default_team: "ring-bearer",
|
||||
}
|
||||
`)
|
||||
}
|
Loading…
Reference in a new issue