Skip to content

Commit 5d436d4

Browse files
committed
Partially support overridable fields.
This only supports title and published right now, but could be trivially extended for other template fields.
1 parent 060a147 commit 5d436d4

File tree

6 files changed

+311
-22
lines changed

6 files changed

+311
-22
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.13
55
require (
66
github.com/dustin/go-humanize v1.0.0
77
github.com/efritz/pentimento v0.0.0-20190429011147-ade47d831101
8+
github.com/gobwas/glob v0.2.3
89
github.com/google/go-cmp v0.4.1
910
github.com/hashicorp/go-multierror v1.1.0
1011
github.com/jig/teereadcloser v0.0.0-20181016160506-953720c48e05

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4
44
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
55
github.com/efritz/pentimento v0.0.0-20190429011147-ade47d831101 h1:RylpU+KNJJNEJIk3o8gZ70uPTlutxaYnikKNPko39LA=
66
github.com/efritz/pentimento v0.0.0-20190429011147-ade47d831101/go.mod h1:5ALWO82UZwfAtNRUtwzsWimcrcuYzyieTyyXOXrP6EQ=
7+
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
8+
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
79
github.com/google/go-cmp v0.4.1 h1:/exdXoGamhu5ONeUJH0deniYLWYvQwW66yvlfiiKTu0=
810
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
911
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@@ -31,8 +33,6 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
3133
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
3234
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
3335
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
34-
github.com/sourcegraph/codeintelutils v0.0.0-20200706141440-54ddac67b5b6 h1:91WE5oskxcHBJIiK8GeUDqGQJWaUBiI0LBfvRxAcDX4=
35-
github.com/sourcegraph/codeintelutils v0.0.0-20200706141440-54ddac67b5b6/go.mod h1:HplI8gRslTrTUUsSYwu28hSOderix7m5dHNca7xBzeo=
3636
github.com/sourcegraph/codeintelutils v0.0.0-20200824140252-1db3aed5cf58 h1:Ps+U1xoZP+Zoph39YfRB6Q846ghO8pgrAgp0MiObvPs=
3737
github.com/sourcegraph/codeintelutils v0.0.0-20200824140252-1db3aed5cf58/go.mod h1:HplI8gRslTrTUUsSYwu28hSOderix7m5dHNca7xBzeo=
3838
github.com/sourcegraph/jsonx v0.0.0-20200629203448-1a936bd500cf h1:oAdWFqhStsWiiMP/vkkHiMXqFXzl1XfUNOdxKJbd6bI=

internal/campaigns/campaign_spec.go

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package campaigns
22

33
import (
4+
"encoding/json"
45
"fmt"
56

7+
"github.com/gobwas/glob"
68
"github.com/hashicorp/go-multierror"
79
"github.com/pkg/errors"
10+
"github.com/sourcegraph/src-cli/internal/campaigns/graphql"
811
"github.com/sourcegraph/src-cli/schema"
912
"github.com/xeipuuv/gojsonschema"
1013
"gopkg.in/yaml.v2"
@@ -36,11 +39,11 @@ type CampaignSpec struct {
3639
}
3740

3841
type ChangesetTemplate struct {
39-
Title string `json:"title,omitempty" yaml:"title"`
42+
Title OverridableString `json:"title,omitempty" yaml:"title"`
4043
Body string `json:"body,omitempty" yaml:"body"`
4144
Branch string `json:"branch,omitempty" yaml:"branch"`
4245
Commit ExpandedGitCommitDescription `json:"commit,omitempty" yaml:"commit"`
43-
Published bool `json:"published" yaml:"published"`
46+
Published OverridableBool `json:"published" yaml:"published"`
4447
}
4548

4649
type ExpandedGitCommitDescription struct {
@@ -58,6 +61,153 @@ type OnQueryOrRepository struct {
5861
Branch string `json:"branch,omitempty" yaml:"branch"`
5962
}
6063

64+
type OverridableBool struct {
65+
Default *bool
66+
OnlyExcept
67+
}
68+
69+
type OnlyExcept struct {
70+
Only []string `json:"only,omitempty" yaml:"only"`
71+
Except []string `json:"except,omitempty" yaml:"except"`
72+
73+
only []glob.Glob
74+
except []glob.Glob
75+
}
76+
77+
func (p *OverridableBool) IsRepoPublished(repo *graphql.Repository) bool {
78+
if p.Default != nil {
79+
return *p.Default
80+
}
81+
82+
if len(p.only) > 0 {
83+
for _, g := range p.only {
84+
if g.Match(repo.Name) {
85+
return true
86+
}
87+
}
88+
return false
89+
}
90+
91+
for _, g := range p.except {
92+
if g.Match(repo.Name) {
93+
return false
94+
}
95+
}
96+
return true
97+
}
98+
99+
func (p *OverridableBool) MarshalJSON() ([]byte, error) {
100+
if p.Default != nil {
101+
return json.Marshal(*p.Default)
102+
}
103+
104+
return json.Marshal(&p.OnlyExcept)
105+
}
106+
107+
func (p *OverridableBool) UnmarshalYAML(unmarshal func(interface{}) error) error {
108+
var def bool
109+
if err := unmarshal(&def); err == nil {
110+
p.Default = &def
111+
return nil
112+
}
113+
114+
p.Default = nil
115+
if err := unmarshal(&p.OnlyExcept); err != nil {
116+
return err
117+
}
118+
119+
var err error
120+
p.only, err = compilePatterns(p.Only)
121+
if err != nil {
122+
return err
123+
}
124+
125+
p.except, err = compilePatterns(p.Except)
126+
if err != nil {
127+
return err
128+
}
129+
130+
return nil
131+
}
132+
133+
func compilePatterns(patterns []string) ([]glob.Glob, error) {
134+
globs := make([]glob.Glob, len(patterns))
135+
for i, pattern := range patterns {
136+
g, err := glob.Compile(pattern)
137+
if err != nil {
138+
return nil, errors.Wrapf(err, "compiling repo pattern %q", pattern)
139+
}
140+
141+
globs[i] = g
142+
}
143+
144+
return globs, nil
145+
}
146+
147+
type OverridableString struct {
148+
Default string
149+
Only []*MatchValue
150+
}
151+
152+
type MatchValue struct {
153+
Match string `json:"match,omitempty" yaml:"match"`
154+
Value string `json:"value,omitempty" yaml:"value"`
155+
156+
match glob.Glob
157+
}
158+
159+
func (o *OverridableString) Value(repo *graphql.Repository) string {
160+
for _, mv := range o.Only {
161+
if mv.match.Match(repo.Name) {
162+
return mv.Value
163+
}
164+
}
165+
166+
return o.Default
167+
}
168+
169+
func (o *OverridableString) MarshalJSON() ([]byte, error) {
170+
if len(o.Only) == 0 {
171+
return json.Marshal(o.Default)
172+
}
173+
174+
return json.Marshal(&struct {
175+
Default string `json:"default,omitempty"`
176+
Only []*MatchValue `json:"only,omitempty"`
177+
}{
178+
Default: o.Default,
179+
Only: o.Only,
180+
})
181+
}
182+
183+
func (o *OverridableString) UnmarshalYAML(unmarshal func(interface{}) error) error {
184+
var s string
185+
if err := unmarshal(&s); err == nil {
186+
o.Default = s
187+
o.Only = []*MatchValue{}
188+
return nil
189+
}
190+
191+
var temp struct {
192+
Default string `yaml:"default"`
193+
Only []*MatchValue `yaml:"only"`
194+
}
195+
if err := unmarshal(&temp); err != nil {
196+
return err
197+
}
198+
199+
o.Default = temp.Default
200+
o.Only = temp.Only
201+
for _, mv := range o.Only {
202+
var err error
203+
if mv.match, err = glob.Compile(mv.Match); err != nil {
204+
return errors.Wrapf(err, "compiling repo pattern %q", mv.match)
205+
}
206+
}
207+
208+
return nil
209+
}
210+
61211
type Step struct {
62212
Run string `json:"run,omitempty" yaml:"run"`
63213
Container string `json:"container,omitempty" yaml:"container"`

internal/campaigns/executor.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,15 +253,15 @@ func createChangesetSpec(task *Task, diff string) *ChangesetSpec {
253253
BaseRev: task.Repository.Rev(),
254254
HeadRepository: task.Repository.ID,
255255
HeadRef: "refs/heads/" + task.Template.Branch,
256-
Title: task.Template.Title,
256+
Title: task.Template.Title.Value(task.Repository),
257257
Body: task.Template.Body,
258258
Commits: []GitCommitDescription{
259259
{
260260
Message: task.Template.Commit.Message,
261261
Diff: string(diff),
262262
},
263263
},
264-
Published: task.Template.Published,
264+
Published: task.Template.Published.IsRepoPublished(task.Repository),
265265
},
266266
}
267267
}

schema/campaign_spec.schema.json

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,8 +115,48 @@
115115
"additionalProperties": false,
116116
"required": ["title", "branch", "commit", "published"],
117117
"properties": {
118-
"title": { "type": "string", "description": "The title of the changeset." },
119-
"body": { "type": "string", "description": "The body (description) of the changeset." },
118+
"title": {
119+
"description": "The title of the changeset.",
120+
"oneOf": [
121+
{
122+
"type": "string",
123+
"description": "The title to use for the entire campaign."
124+
},
125+
{
126+
"type": "object",
127+
"required": ["default", "only"],
128+
"additionalProperties": false,
129+
"properties": {
130+
"default": {
131+
"type": "string",
132+
"description": "The title to use for all changesets that do not match any of the rules in the only array."
133+
},
134+
"only": {
135+
"type": "array",
136+
"items": {
137+
"type": "object",
138+
"required": ["match", "value"],
139+
"additionalProperties": false,
140+
"properties": {
141+
"match": {
142+
"type": "string",
143+
"description": "The repository name to match. Glob wildcards are supported."
144+
},
145+
"value": {
146+
"type": "string",
147+
"description": "The title to use for changesets that match this rule."
148+
}
149+
}
150+
}
151+
}
152+
}
153+
}
154+
]
155+
},
156+
"body": {
157+
"type": "string",
158+
"description": "The body (description) of the changeset."
159+
},
120160
"branch": {
121161
"type": "string",
122162
"description": "The name of the Git branch to create or update on each repository with the changes."
@@ -135,9 +175,45 @@
135175
}
136176
},
137177
"published": {
138-
"type": "boolean",
139178
"description": "Whether to publish the changeset. An unpublished changeset can be previewed on Sourcegraph by any person who can view the campaign, but its commit, branch, and pull request aren't created on the code host. A published changeset results in a commit, branch, and pull request being created on the code host.",
140-
"$comment": "TODO(sqs): Come up with a way to specify that only a subset of changesets should be published. For example, making `published` an array with some include/exclude syntax items."
179+
"oneOf": [
180+
{
181+
"type": "boolean",
182+
"description": "A single flag to control the publishing state for the entire campaign."
183+
},
184+
{
185+
"oneOf": [
186+
{
187+
"type": "object",
188+
"description": "Only repositories that match patterns in this array will be published.",
189+
"additionalProperties": false,
190+
"required": ["only"],
191+
"properties": {
192+
"only": {
193+
"type": "array",
194+
"items": {
195+
"type": "string"
196+
}
197+
}
198+
}
199+
},
200+
{
201+
"type": "object",
202+
"description": "Only repositories that do NOT match patterns in this array will be published.",
203+
"additionalProperties": false,
204+
"required": ["except"],
205+
"properties": {
206+
"except": {
207+
"type": "array",
208+
"items": {
209+
"type": "string"
210+
}
211+
}
212+
}
213+
}
214+
]
215+
}
216+
]
141217
}
142218
}
143219
}

0 commit comments

Comments
 (0)