Skip to content

Commit 0ce1ae4

Browse files
authored
Fix: no longer require SRC_GITHUB_TOKEN to be set (#958)
1 parent 97b08ed commit 0ce1ae4

File tree

5 files changed

+340
-309
lines changed

5 files changed

+340
-309
lines changed

cmd/src/validate_install.go

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import (
1111
"github.com/mattn/go-isatty"
1212

1313
"github.com/sourcegraph/src-cli/internal/api"
14-
"github.com/sourcegraph/src-cli/internal/validate"
1514
"github.com/sourcegraph/src-cli/internal/validate/install"
1615

1716
"github.com/sourcegraph/sourcegraph/lib/errors"
@@ -97,14 +96,7 @@ Environmental variables
9796
validationSpec = install.DefaultConfig()
9897
}
9998

100-
envGithubToken := os.Getenv("SRC_GITHUB_TOKEN")
101-
102-
// will work for now with only GitHub supported but will need to be revisited when other code hosts are supported
103-
if envGithubToken == "" {
104-
return errors.Newf("%s failed to read `SRC_GITHUB_TOKEN` environment variable", validate.WarningSign)
105-
}
106-
107-
validationSpec.ExternalService.Config.GitHub.Token = envGithubToken
99+
validationSpec.ExternalService.Config.GitHub.Token = os.Getenv("SRC_GITHUB_TOKEN")
108100

109101
return install.Validate(context.Background(), client, validationSpec)
110102
}
Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
package install
2+
3+
import (
4+
"encoding/json"
5+
6+
"gopkg.in/yaml.v3"
7+
)
8+
9+
type ExternalService struct {
10+
// Type of code host, e.g. GITHUB.
11+
Kind string `yaml:"kind"`
12+
13+
// Display name of external service, e.g. sourcegraph-test.
14+
DisplayName string `yaml:"displayName"`
15+
16+
// Configuration for code host.
17+
Config Config `yaml:"config"`
18+
19+
// Maximum retry attempts when cloning test repositories. Defaults to 5 retries.
20+
MaxRetries int `yaml:"maxRetries"`
21+
22+
// Retry timeout in seconds. Defaults to 5 seconds
23+
RetryTimeoutSeconds int `yaml:"retryTimeoutSeconds"`
24+
25+
// Delete code host when test is done. Defaults to true.
26+
DeleteWhenDone bool `yaml:"deleteWhenDone"`
27+
}
28+
29+
// Config for different types of code hosts.
30+
type Config struct {
31+
GitHub GitHub `yaml:"gitHub"`
32+
}
33+
34+
// GitHub configuration parameters.
35+
type GitHub struct {
36+
// URL used to access your GitHub instance, e.g. https://github.com.
37+
URL string `yaml:"url" json:"url"`
38+
39+
// Auth token used to authenticate to GitHub instance. This should be provided via env var SRC_GITHUB_TOKEN.
40+
Token string `yaml:"token" json:"token"`
41+
42+
// List of organizations.
43+
Orgs []string `yaml:"orgs" json:"orgs"`
44+
45+
// List of repositories to pull.
46+
Repos []string `yaml:"repos" json:"repos"`
47+
}
48+
49+
type Insight struct {
50+
Title string `yaml:"title"`
51+
DataSeries []map[string]any `yaml:"dataSeries"`
52+
DeleteWhenDone bool `yaml:"deleteWhenDone"`
53+
}
54+
55+
type ValidationSpec struct {
56+
// Search queries used for validation testing, e.g. "repo:^github\\.com/gorilla/mux$ Router".
57+
SearchQuery []string `yaml:"searchQuery"`
58+
59+
// External Service configuration.
60+
ExternalService ExternalService `yaml:"externalService"`
61+
62+
// Insight used for validation testing.
63+
Insight Insight `yaml:"insight"`
64+
}
65+
66+
// DefaultConfig returns a default configuration to be used for testing.
67+
func DefaultConfig() *ValidationSpec {
68+
return &ValidationSpec{
69+
SearchQuery: []string{
70+
"repo:^github.com/sourcegraph/src-cli$ config",
71+
"repo:^github.com/sourcegraph/src-cli$@4.0.0 config",
72+
"repo:^github.com/sourcegraph/src-cli$ type:symbol config",
73+
},
74+
ExternalService: ExternalService{
75+
Kind: "GITHUB",
76+
DisplayName: "sourcegraph-test",
77+
Config: Config{
78+
GitHub: GitHub{
79+
URL: "https://github.com",
80+
Token: "",
81+
Orgs: []string{},
82+
Repos: []string{"sourcegraph/src-cli"},
83+
},
84+
},
85+
MaxRetries: 5,
86+
RetryTimeoutSeconds: 5,
87+
DeleteWhenDone: true,
88+
},
89+
Insight: Insight{
90+
Title: "test insight",
91+
DataSeries: []map[string]any{
92+
{
93+
"query": "lang:javascript",
94+
"label": "javascript",
95+
"repositoryScope": "",
96+
"lineColor": "#6495ED",
97+
"timeScopeUnit": "MONTH",
98+
"timeScopeValue": 1,
99+
},
100+
{
101+
"query": "lang:typescript",
102+
"label": "typescript",
103+
"lineColor": "#DE3163",
104+
"repositoryScope": "",
105+
"timeScopeUnit": "MONTH",
106+
"timeScopeValue": 1,
107+
},
108+
},
109+
DeleteWhenDone: true,
110+
},
111+
}
112+
}
113+
114+
// LoadYamlConfig will unmarshal a YAML configuration file into a ValidationSpec.
115+
func LoadYamlConfig(userConfig []byte) (*ValidationSpec, error) {
116+
var config ValidationSpec
117+
if err := yaml.Unmarshal(userConfig, &config); err != nil {
118+
return nil, err
119+
}
120+
121+
return &config, nil
122+
}
123+
124+
// LoadJsonConfig will unmarshal a JSON configuration file into a ValidationSpec.
125+
func LoadJsonConfig(userConfig []byte) (*ValidationSpec, error) {
126+
var config ValidationSpec
127+
if err := json.Unmarshal(userConfig, &config); err != nil {
128+
return nil, err
129+
}
130+
131+
return &config, nil
132+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package install
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"log"
8+
9+
"github.com/sourcegraph/src-cli/internal/api"
10+
"github.com/sourcegraph/src-cli/internal/validate"
11+
12+
"github.com/sourcegraph/sourcegraph/lib/errors"
13+
)
14+
15+
const GITHUB = "GITHUB"
16+
17+
func validateGithub(ctx context.Context, client api.Client, config *ValidationSpec) (func(), error) {
18+
// validate external service
19+
log.Printf("%s validating external service", validate.EmojiFingerPointRight)
20+
21+
srvId, err := addGithubExternalService(ctx, client, config.ExternalService)
22+
if err != nil {
23+
return nil, err
24+
}
25+
26+
log.Printf("%s external service %s is being added", validate.HourglassEmoji, config.ExternalService.DisplayName)
27+
28+
cleanupFunc := func() {
29+
if srvId != "" && config.ExternalService.DeleteWhenDone {
30+
_ = removeExternalService(ctx, client, srvId)
31+
log.Printf("%s external service %s has been removed", validate.SuccessEmoji, config.ExternalService.DisplayName)
32+
}
33+
}
34+
35+
log.Printf("%s cloning repository", validate.HourglassEmoji)
36+
37+
repo := fmt.Sprintf("github.com/%s", config.ExternalService.Config.GitHub.Repos[0])
38+
cloned, err := repoCloneTimeout(ctx, client, repo, config.ExternalService)
39+
if err != nil {
40+
return nil, err
41+
}
42+
if !cloned {
43+
return nil, errors.Newf("%s validate failed, repo did not clone\n", validate.FailureEmoji)
44+
}
45+
46+
log.Printf("%s repositry successfully cloned", validate.SuccessEmoji)
47+
48+
return cleanupFunc, nil
49+
}
50+
51+
func addGithubExternalService(ctx context.Context, client api.Client, srv ExternalService) (string, error) {
52+
if srv.Config.GitHub.Token == "" {
53+
return "", errors.Newf("%s failed to read `SRC_GITHUB_TOKEN` environment variable", validate.WarningSign)
54+
}
55+
56+
cfg, err := json.Marshal(srv.Config.GitHub)
57+
if err != nil {
58+
return "", errors.Wrap(err, "addExternalService failed")
59+
}
60+
61+
q := clientQuery{
62+
opName: "AddExternalService",
63+
query: `mutation AddExternalService($kind: ExternalServiceKind!, $displayName: String!, $config: String!) {
64+
addExternalService(input:{
65+
kind:$kind,
66+
displayName:$displayName,
67+
config: $config
68+
})
69+
{
70+
id
71+
}
72+
}`,
73+
variables: jsonVars{
74+
"kind": GITHUB,
75+
"displayName": srv.DisplayName,
76+
"config": string(cfg),
77+
},
78+
}
79+
80+
var result struct {
81+
AddExternalService struct {
82+
ID string `json:"id"`
83+
} `json:"addExternalService"`
84+
}
85+
86+
ok, err := client.NewRequest(q.query, q.variables).Do(ctx, &result)
87+
if err != nil {
88+
return "", errors.Wrap(err, "addExternalService failed")
89+
}
90+
if !ok {
91+
return "", errors.New("addExternalService failed, no data to unmarshal")
92+
}
93+
94+
return result.AddExternalService.ID, nil
95+
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package install
2+
3+
import (
4+
"context"
5+
6+
"github.com/sourcegraph/src-cli/internal/api"
7+
8+
"github.com/sourcegraph/sourcegraph/lib/errors"
9+
)
10+
11+
func createInsight(ctx context.Context, client api.Client, insight Insight) (string, error) {
12+
var dataSeries []map[string]interface{}
13+
14+
for _, ds := range insight.DataSeries {
15+
var series = map[string]interface{}{
16+
"query": ds["query"],
17+
"options": map[string]interface{}{
18+
"label": ds["label"],
19+
"lineColor": ds["lineColor"],
20+
},
21+
"repositoryScope": map[string]interface{}{
22+
"repositories": ds["repositoryScope"],
23+
},
24+
"timeScope": map[string]interface{}{
25+
"stepInterval": map[string]interface{}{
26+
"unit": ds["timeScopeUnit"],
27+
"value": ds["timeScopeValue"],
28+
},
29+
},
30+
}
31+
32+
dataSeries = append(dataSeries, series)
33+
}
34+
35+
q := clientQuery{
36+
opName: "CreateLineChartSearchInsight",
37+
query: `mutation CreateLineChartSearchInsight($input: LineChartSearchInsightInput!) {
38+
createLineChartSearchInsight(input: $input) {
39+
view {
40+
id
41+
}
42+
}
43+
}`,
44+
variables: jsonVars{
45+
"input": map[string]interface{}{
46+
"options": map[string]interface{}{"title": insight.Title},
47+
"dataSeries": dataSeries,
48+
},
49+
},
50+
}
51+
52+
var result struct {
53+
CreateLineChartSearchInsight struct {
54+
View struct {
55+
ID string `json:"id"`
56+
} `json:"view"`
57+
} `json:"createLineChartSearchInsight"`
58+
}
59+
60+
ok, err := client.NewRequest(q.query, q.variables).Do(ctx, &result)
61+
if err != nil {
62+
return "", errors.Wrap(err, "createInsight failed")
63+
}
64+
if !ok {
65+
return "", errors.New("createInsight failed, no data to unmarshal")
66+
}
67+
68+
return result.CreateLineChartSearchInsight.View.ID, nil
69+
}
70+
71+
func removeInsight(ctx context.Context, client api.Client, insightId string) error {
72+
q := clientQuery{
73+
opName: "DeleteInsightView",
74+
query: `mutation DeleteInsightView ($id: ID!) {
75+
deleteInsightView(id: $id){
76+
alwaysNil
77+
}
78+
}`,
79+
variables: jsonVars{
80+
"id": insightId,
81+
},
82+
}
83+
84+
var result struct {
85+
Data struct {
86+
DeleteInsightView struct {
87+
AlwaysNil string `json:"alwaysNil"`
88+
} `json:"deleteInsightView"`
89+
} `json:"data"`
90+
}
91+
92+
ok, err := client.NewRequest(q.query, q.variables).Do(ctx, &result)
93+
if err != nil {
94+
return errors.Wrap(err, "removeInsight failed")
95+
}
96+
if !ok {
97+
return errors.New("removeInsight failed, no data to unmarshal")
98+
}
99+
100+
return nil
101+
}

0 commit comments

Comments
 (0)