Add Code Metadata rule to soong/testing.

This Cl adds a new rule to Soong to generate code ownership metadata. Also, this CL adds a provider in the Java SDK library to provide generated source files to the Code_metadata rule. Will add providers to other libraries in the future changes.

Bug: 296873595
Change-Id: Ic2e43aa9b161231fea4416d1f0d36b778361d7c5
This commit is contained in:
Aditya Choudhary 2023-10-12 19:40:17 +00:00
parent 14e1149195
commit 8094b6bf9d
25 changed files with 1042 additions and 6 deletions

View file

@ -93,6 +93,7 @@ bootstrap_go_package {
"singleton.go",
"singleton_module.go",
"soong_config_modules.go",
"source_file_provider.go",
"test_asserts.go",
"test_suites.go",
"testing.go",

View file

@ -0,0 +1,11 @@
package android
import (
"github.com/google/blueprint"
)
type SrcsFileProviderData struct {
SrcPaths Paths
}
var SrcsFileProviderKey = blueprint.NewProvider(SrcsFileProviderData{})

View file

@ -86,6 +86,7 @@ bootstrap_go_package {
"app_import_test.go",
"app_set_test.go",
"app_test.go",
"code_metadata_test.go",
"bootclasspath_fragment_test.go",
"device_host_converter_test.go",
"dex_test.go",

125
java/code_metadata_test.go Normal file
View file

@ -0,0 +1,125 @@
package java
import (
"strings"
"testing"
"android/soong/android"
soongTesting "android/soong/testing"
"android/soong/testing/code_metadata_internal_proto"
"google.golang.org/protobuf/proto"
)
func TestCodeMetadata(t *testing.T) {
bp := `code_metadata {
name: "module-name",
teamId: "12345",
code: [
"foo",
]
}
java_sdk_library {
name: "foo",
srcs: ["a.java"],
}`
result := runCodeMetadataTest(t, android.FixtureExpectsNoErrors, bp)
module := result.ModuleForTests(
"module-name", "",
).Module().(*soongTesting.CodeMetadataModule)
// Check that the provider has the right contents
data := result.ModuleProvider(
module, soongTesting.CodeMetadataProviderKey,
).(soongTesting.CodeMetadataProviderData)
if !strings.HasSuffix(
data.IntermediatePath.String(), "/intermediateCodeMetadata.pb",
) {
t.Errorf(
"Missing intermediates path in provider: %s",
data.IntermediatePath.String(),
)
}
buildParamsSlice := module.BuildParamsForTests()
var metadata = ""
for _, params := range buildParamsSlice {
if params.Rule.String() == "android/soong/android.writeFile" {
metadata = params.Args["content"]
}
}
metadataList := make([]*code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership, 0, 2)
teamId := "12345"
bpFilePath := "Android.bp"
targetName := "foo"
srcFile := []string{"a.java"}
expectedMetadataProto := code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
TrendyTeamId: &teamId,
TargetName: &targetName,
Path: &bpFilePath,
SourceFiles: srcFile,
}
metadataList = append(metadataList, &expectedMetadataProto)
CodeMetadataMetadata := code_metadata_internal_proto.CodeMetadataInternal{TargetOwnershipList: metadataList}
protoData, _ := proto.Marshal(&CodeMetadataMetadata)
rawData := string(protoData)
formattedData := strings.ReplaceAll(rawData, "\n", "\\n")
expectedMetadata := "'" + formattedData + "\\n'"
if metadata != expectedMetadata {
t.Errorf(
"Retrieved metadata: %s is not equal to expectedMetadata: %s", metadata,
expectedMetadata,
)
}
// Tests for all_test_spec singleton.
singleton := result.SingletonForTests("all_code_metadata")
rule := singleton.Rule("all_code_metadata_rule")
prebuiltOs := result.Config.PrebuiltOS()
expectedCmd := "out/soong/host/" + prebuiltOs + "/bin/metadata -rule code_metadata -inputFile out/soong/all_code_metadata_paths.rsp -outputFile out/soong/ownership/all_code_metadata.pb"
expectedOutputFile := "out/soong/ownership/all_code_metadata.pb"
expectedInputFile := "out/soong/.intermediates/module-name/intermediateCodeMetadata.pb"
if !strings.Contains(
strings.TrimSpace(rule.Output.String()),
expectedOutputFile,
) {
t.Errorf(
"Retrieved singletonOutputFile: %s is not equal to expectedSingletonOutputFile: %s",
rule.Output.String(), expectedOutputFile,
)
}
if !strings.Contains(
strings.TrimSpace(rule.Inputs[0].String()),
expectedInputFile,
) {
t.Errorf(
"Retrieved singletonInputFile: %s is not equal to expectedSingletonInputFile: %s",
rule.Inputs[0].String(), expectedInputFile,
)
}
if !strings.Contains(
strings.TrimSpace(rule.RuleParams.Command),
expectedCmd,
) {
t.Errorf(
"Retrieved cmd: %s doesn't contain expectedCmd: %s",
rule.RuleParams.Command, expectedCmd,
)
}
}
func runCodeMetadataTest(
t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
) *android.TestResult {
return android.GroupFixturePreparers(
soongTesting.PrepareForTestWithTestingBuildComponents, prepareForJavaTest,
PrepareForTestWithJavaSdkLibraryFiles, FixtureWithLastReleaseApis("foo"),
).
ExtendWithErrorHandler(errorHandler).
RunTestWithBp(t, bp)
}

View file

@ -1477,6 +1477,7 @@ func (module *SdkLibrary) GenerateAndroidBuildActions(ctx android.ModuleContext)
}
}
ctx.SetProvider(android.AdditionalSdkInfoProvider, android.AdditionalSdkInfo{additionalSdkInfo})
ctx.SetProvider(android.SrcsFileProviderKey, android.SrcsFileProviderData{SrcPaths: module.uniqueSrcFiles})
}
func (module *SdkLibrary) AndroidMkEntries() []android.AndroidMkEntries {

View file

@ -27,7 +27,7 @@ func TestTestSpec(t *testing.T) {
java_test {
name: "java-test-module-name-two",
}`
result := runTest(t, android.FixtureExpectsNoErrors, bp)
result := runTestSpecTest(t, android.FixtureExpectsNoErrors, bp)
module := result.ModuleForTests(
"module-name", "",
@ -78,7 +78,7 @@ func TestTestSpec(t *testing.T) {
if metadata != expectedMetadata {
t.Errorf(
"Retrieved metadata: %s is not equal to expectedMetadata: %s", metadata,
"Retrieved metadata: %s doesn't contain expectedMetadata: %s", metadata,
expectedMetadata,
)
}
@ -121,11 +121,11 @@ func TestTestSpec(t *testing.T) {
}
}
func runTest(
t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
func runTestSpecTest(
t *testing.T, errorHandler android.FixtureErrorHandler, bp string,
) *android.TestResult {
return android.GroupFixturePreparers(
soongTesting.PrepareForTestWithTestSpecBuildComponents,
soongTesting.PrepareForTestWithTestingBuildComponents,
PrepareForIntegrationTestWithJava,
).
ExtendWithErrorHandler(errorHandler).

View file

@ -8,11 +8,14 @@ bootstrap_go_package {
deps: [
"blueprint",
"soong-android",
"soong-testing-code_metadata_internal_proto",
"soong-testing-test_spec_proto",
],
srcs: [
"all_code_metadata.go",
"all_test_specs.go",
"code_metadata.go",
"test_spec.go",
"init.go",
"test.go",

4
testing/OWNERS Normal file
View file

@ -0,0 +1,4 @@
dariofreni@google.com
joeo@google.com
ronish@google.com
caditya@google.com

View file

@ -0,0 +1,51 @@
package testing
import (
"android/soong/android"
)
const fileContainingCodeMetadataFilePaths = "all_code_metadata_paths.rsp"
const allCodeMetadataFile = "all_code_metadata.pb"
func AllCodeMetadataFactory() android.Singleton {
return &allCodeMetadataSingleton{}
}
type allCodeMetadataSingleton struct {
// Path where the collected metadata is stored after successful validation.
outputPath android.OutputPath
}
func (this *allCodeMetadataSingleton) GenerateBuildActions(ctx android.SingletonContext) {
var intermediateMetadataPaths android.Paths
ctx.VisitAllModules(
func(module android.Module) {
if !ctx.ModuleHasProvider(module, CodeMetadataProviderKey) {
return
}
intermediateMetadataPaths = append(
intermediateMetadataPaths, ctx.ModuleProvider(
module, CodeMetadataProviderKey,
).(CodeMetadataProviderData).IntermediatePath,
)
},
)
rspFile := android.PathForOutput(ctx, fileContainingCodeMetadataFilePaths)
this.outputPath = android.PathForOutput(ctx, ownershipDirectory, allCodeMetadataFile)
rule := android.NewRuleBuilder(pctx, ctx)
cmd := rule.Command().
BuiltTool("metadata").
FlagWithArg("-rule ", "code_metadata").
FlagWithRspFileInputList("-inputFile ", rspFile, intermediateMetadataPaths)
cmd.FlagWithOutput("-outputFile ", this.outputPath)
rule.Build("all_code_metadata_rule", "Generate all code metadata")
ctx.Phony("all_code_metadata", this.outputPath)
}
func (this *allCodeMetadataSingleton) MakeVars(ctx android.MakeVarsContext) {
ctx.DistForGoal("code_metadata", this.outputPath)
}

139
testing/code_metadata.go Normal file
View file

@ -0,0 +1,139 @@
// 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 testing
import (
"path/filepath"
"android/soong/android"
"android/soong/testing/code_metadata_internal_proto"
"github.com/google/blueprint"
"google.golang.org/protobuf/proto"
)
func CodeMetadataFactory() android.Module {
module := &CodeMetadataModule{}
android.InitAndroidModule(module)
android.InitDefaultableModule(module)
module.AddProperties(&module.properties)
return module
}
type CodeMetadataModule struct {
android.ModuleBase
android.DefaultableModuleBase
android.BazelModuleBase
// Properties for "code_metadata"
properties struct {
// Specifies the name of the code_config.
Name string
// Specifies the team ID.
TeamId string
// Specifies the list of modules that this code_metadata covers.
Code []string
// An optional field to specify if multiple ownerships for source files is allowed.
MultiOwnership bool
}
}
type codeDepTagType struct {
blueprint.BaseDependencyTag
}
var codeDepTag = codeDepTagType{}
func (module *CodeMetadataModule) DepsMutator(ctx android.BottomUpMutatorContext) {
// Validate Properties
if len(module.properties.TeamId) == 0 {
ctx.PropertyErrorf(
"TeamId",
"Team Id not found in the code_metadata module. Hint: Maybe the teamId property hasn't been properly specified.",
)
}
if !isInt(module.properties.TeamId) {
ctx.PropertyErrorf(
"TeamId", "Invalid value for Team ID. The Team ID must be an integer.",
)
}
if len(module.properties.Code) == 0 {
ctx.PropertyErrorf(
"Code",
"Targets to be attributed cannot be empty. Hint: Maybe the code property hasn't been properly specified.",
)
}
ctx.AddDependency(ctx.Module(), codeDepTag, module.properties.Code...)
}
// Provider published by CodeMetadata
type CodeMetadataProviderData struct {
IntermediatePath android.WritablePath
}
var CodeMetadataProviderKey = blueprint.NewProvider(CodeMetadataProviderData{})
func (module *CodeMetadataModule) GenerateAndroidBuildActions(ctx android.ModuleContext) {
metadataList := make(
[]*code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership, 0,
len(module.properties.Code),
)
bpFilePath := filepath.Join(ctx.ModuleDir(), ctx.BlueprintsFile())
for _, m := range ctx.GetDirectDepsWithTag(codeDepTag) {
targetName := m.Name()
var moduleSrcs android.Paths
if ctx.OtherModuleHasProvider(m, android.SrcsFileProviderKey) {
moduleSrcs = ctx.OtherModuleProvider(
m, android.SrcsFileProviderKey,
).(android.SrcsFileProviderData).SrcPaths
}
if module.properties.MultiOwnership {
metadata := &code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
TargetName: &targetName,
TrendyTeamId: &module.properties.TeamId,
Path: &bpFilePath,
MultiOwnership: &module.properties.MultiOwnership,
SourceFiles: moduleSrcs.Strings(),
}
metadataList = append(metadataList, metadata)
} else {
metadata := &code_metadata_internal_proto.CodeMetadataInternal_TargetOwnership{
TargetName: &targetName,
TrendyTeamId: &module.properties.TeamId,
Path: &bpFilePath,
SourceFiles: moduleSrcs.Strings(),
}
metadataList = append(metadataList, metadata)
}
}
codeMetadata := &code_metadata_internal_proto.CodeMetadataInternal{TargetOwnershipList: metadataList}
protoData, err := proto.Marshal(codeMetadata)
if err != nil {
ctx.ModuleErrorf("Error marshaling code metadata: %s", err.Error())
return
}
intermediatePath := android.PathForModuleOut(
ctx, "intermediateCodeMetadata.pb",
)
android.WriteFileRule(ctx, intermediatePath, string(protoData))
ctx.SetProvider(
CodeMetadataProviderKey,
CodeMetadataProviderData{IntermediatePath: intermediatePath},
)
}

View 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-testing-code_metadata_internal_proto",
pkgPath: "android/soong/testing/code_metadata_internal_proto",
deps: [
"golang-protobuf-reflect-protoreflect",
"golang-protobuf-runtime-protoimpl",
],
srcs: [
"code_metadata_internal.pb.go",
],
}

View file

@ -0,0 +1,4 @@
dariofreni@google.com
joeo@google.com
ronish@google.com
caditya@google.com

View file

@ -0,0 +1,277 @@
// 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: code_metadata_internal.proto
package code_metadata_internal_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 CodeMetadataInternal struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// List of all code targets and their metadata.
TargetOwnershipList []*CodeMetadataInternal_TargetOwnership `protobuf:"bytes,1,rep,name=target_ownership_list,json=targetOwnershipList" json:"target_ownership_list,omitempty"`
}
func (x *CodeMetadataInternal) Reset() {
*x = CodeMetadataInternal{}
if protoimpl.UnsafeEnabled {
mi := &file_code_metadata_internal_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CodeMetadataInternal) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CodeMetadataInternal) ProtoMessage() {}
func (x *CodeMetadataInternal) ProtoReflect() protoreflect.Message {
mi := &file_code_metadata_internal_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 CodeMetadataInternal.ProtoReflect.Descriptor instead.
func (*CodeMetadataInternal) Descriptor() ([]byte, []int) {
return file_code_metadata_internal_proto_rawDescGZIP(), []int{0}
}
func (x *CodeMetadataInternal) GetTargetOwnershipList() []*CodeMetadataInternal_TargetOwnership {
if x != nil {
return x.TargetOwnershipList
}
return nil
}
type CodeMetadataInternal_TargetOwnership 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: The src files of the target.
// To be used to determine ownership of a file for ownership
SourceFiles []string `protobuf:"bytes,4,rep,name=source_files,json=sourceFiles" json:"source_files,omitempty"`
// OPTIONAL: Specify if multiple ownerships of the source files are allowed.
MultiOwnership *bool `protobuf:"varint,5,opt,name=multi_ownership,json=multiOwnership" json:"multi_ownership,omitempty"`
}
func (x *CodeMetadataInternal_TargetOwnership) Reset() {
*x = CodeMetadataInternal_TargetOwnership{}
if protoimpl.UnsafeEnabled {
mi := &file_code_metadata_internal_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CodeMetadataInternal_TargetOwnership) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CodeMetadataInternal_TargetOwnership) ProtoMessage() {}
func (x *CodeMetadataInternal_TargetOwnership) ProtoReflect() protoreflect.Message {
mi := &file_code_metadata_internal_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 CodeMetadataInternal_TargetOwnership.ProtoReflect.Descriptor instead.
func (*CodeMetadataInternal_TargetOwnership) Descriptor() ([]byte, []int) {
return file_code_metadata_internal_proto_rawDescGZIP(), []int{0, 0}
}
func (x *CodeMetadataInternal_TargetOwnership) GetTargetName() string {
if x != nil && x.TargetName != nil {
return *x.TargetName
}
return ""
}
func (x *CodeMetadataInternal_TargetOwnership) GetPath() string {
if x != nil && x.Path != nil {
return *x.Path
}
return ""
}
func (x *CodeMetadataInternal_TargetOwnership) GetTrendyTeamId() string {
if x != nil && x.TrendyTeamId != nil {
return *x.TrendyTeamId
}
return ""
}
func (x *CodeMetadataInternal_TargetOwnership) GetSourceFiles() []string {
if x != nil {
return x.SourceFiles
}
return nil
}
func (x *CodeMetadataInternal_TargetOwnership) GetMultiOwnership() bool {
if x != nil && x.MultiOwnership != nil {
return *x.MultiOwnership
}
return false
}
var File_code_metadata_internal_proto protoreflect.FileDescriptor
var file_code_metadata_internal_proto_rawDesc = []byte{
0x0a, 0x1c, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x1c,
0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc9, 0x02, 0x0a,
0x14, 0x43, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x49, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x12, 0x76, 0x0a, 0x15, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x5f,
0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x01,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x42, 0x2e, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 0x5f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f,
0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x13, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74,
0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4c, 0x69, 0x73, 0x74, 0x1a, 0xb8, 0x01,
0x0a, 0x0f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69,
0x70, 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, 0x21, 0x0a, 0x0c,
0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03,
0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12,
0x27, 0x0a, 0x0f, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68,
0x69, 0x70, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x6d, 0x75, 0x6c, 0x74, 0x69, 0x4f,
0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x42, 0x34, 0x5a, 0x32, 0x61, 0x6e, 0x64, 0x72,
0x6f, 0x69, 0x64, 0x2f, 0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e,
0x67, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
}
var (
file_code_metadata_internal_proto_rawDescOnce sync.Once
file_code_metadata_internal_proto_rawDescData = file_code_metadata_internal_proto_rawDesc
)
func file_code_metadata_internal_proto_rawDescGZIP() []byte {
file_code_metadata_internal_proto_rawDescOnce.Do(func() {
file_code_metadata_internal_proto_rawDescData = protoimpl.X.CompressGZIP(file_code_metadata_internal_proto_rawDescData)
})
return file_code_metadata_internal_proto_rawDescData
}
var file_code_metadata_internal_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_code_metadata_internal_proto_goTypes = []interface{}{
(*CodeMetadataInternal)(nil), // 0: code_metadata_internal_proto.CodeMetadataInternal
(*CodeMetadataInternal_TargetOwnership)(nil), // 1: code_metadata_internal_proto.CodeMetadataInternal.TargetOwnership
}
var file_code_metadata_internal_proto_depIdxs = []int32{
1, // 0: code_metadata_internal_proto.CodeMetadataInternal.target_ownership_list:type_name -> code_metadata_internal_proto.CodeMetadataInternal.TargetOwnership
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_code_metadata_internal_proto_init() }
func file_code_metadata_internal_proto_init() {
if File_code_metadata_internal_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_code_metadata_internal_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CodeMetadataInternal); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_code_metadata_internal_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CodeMetadataInternal_TargetOwnership); 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_code_metadata_internal_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_code_metadata_internal_proto_goTypes,
DependencyIndexes: file_code_metadata_internal_proto_depIdxs,
MessageInfos: file_code_metadata_internal_proto_msgTypes,
}.Build()
File_code_metadata_internal_proto = out.File
file_code_metadata_internal_proto_rawDesc = nil
file_code_metadata_internal_proto_goTypes = nil
file_code_metadata_internal_proto_depIdxs = nil
}

View file

@ -0,0 +1,40 @@
// 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 code_metadata_internal_proto;
option go_package = "android/soong/testing/code_metadata_internal_proto";
message CodeMetadataInternal {
message TargetOwnership {
// 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: The src files of the target.
// To be used to determine ownership of a file for ownership
repeated string source_files = 4;
// OPTIONAL: Specify if multiple ownerships of the source files are allowed.
optional bool multi_ownership = 5;
}
// List of all code targets and their metadata.
repeated TargetOwnership target_ownership_list = 1;
}

View file

@ -0,0 +1,3 @@
module android/soong/testing/code_metadata_internal_proto
go 1.18

View file

@ -0,0 +1,3 @@
#!/bin/bash
aprotoc --go_out=paths=source_relative:. code_metadata_internal.proto

View 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-testing-code_metadata_proto",
pkgPath: "android/soong/testing/code_metadata_proto",
deps: [
"golang-protobuf-reflect-protoreflect",
"golang-protobuf-runtime-protoimpl",
],
srcs: [
"code_metadata.pb.go",
],
}

View file

@ -0,0 +1,4 @@
dariofreni@google.com
joeo@google.com
ronish@google.com
caditya@google.com

View file

@ -0,0 +1,263 @@
// 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: code_metadata.proto
package code_metadata_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 CodeMetadata struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// List of all code targets and their metadata.
TargetOwnershipList []*CodeMetadata_TargetOwnership `protobuf:"bytes,1,rep,name=target_ownership_list,json=targetOwnershipList" json:"target_ownership_list,omitempty"`
}
func (x *CodeMetadata) Reset() {
*x = CodeMetadata{}
if protoimpl.UnsafeEnabled {
mi := &file_code_metadata_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CodeMetadata) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CodeMetadata) ProtoMessage() {}
func (x *CodeMetadata) ProtoReflect() protoreflect.Message {
mi := &file_code_metadata_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 CodeMetadata.ProtoReflect.Descriptor instead.
func (*CodeMetadata) Descriptor() ([]byte, []int) {
return file_code_metadata_proto_rawDescGZIP(), []int{0}
}
func (x *CodeMetadata) GetTargetOwnershipList() []*CodeMetadata_TargetOwnership {
if x != nil {
return x.TargetOwnershipList
}
return nil
}
type CodeMetadata_TargetOwnership 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: The src files of the target.
// To be used to determine ownership of a file for ownership
SourceFiles []string `protobuf:"bytes,4,rep,name=source_files,json=sourceFiles" json:"source_files,omitempty"`
}
func (x *CodeMetadata_TargetOwnership) Reset() {
*x = CodeMetadata_TargetOwnership{}
if protoimpl.UnsafeEnabled {
mi := &file_code_metadata_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *CodeMetadata_TargetOwnership) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*CodeMetadata_TargetOwnership) ProtoMessage() {}
func (x *CodeMetadata_TargetOwnership) ProtoReflect() protoreflect.Message {
mi := &file_code_metadata_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 CodeMetadata_TargetOwnership.ProtoReflect.Descriptor instead.
func (*CodeMetadata_TargetOwnership) Descriptor() ([]byte, []int) {
return file_code_metadata_proto_rawDescGZIP(), []int{0, 0}
}
func (x *CodeMetadata_TargetOwnership) GetTargetName() string {
if x != nil && x.TargetName != nil {
return *x.TargetName
}
return ""
}
func (x *CodeMetadata_TargetOwnership) GetPath() string {
if x != nil && x.Path != nil {
return *x.Path
}
return ""
}
func (x *CodeMetadata_TargetOwnership) GetTrendyTeamId() string {
if x != nil && x.TrendyTeamId != nil {
return *x.TrendyTeamId
}
return ""
}
func (x *CodeMetadata_TargetOwnership) GetSourceFiles() []string {
if x != nil {
return x.SourceFiles
}
return nil
}
var File_code_metadata_proto protoreflect.FileDescriptor
var file_code_metadata_proto_rawDesc = []byte{
0x0a, 0x13, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x13, 0x63, 0x6f, 0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61,
0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x87, 0x02, 0x0a, 0x0c, 0x43,
0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x65, 0x0a, 0x15, 0x74,
0x61, 0x72, 0x67, 0x65, 0x74, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x5f,
0x6c, 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x63, 0x6f, 0x64,
0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2e, 0x43, 0x6f, 0x64, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x2e, 0x54, 0x61,
0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x52, 0x13, 0x74,
0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 0x4c, 0x69,
0x73, 0x74, 0x1a, 0x8f, 0x01, 0x0a, 0x0f, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x4f, 0x77, 0x6e,
0x65, 0x72, 0x73, 0x68, 0x69, 0x70, 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, 0x21, 0x0a, 0x0c, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46,
0x69, 0x6c, 0x65, 0x73, 0x42, 0x2b, 0x5a, 0x29, 0x61, 0x6e, 0x64, 0x72, 0x6f, 0x69, 0x64, 0x2f,
0x73, 0x6f, 0x6f, 0x6e, 0x67, 0x2f, 0x74, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x67, 0x2f, 0x63, 0x6f,
0x64, 0x65, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x70, 0x72, 0x6f, 0x74,
0x6f,
}
var (
file_code_metadata_proto_rawDescOnce sync.Once
file_code_metadata_proto_rawDescData = file_code_metadata_proto_rawDesc
)
func file_code_metadata_proto_rawDescGZIP() []byte {
file_code_metadata_proto_rawDescOnce.Do(func() {
file_code_metadata_proto_rawDescData = protoimpl.X.CompressGZIP(file_code_metadata_proto_rawDescData)
})
return file_code_metadata_proto_rawDescData
}
var file_code_metadata_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
var file_code_metadata_proto_goTypes = []interface{}{
(*CodeMetadata)(nil), // 0: code_metadata_proto.CodeMetadata
(*CodeMetadata_TargetOwnership)(nil), // 1: code_metadata_proto.CodeMetadata.TargetOwnership
}
var file_code_metadata_proto_depIdxs = []int32{
1, // 0: code_metadata_proto.CodeMetadata.target_ownership_list:type_name -> code_metadata_proto.CodeMetadata.TargetOwnership
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_code_metadata_proto_init() }
func file_code_metadata_proto_init() {
if File_code_metadata_proto != nil {
return
}
if !protoimpl.UnsafeEnabled {
file_code_metadata_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CodeMetadata); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_code_metadata_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*CodeMetadata_TargetOwnership); 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_code_metadata_proto_rawDesc,
NumEnums: 0,
NumMessages: 2,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_code_metadata_proto_goTypes,
DependencyIndexes: file_code_metadata_proto_depIdxs,
MessageInfos: file_code_metadata_proto_msgTypes,
}.Build()
File_code_metadata_proto = out.File
file_code_metadata_proto_rawDesc = nil
file_code_metadata_proto_goTypes = nil
file_code_metadata_proto_depIdxs = nil
}

View file

@ -0,0 +1,37 @@
// 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 code_metadata_proto;
option go_package = "android/soong/testing/code_metadata_proto";
message CodeMetadata {
message TargetOwnership {
// 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: The src files of the target.
// To be used to determine ownership of a file for ownership
repeated string source_files = 4;
}
// List of all code targets and their metadata.
repeated TargetOwnership target_ownership_list = 1;
}

View file

@ -0,0 +1,3 @@
module android/soong/testing/code_metadata_proto
go 1.18

View file

@ -0,0 +1,3 @@
#!/bin/bash
aprotoc --go_out=paths=source_relative:. code_metadata.proto

View file

@ -28,6 +28,8 @@ func init() {
}
func RegisterBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("code_metadata", CodeMetadataFactory)
ctx.RegisterModuleType("test_spec", TestSpecFactory)
ctx.RegisterParallelSingletonType("all_code_metadata", AllCodeMetadataFactory)
ctx.RegisterParallelSingletonType("all_test_specs", AllTestSpecsFactory)
}

View file

@ -18,4 +18,4 @@ import (
"android/soong/android"
)
var PrepareForTestWithTestSpecBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents)
var PrepareForTestWithTestingBuildComponents = android.FixtureRegisterWithContext(RegisterBuildComponents)

View file

@ -0,0 +1,3 @@
module android/soong/testing/test_spec_proto
go 1.18