Documentation
Overview ¶
Package changelist implements operations on a single CL.
It is agnostic about the kind of a CL even though currently all CLs represent Gerrit changes.
Index ¶
- Variables
- func Delete(ctx context.Context, id common.CLID) error
- func LoadMulti(ctx context.Context, cls []*CL) (err error)
- func Lookup(ctx context.Context, eids []ExternalID) ([]common.CLID, error)
- func RemoveUnusedGerritInfo(ci *gerritpb.ChangeInfo)
- func Sort(cls []*CL)
- func Update(ctx context.Context, eid ExternalID, knownCLID common.CLID, ...) error
- type ApplicableConfig
- func (*ApplicableConfig) Descriptor() ([]byte, []int)
- func (x *ApplicableConfig) GetProjects() []*ApplicableConfig_Project
- func (a *ApplicableConfig) HasOnlyProject(luciProject string) bool
- func (a *ApplicableConfig) HasProject(luciProject string) bool
- func (*ApplicableConfig) ProtoMessage()
- func (x *ApplicableConfig) ProtoReflect() protoreflect.Message
- func (x *ApplicableConfig) Reset()
- func (a *ApplicableConfig) SemanticallyEqual(b *ApplicableConfig) bool
- func (x *ApplicableConfig) String() string
- type ApplicableConfig_Project
- func (*ApplicableConfig_Project) Descriptor() ([]byte, []int)
- func (x *ApplicableConfig_Project) GetConfigGroupIds() []string
- func (x *ApplicableConfig_Project) GetName() string
- func (*ApplicableConfig_Project) ProtoMessage()
- func (x *ApplicableConfig_Project) ProtoReflect() protoreflect.Message
- func (x *ApplicableConfig_Project) Reset()
- func (x *ApplicableConfig_Project) String() string
- type CL
- type Dep
- type DepKind
- type DependentMeta
- type DependentMeta_Meta
- func (*DependentMeta_Meta) Descriptor() ([]byte, []int)
- func (x *DependentMeta_Meta) GetNoAccess() bool
- func (x *DependentMeta_Meta) GetUpdateTime() *timestamppb.Timestamp
- func (*DependentMeta_Meta) ProtoMessage()
- func (x *DependentMeta_Meta) ProtoReflect() protoreflect.Message
- func (x *DependentMeta_Meta) Reset()
- func (x *DependentMeta_Meta) String() string
- type ExternalID
- type Gerrit
- func (*Gerrit) Descriptor() ([]byte, []int)
- func (x *Gerrit) GetFiles() []string
- func (x *Gerrit) GetGitDeps() []*GerritGitDep
- func (x *Gerrit) GetHost() string
- func (x *Gerrit) GetInfo() *gerrit.ChangeInfo
- func (x *Gerrit) GetSoftDeps() []*GerritSoftDep
- func (*Gerrit) ProtoMessage()
- func (x *Gerrit) ProtoReflect() protoreflect.Message
- func (x *Gerrit) Reset()
- func (x *Gerrit) String() string
- type GerritGitDep
- type GerritSoftDep
- func (*GerritSoftDep) Descriptor() ([]byte, []int)
- func (x *GerritSoftDep) GetChange() int64
- func (x *GerritSoftDep) GetHost() string
- func (*GerritSoftDep) ProtoMessage()
- func (x *GerritSoftDep) ProtoReflect() protoreflect.Message
- func (x *GerritSoftDep) Reset()
- func (x *GerritSoftDep) String() string
- type Notify
- type Snapshot
- func (*Snapshot) Descriptor() ([]byte, []int)
- func (x *Snapshot) GetDeps() []*Dep
- func (x *Snapshot) GetExternalUpdateTime() *timestamppb.Timestamp
- func (x *Snapshot) GetGerrit() *Gerrit
- func (m *Snapshot) GetKind() isSnapshot_Kind
- func (x *Snapshot) GetLuciProject() string
- func (x *Snapshot) GetMinEquivalentPatchset() int32
- func (x *Snapshot) GetPatchset() int32
- func (s *Snapshot) IsUpToDate(luciProject string, t time.Time) bool
- func (s *Snapshot) OwnerIdentity() (identity.Identity, error)
- func (s *Snapshot) PanicIfNotValid()
- func (*Snapshot) ProtoMessage()
- func (x *Snapshot) ProtoReflect() protoreflect.Message
- func (x *Snapshot) Reset()
- func (x *Snapshot) String() string
- type Snapshot_Gerrit
- type UpdateFields
Constants ¶
Variables ¶
var ( DepKind_name = map[int32]string{ 0: "DEP_KIND_UNSPECIFIED", 1: "HARD", 2: "SOFT", } DepKind_value = map[string]int32{ "DEP_KIND_UNSPECIFIED": 0, "HARD": 1, "SOFT": 2, } )
Enum value maps for DepKind.
var File_go_chromium_org_luci_cv_internal_changelist_storage_proto protoreflect.FileDescriptor
Functions ¶
func Delete ¶
Delete deletes CL and its CLMap entities trasactionally.
Thus, Delete and insertion (part of ExternalID.getOrInsert) are atomic with respect to one another.
However, ExternalID.get and fast path of ExternalID.getOrInsert if called concurrently with Delete may return temporary error, but on retry they would return ErrNoSuchEntity.
func LoadMulti ¶
LoadMulti is datastore.Get(ctx, cls) which parallelizes & batches, staying within Datatstore limits even for large number of CLs.
TODO(tandrii): generalize it via reflection or once Go finally gets Generics. The same code also exists in run package.
func Lookup ¶
Lookup loads CLID for each given ExternalID.
CLID is 0 if ExternalID is not yet known. Always returns a singular error.
func RemoveUnusedGerritInfo ¶
func RemoveUnusedGerritInfo(ci *gerritpb.ChangeInfo)
RemoveUnusedGerritInfo mutates given ChangeInfo to remove what CV definitely doesn't need to reduce bytes shuffled to/from Datastore.
Doesn't complain if anything is missing.
NOTE: keep this function actions in sync with storage.proto doc for Gerrit.info field.
func Update ¶
func Update(ctx context.Context, eid ExternalID, knownCLID common.CLID, fields UpdateFields, notify Notify) error
Update updates CL entity.
Either ExternalID or a known common.CLID must be provided.
If common.CLID is not known and CL for provided ExternalID doesn't exist, then a new CL is created with values from UpdateFields. Otherwise, an existing CL entity will be updated as documented in UpdateFields.
If notify is given AND cl entity is created/updated, notify will be called in a transaction context after CL is successfully created/updated.
Types ¶
type ApplicableConfig ¶
type ApplicableConfig struct { Projects []*ApplicableConfig_Project `protobuf:"bytes,2,rep,name=projects,proto3" json:"projects,omitempty"` // contains filtered or unexported fields }
ApplicableConfig keeps track of configs applicable to a CL.
This is computed based on known set of LUCI project configs, versions of which are updated by CV independently, so the ApplicableConfig are also eventually consistent.
Normally, there is 1 applicable configs = exactly 1 project with 1 config group. If CL is no longer watched by CV, there will be 0 applicable configs.
Sometimes, there can be 2+ applicable configs. This happens if either:
* eventual consistency: responsibility for CL is moved from one LUCI project to another. Three is no way to make this atomically, so CL may temporarily end up with 0 or 2 projects watching it, before settling on just 1. * misconfiguration: two projects or 2 different ConfigGroups within the same project watch the same CL.
In either case, CV refuses to guess and will abstain from processing such CLs, but storing the list is very useful for CV debugging and potentially for better diagnostic messages to CV users and LUCI project owners.
func (*ApplicableConfig) Descriptor ¶
func (*ApplicableConfig) Descriptor() ([]byte, []int)
Deprecated: Use ApplicableConfig.ProtoReflect.Descriptor instead.
func (*ApplicableConfig) GetProjects ¶
func (x *ApplicableConfig) GetProjects() []*ApplicableConfig_Project
func (*ApplicableConfig) HasOnlyProject ¶
func (a *ApplicableConfig) HasOnlyProject(luciProject string) bool
HasOnlyProject returns true iff ApplicableConfig contains only the given project, regardless of the number of applicable config groups it may contain.
func (*ApplicableConfig) HasProject ¶
func (a *ApplicableConfig) HasProject(luciProject string) bool
HasProject returns true whether ApplicableConfig contains the given project, possibly among other projects.
func (*ApplicableConfig) ProtoMessage ¶
func (*ApplicableConfig) ProtoMessage()
func (*ApplicableConfig) ProtoReflect ¶
func (x *ApplicableConfig) ProtoReflect() protoreflect.Message
func (*ApplicableConfig) Reset ¶
func (x *ApplicableConfig) Reset()
func (*ApplicableConfig) SemanticallyEqual ¶
func (a *ApplicableConfig) SemanticallyEqual(b *ApplicableConfig) bool
SemanticallyEqual checks if ApplicableConfig configs are the same.
func (*ApplicableConfig) String ¶
func (x *ApplicableConfig) String() string
type ApplicableConfig_Project ¶
type ApplicableConfig_Project struct { Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` // ID of the specific ConfigGroup. See cv/internal/config.ConfigGroupID. // // The referenced version may no longer be available to datastore, // commonly happening if CL wasn't active for a long time. ConfigGroupIds []string `protobuf:"bytes,2,rep,name=config_group_ids,json=configGroupIds,proto3" json:"config_group_ids,omitempty"` // contains filtered or unexported fields }
func (*ApplicableConfig_Project) Descriptor ¶
func (*ApplicableConfig_Project) Descriptor() ([]byte, []int)
Deprecated: Use ApplicableConfig_Project.ProtoReflect.Descriptor instead.
func (*ApplicableConfig_Project) GetConfigGroupIds ¶
func (x *ApplicableConfig_Project) GetConfigGroupIds() []string
func (*ApplicableConfig_Project) GetName ¶
func (x *ApplicableConfig_Project) GetName() string
func (*ApplicableConfig_Project) ProtoMessage ¶
func (*ApplicableConfig_Project) ProtoMessage()
func (*ApplicableConfig_Project) ProtoReflect ¶
func (x *ApplicableConfig_Project) ProtoReflect() protoreflect.Message
func (*ApplicableConfig_Project) Reset ¶
func (x *ApplicableConfig_Project) Reset()
func (*ApplicableConfig_Project) String ¶
func (x *ApplicableConfig_Project) String() string
type CL ¶
type CL struct { // ID is auto-generated by Datastore. ID common.CLID `gae:"$id"` // int64 // ExternalID must not be modified once entity is created. ExternalID ExternalID `gae:",noindex"` // string. Indexed in CLMap entities. // EVersion is entity version. Every update should increment it by 1. // See Update() function. EVersion int `gae:",noindex"` // UpdateTime is exact time of when this entity was last updated. // // It's not indexed to avoid hot areas in the index. UpdateTime time.Time `gae:",noindex"` // Snapshot is latest known state of a CL. // It may and often is behind the source of truth -- the code reveview site // (e.g. Gerrit). Snapshot *Snapshot // ApplicableConfig keeps track of configs applicable to the CL. ApplicableConfig *ApplicableConfig // DependentMeta stores metadata per LUCI project about this CL being a dependency // of another CL in the context of the specific LUCI project. // // See description in protobuf type with the same name. DependentMeta *DependentMeta // IncompleteRuns tracks not yet finalized Runs working on this CL. Sorted. // // It's updated transactionally with the Run being modified. IncompleteRuns common.RunIDs `gae:",noindex"` // contains filtered or unexported fields }
CL is a CL entity in Datastore.
type Dep ¶
type Dep struct { // CLID is internal CV ID of a CL which is the dependency. Clid int64 `protobuf:"varint,1,opt,name=clid,proto3" json:"clid,omitempty"` Kind DepKind `protobuf:"varint,2,opt,name=kind,proto3,enum=cv.changelist.DepKind" json:"kind,omitempty"` // contains filtered or unexported fields }
func (*Dep) Descriptor ¶
Deprecated: Use Dep.ProtoReflect.Descriptor instead.
func (*Dep) ProtoMessage ¶
func (*Dep) ProtoMessage()
func (*Dep) ProtoReflect ¶
func (x *Dep) ProtoReflect() protoreflect.Message
type DepKind ¶
type DepKind int32
func (DepKind) Descriptor ¶
func (DepKind) Descriptor() protoreflect.EnumDescriptor
func (DepKind) EnumDescriptor ¶
Deprecated: Use DepKind.Descriptor instead.
func (DepKind) Number ¶
func (x DepKind) Number() protoreflect.EnumNumber
func (DepKind) Type ¶
func (DepKind) Type() protoreflect.EnumType
type DependentMeta ¶
type DependentMeta struct { // Maps LUCI Project to metadata. ByProject map[string]*DependentMeta_Meta `` /* 176-byte string literal not displayed */ // contains filtered or unexported fields }
DependentMeta stores metadata per LUCI project about this CL being a dependency of another one in the context of the specific LUCI project.
This is necessary because soft dependencies (e.g. via CQ-Depend) can be arbitrary CL references (e.g. any GoBID), which aren't alone sufficient to determine ApplicableConfig. Thus, code review has to be queried first for CL details.
In ideal case, code review responds with CL details, CV can verify that CL is watched by the current project, and then save Snapshot and ApplicableConfig.
However, codereview may respond with an 403/404 error, s.t. CV can't determine an ApplicableConfig, but CV needs to persist the 403/404 error fact somehow s.t. it differs from yet-to-be-fetched CL.
To illustrate, consider dependency of CL 200000 specified via
CQ-Depend: chrome-internal:184849
in the context of `infra-internal` project. CV first needs to fetch 184849 details from Gerrit authenticating as `infra-internal`. This CL doesn't belong to any infra repo, and as such `infra-internal` project-scoped account doesn't have READ access to it, so Gerrit responds with 404. This fact is stored in .DependentMeta["infra-internal"] = 404. Later, ProjectManager will read this fact, and respond on CL 200000 that CQ-Depend footer is wrong.
func (*DependentMeta) Descriptor ¶
func (*DependentMeta) Descriptor() ([]byte, []int)
Deprecated: Use DependentMeta.ProtoReflect.Descriptor instead.
func (*DependentMeta) GetByProject ¶
func (x *DependentMeta) GetByProject() map[string]*DependentMeta_Meta
func (*DependentMeta) ProtoMessage ¶
func (*DependentMeta) ProtoMessage()
func (*DependentMeta) ProtoReflect ¶
func (x *DependentMeta) ProtoReflect() protoreflect.Message
func (*DependentMeta) Reset ¶
func (x *DependentMeta) Reset()
func (*DependentMeta) String ¶
func (x *DependentMeta) String() string
type DependentMeta_Meta ¶
type DependentMeta_Meta struct { // If true, means this CL doesn't exist or it isn't accessible to the // specific LUCI project. NoAccess bool `protobuf:"varint,1,opt,name=no_access,json=noAccess,proto3" json:"no_access,omitempty"` // The timestamp when this was computed. UpdateTime *timestamppb.Timestamp `protobuf:"bytes,2,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"` // contains filtered or unexported fields }
func (*DependentMeta_Meta) Descriptor ¶
func (*DependentMeta_Meta) Descriptor() ([]byte, []int)
Deprecated: Use DependentMeta_Meta.ProtoReflect.Descriptor instead.
func (*DependentMeta_Meta) GetNoAccess ¶
func (x *DependentMeta_Meta) GetNoAccess() bool
func (*DependentMeta_Meta) GetUpdateTime ¶
func (x *DependentMeta_Meta) GetUpdateTime() *timestamppb.Timestamp
func (*DependentMeta_Meta) ProtoMessage ¶
func (*DependentMeta_Meta) ProtoMessage()
func (*DependentMeta_Meta) ProtoReflect ¶
func (x *DependentMeta_Meta) ProtoReflect() protoreflect.Message
func (*DependentMeta_Meta) Reset ¶
func (x *DependentMeta_Meta) Reset()
func (*DependentMeta_Meta) String ¶
func (x *DependentMeta_Meta) String() string
type ExternalID ¶
type ExternalID string
ExternalID is a unique CL ID deterministically constructed based on CL data.
Currently, only Gerrit is supported.
func GobID ¶
func GobID(host string, change int64) (ExternalID, error)
GobID makes an ExternalID for a Gerrit CL.
Host is typically "something-review.googlesource.com". Change is a number, e.g. 2515619 for https://chromium-review.googlesource.com/c/infra/luci/luci-go/+/2515619
func MustGobID ¶
func MustGobID(host string, change int64) ExternalID
MustGobID is like GobID but panic on error.
func (ExternalID) Get ¶
func (eid ExternalID) Get(ctx context.Context) (*CL, error)
Get reads a CL from datastore.
Returns datastore.ErrNoSuchEntity if it doesn't exist.
func (ExternalID) GetOrInsert ¶
GetOrInsert reads a CL from datastore, creating a new one if not exists yet.
populate is called within a transaction to populate fields of a new entity. It should be a fast function.
Warning:
* populate may be called several times since transaction can be retried. * cl.ExternalID and cl.ID must not be changed by populate.
func (ExternalID) ParseGobID ¶
func (e ExternalID) ParseGobID() (host string, change int64, err error)
ParseGobID returns Gerrit host and change if this is a GobID.
type Gerrit ¶
type Gerrit struct { // Gerrit host. Host string `protobuf:"bytes,5,opt,name=host,proto3" json:"host,omitempty"` // Info contains subset of ChangeInfo listed below. // // NOTE: keep this list in sync with RemoveUnusedGerritInfo() function. // * number // * owner // * id // * email (may be not set) // * project // * ref // * status // * current_revision // * revisions // * kind // * number // * ref // * created // * description (patchset title) // * commit (for current_revision only) // * message (current CL description) // * labels // * optional // * all (only if vote != 0) // * user // * id // * email (may be not set) // * value // * messages // * id // * date // * message // * author // * id // * realauthor // * id // * updated // * created Info *gerrit.ChangeInfo `protobuf:"bytes,1,opt,name=info,proto3" json:"info,omitempty"` // Files are filenames touched in the current revision. // // It's derived from gerrit.ListFilesResponse, see // https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#list-files. Files []string `protobuf:"bytes,2,rep,name=files,proto3" json:"files,omitempty"` // Git dependencies of the current revision. GitDeps []*GerritGitDep `protobuf:"bytes,3,rep,name=git_deps,json=gitDeps,proto3" json:"git_deps,omitempty"` // Free-form dependencies. Currently, sourced from CQ-Depend footers. // In the future, this may be derived from Gerrit hashtags, topics, or other // mechanisms. SoftDeps []*GerritSoftDep `protobuf:"bytes,4,rep,name=soft_deps,json=softDeps,proto3" json:"soft_deps,omitempty"` // contains filtered or unexported fields }
func (*Gerrit) Descriptor ¶
Deprecated: Use Gerrit.ProtoReflect.Descriptor instead.
func (*Gerrit) GetGitDeps ¶
func (x *Gerrit) GetGitDeps() []*GerritGitDep
func (*Gerrit) GetInfo ¶
func (x *Gerrit) GetInfo() *gerrit.ChangeInfo
func (*Gerrit) GetSoftDeps ¶
func (x *Gerrit) GetSoftDeps() []*GerritSoftDep
func (*Gerrit) ProtoMessage ¶
func (*Gerrit) ProtoMessage()
func (*Gerrit) ProtoReflect ¶
func (x *Gerrit) ProtoReflect() protoreflect.Message
type GerritGitDep ¶
type GerritGitDep struct { // Gerrit Change number. Change int64 `protobuf:"varint,1,opt,name=change,proto3" json:"change,omitempty"` // Immediate is set iff this dep is an immediate parent of the Gerrit CL. // // Immediate dep must be submitted before its child. // Non-immediate CLs don't necessarily have to be submitted before: // for example, for a chain <base> <- A1 <- B1 <- C1 <- D1 // D1's deps are [A,B,C] but only C is immediate, and 1 stands for patchset. // Developer may then swap B,C without re-uploading D (say, to avoid // patchset churn), resulting in a new logical chain: // <base> <- A1 <- C2 <- B2 // \ // <- B1 <- C1 <- D1 // // In this case, Gerrit's related changes for D1 will still return A1,B1,C1, // which CV interprets as C must be landed before D, while B and A should // be landed before D. // // TODO(tandrii): this is replicating existing CQDaemon logic. I think // it'd be reasonable to treat all (A,B,C) as MUST BE submitted before D. Immediate bool `protobuf:"varint,2,opt,name=immediate,proto3" json:"immediate,omitempty"` // contains filtered or unexported fields }
GerritGitDep is a dependency discovered via Git child->parent chain for one Gerrit CL.
func (*GerritGitDep) Descriptor ¶
func (*GerritGitDep) Descriptor() ([]byte, []int)
Deprecated: Use GerritGitDep.ProtoReflect.Descriptor instead.
func (*GerritGitDep) GetChange ¶
func (x *GerritGitDep) GetChange() int64
func (*GerritGitDep) GetImmediate ¶
func (x *GerritGitDep) GetImmediate() bool
func (*GerritGitDep) ProtoMessage ¶
func (*GerritGitDep) ProtoMessage()
func (*GerritGitDep) ProtoReflect ¶
func (x *GerritGitDep) ProtoReflect() protoreflect.Message
func (*GerritGitDep) Reset ¶
func (x *GerritGitDep) Reset()
func (*GerritGitDep) String ¶
func (x *GerritGitDep) String() string
type GerritSoftDep ¶
type GerritSoftDep struct { // Gerrit host. Host string `protobuf:"bytes,1,opt,name=host,proto3" json:"host,omitempty"` // Gerrit change number. Change int64 `protobuf:"varint,2,opt,name=change,proto3" json:"change,omitempty"` // contains filtered or unexported fields }
func (*GerritSoftDep) Descriptor ¶
func (*GerritSoftDep) Descriptor() ([]byte, []int)
Deprecated: Use GerritSoftDep.ProtoReflect.Descriptor instead.
func (*GerritSoftDep) GetChange ¶
func (x *GerritSoftDep) GetChange() int64
func (*GerritSoftDep) GetHost ¶
func (x *GerritSoftDep) GetHost() string
func (*GerritSoftDep) ProtoMessage ¶
func (*GerritSoftDep) ProtoMessage()
func (*GerritSoftDep) ProtoReflect ¶
func (x *GerritSoftDep) ProtoReflect() protoreflect.Message
func (*GerritSoftDep) Reset ¶
func (x *GerritSoftDep) Reset()
func (*GerritSoftDep) String ¶
func (x *GerritSoftDep) String() string
type Notify ¶
Notify is called with the updated CL in a transaction context after CL is successfully created/updated.
type Snapshot ¶
type Snapshot struct { // The timestamp from external system. // Used to determine if re-querying external system is needed. ExternalUpdateTime *timestamppb.Timestamp `protobuf:"bytes,1,opt,name=external_update_time,json=externalUpdateTime,proto3" json:"external_update_time,omitempty"` // LUCI project in the context of which this snapshot was saved. // // Since a CL isn't a resource of CV, CV can't infer whether specific LUCI // project has access to a CL w/o re-querying Gerrit and effectively // recomputing the snapshot. LuciProject string `protobuf:"bytes,2,opt,name=luci_project,json=luciProject,proto3" json:"luci_project,omitempty"` // Resolved dependencies of a CL. Deps []*Dep `protobuf:"bytes,3,rep,name=deps,proto3" json:"deps,omitempty"` // Patchset is incremental number of the latest patchset (aka revision). Patchset int32 `protobuf:"varint,4,opt,name=patchset,proto3" json:"patchset,omitempty"` // MinEquivalentPatchset is the smallest and hence the earliest patchset // which is code-wise equivalent to the latest one. // // See gerrit.EquivalentPatchsetRange function for details. // // CV tracks this to determine which prior tryjobs can be re-used and which // can be canceled. MinEquivalentPatchset int32 `` /* 127-byte string literal not displayed */ // CL-kind specific data. // // Types that are assignable to Kind: // *Snapshot_Gerrit Kind isSnapshot_Kind `protobuf_oneof:"kind"` // contains filtered or unexported fields }
Snapshot stores a snapshot of CL info as seen by CV at a certain time.
When stored in CL entity, represents latest known Gerrit data. When stored in RunCL entity, represents data pertaining to a fixed patchset.
func (*Snapshot) Descriptor ¶
Deprecated: Use Snapshot.ProtoReflect.Descriptor instead.
func (*Snapshot) GetExternalUpdateTime ¶
func (x *Snapshot) GetExternalUpdateTime() *timestamppb.Timestamp
func (*Snapshot) GetLuciProject ¶
func (*Snapshot) GetMinEquivalentPatchset ¶
func (*Snapshot) GetPatchset ¶
func (*Snapshot) IsUpToDate ¶
IsUpToDate returns whether stored Snapshot is at least as recent as given time and was done for a matching LUCI project.
func (*Snapshot) OwnerIdentity ¶
OwnerIdentity is the identity of a user owning this CL.
Snapshot must not be nil.
func (*Snapshot) PanicIfNotValid ¶
func (s *Snapshot) PanicIfNotValid()
PanicIfNotValid checks that Snapshot stored has required fields set.
func (*Snapshot) ProtoMessage ¶
func (*Snapshot) ProtoMessage()
func (*Snapshot) ProtoReflect ¶
func (x *Snapshot) ProtoReflect() protoreflect.Message
type Snapshot_Gerrit ¶
type Snapshot_Gerrit struct {
Gerrit *Gerrit `protobuf:"bytes,11,opt,name=gerrit,proto3,oneof"`
}
type UpdateFields ¶
type UpdateFields struct { // Snapshot overwrites existing CL snapshot if newer according to its // .ExternalUpdateTime. Snapshot *Snapshot // ApplicableConfig overwrites existing CL ApplicableConfig if semantically // different from existing one. ApplicableConfig *ApplicableConfig // AddDependentMeta adds or overwrites metadata per LUCI project in CL AsDepMeta. // Doesn't affect metadata stored for projects not referenced here. AddDependentMeta *DependentMeta }
UpdateFields defines what parts of CL metadata to update.
At least one field must be specified.
func (UpdateFields) IsEmpty ¶
func (u UpdateFields) IsEmpty() bool
IsEmpty returns true if no updates are necessary.