go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/internal/bugs/bugid.go (about) 1 // Copyright 2022 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package bugs 16 17 import ( 18 "errors" 19 "fmt" 20 "regexp" 21 ) 22 23 // MonorailSystem is the name of the monorail bug tracker system. 24 const MonorailSystem = "monorail" 25 26 // BuganizerSystem is the name of the buganizer bug tracker system. 27 const BuganizerSystem = "buganizer" 28 29 // MonorailBugIDRe matches identifiers of monorail bugs, like 30 // "{monorail_project}/{numeric_id}". 31 var MonorailBugIDRe = regexp.MustCompile(`^([a-z0-9\-_]+)/([1-9][0-9]*)$`) 32 33 // BuganizerBugIDRe matches identifiers of buganizer bugs (excluding 34 // the b/), like 1234567890. 35 var BuganizerBugIDRe = regexp.MustCompile(`^([1-9][0-9]*)$`) 36 37 // BugID represents the identity of a bug managed by LUCI Analysis. 38 type BugID struct { 39 // System is the bug tracking system of the bug. This is either 40 // "monorail" or "buganizer". 41 System string `json:"system"` 42 // ID is the bug tracking system-specific identity of the bug. 43 // For monorail, the scheme is {project}/{numeric_id}, for 44 // buganizer the scheme is {numeric_id}. 45 ID string `json:"id"` 46 } 47 48 // Validate checks if BugID is a valid bug reference. If not, it 49 // returns an error. 50 func (b *BugID) Validate() error { 51 switch b.System { 52 case MonorailSystem: 53 if !MonorailBugIDRe.MatchString(b.ID) { 54 return fmt.Errorf("invalid monorail bug ID %q", b.ID) 55 } 56 case BuganizerSystem: 57 if !BuganizerBugIDRe.MatchString(b.ID) { 58 return fmt.Errorf("invalid buganizer bug ID %q", b.ID) 59 } 60 default: 61 return fmt.Errorf("invalid bug tracking system %q", b.System) 62 } 63 return nil 64 } 65 66 // MonorailID returns the monorail project and ID of the given bug. 67 // If the bug is not a monorail bug or is invalid, an error is returned. 68 func (b *BugID) MonorailProjectAndID() (project, id string, err error) { 69 if b.System != MonorailSystem { 70 return "", "", errors.New("not a monorail bug") 71 } 72 m := MonorailBugIDRe.FindStringSubmatch(b.ID) 73 if m == nil { 74 return "", "", errors.New("not a valid monorail bug ID") 75 } 76 return m[1], m[2], nil 77 } 78 79 func (b BugID) String() string { 80 return fmt.Sprintf("%s:%s", b.System, b.ID) 81 }