Skip to content

Commit 5a641a5

Browse files
committed
Merge branch 'master' into solution.json-.exercism-dir
2 parents eaca5f3 + f81bc67 commit 5a641a5

11 files changed

Lines changed: 114 additions & 160 deletions

cmd/configure.go

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,14 +60,8 @@ func runConfigure(configuration config.Configuration, flags *pflag.FlagSet) erro
6060
// If the command is run 'bare' and we have no token,
6161
// explain how to set the token.
6262
if flags.NFlag() == 0 && cfg.GetString("token") == "" {
63-
baseURL := cfg.GetString("apibaseurl")
64-
if baseURL != "" {
65-
// If we have a base URL, then give the exact link.
66-
tokenURL := config.InferSiteURL(baseURL) + "/my/settings"
67-
return fmt.Errorf("There is no token configured. Find your token on %s, and call this command again with --token=<your-token>.", tokenURL)
68-
}
69-
// If we don't, then do our best.
70-
return fmt.Errorf("There is no token configured. Find your token in your settings on the website, and call this command again with --token=<your-token>.")
63+
tokenURL := config.SettingsURL(cfg.GetString("apibaseurl"))
64+
return fmt.Errorf("There is no token configured. Find your token on %s, and call this command again with --token=<your-token>.", tokenURL)
7165
}
7266

7367
// Determine the base API URL.
@@ -114,8 +108,7 @@ func runConfigure(configuration config.Configuration, flags *pflag.FlagSet) erro
114108
token = cfg.GetString("token")
115109
}
116110

117-
// Infer the URL where the token can be found.
118-
tokenURL := config.InferSiteURL(cfg.GetString("apibaseurl")) + "/my/settings"
111+
tokenURL := config.SettingsURL(cfg.GetString("apibaseurl"))
119112

120113
// If we don't have a token then explain how to set it and bail.
121114
if token == "" {

cmd/download.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ Download other people's solutions by providing the UUID.
4949
func runDownload(cfg config.Configuration, flags *pflag.FlagSet, args []string) error {
5050
usrCfg := cfg.UserViperConfig
5151
if usrCfg.GetString("token") == "" {
52-
tokenURL := config.InferSiteURL(usrCfg.GetString("apibaseurl")) + "/my/settings"
53-
return fmt.Errorf(msgWelcomePleaseConfigure, tokenURL, BinaryName)
52+
return fmt.Errorf(msgWelcomePleaseConfigure, config.SettingsURL(usrCfg.GetString("apibaseurl")), BinaryName)
5453
}
5554
if usrCfg.GetString("workspace") == "" || usrCfg.GetString("apibaseurl") == "" {
5655
return fmt.Errorf(msgRerunConfigure, BinaryName)

cmd/download_test.go

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package cmd
22

33
import (
4+
"bytes"
5+
"encoding/json"
46
"fmt"
57
"io/ioutil"
68
"net/http"
@@ -24,6 +26,8 @@ func TestDownloadWithoutToken(t *testing.T) {
2426
err := runDownload(cfg, pflag.NewFlagSet("fake", pflag.PanicOnError), []string{})
2527
if assert.Error(t, err) {
2628
assert.Regexp(t, "Welcome to Exercism", err.Error())
29+
// It uses the default base API url to infer the host
30+
assert.Regexp(t, "exercism.io/my/settings", err.Error())
2731
}
2832
}
2933

@@ -84,17 +88,30 @@ func TestDownload(t *testing.T) {
8488
}()
8589

8690
testCases := []struct {
87-
requestor string
88-
expectedDir string
89-
flag, flagValue string
91+
requestor string
92+
expectedDir string
93+
flags map[string]string
9094
}{
91-
{requestorSelf, "", "exercise", "bogus-exercise"},
92-
{requestorSelf, "", "uuid", "bogus-id"},
93-
{requestorOther, filepath.Join("users", "alice"), "uuid", "bogus-id"},
95+
{
96+
requestor: requestorSelf,
97+
expectedDir: "",
98+
flags: map[string]string{"exercise": "bogus-exercise"},
99+
},
100+
{
101+
requestor: requestorSelf,
102+
expectedDir: "",
103+
flags: map[string]string{"uuid": "bogus-id"},
104+
},
105+
{
106+
requestor: requestorOther,
107+
expectedDir: filepath.Join("users", "alice"),
108+
flags: map[string]string{"uuid": "bogus-id"},
109+
},
94110
}
95111

96112
for _, tc := range testCases {
97113
tmpDir, err := ioutil.TempDir("", "download-cmd")
114+
defer os.RemoveAll(tmpDir)
98115
assert.NoError(t, err)
99116

100117
ts := fakeDownloadServer(tc.requestor)
@@ -110,12 +127,32 @@ func TestDownload(t *testing.T) {
110127
}
111128
flags := pflag.NewFlagSet("fake", pflag.PanicOnError)
112129
setupDownloadFlags(flags)
113-
flags.Set(tc.flag, tc.flagValue)
130+
for name, value := range tc.flags {
131+
flags.Set(name, value)
132+
}
114133

115134
err = runDownload(cfg, flags, []string{})
116135
assert.NoError(t, err)
117136

118-
assertDownloadedCorrectFiles(t, filepath.Join(tmpDir, tc.expectedDir), tc.requestor)
137+
targetDir := filepath.Join(tmpDir, tc.expectedDir)
138+
assertDownloadedCorrectFiles(t, targetDir, tc.requestor)
139+
140+
metadata := `{
141+
"track": "bogus-track",
142+
"exercise":"bogus-exercise",
143+
"id":"bogus-id",
144+
"url":"",
145+
"handle":"alice",
146+
"is_requester":%s,
147+
"auto_approve":false
148+
}`
149+
metadata = fmt.Sprintf(metadata, tc.requestor)
150+
metadata = compact(t, metadata)
151+
152+
path := filepath.Join(targetDir, "bogus-track", "bogus-exercise", ws.SolutionMetadataFilepath())
153+
b, err := ioutil.ReadFile(path)
154+
assert.NoError(t, err)
155+
assert.Equal(t, metadata, string(b), "the solution metadata file")
119156
}
120157
}
121158

@@ -150,7 +187,6 @@ func fakeDownloadServer(requestor string) *httptest.Server {
150187
}
151188

152189
func assertDownloadedCorrectFiles(t *testing.T, targetDir, requestor string) {
153-
metadata := `{"track":"bogus-track","exercise":"bogus-exercise","id":"bogus-id","url":"","handle":"alice","is_requester":%s,"auto_approve":false}`
154190
expectedFiles := []struct {
155191
desc string
156192
path string
@@ -166,11 +202,6 @@ func assertDownloadedCorrectFiles(t *testing.T, targetDir, requestor string) {
166202
path: filepath.Join(targetDir, "bogus-track", "bogus-exercise", "subdir", "file-2.txt"),
167203
contents: "this is file 2",
168204
},
169-
{
170-
desc: "the solution metadata file",
171-
path: filepath.Join(targetDir, "bogus-track", "bogus-exercise", ws.SolutionMetadataFilepath()),
172-
contents: fmt.Sprintf(metadata, requestor),
173-
},
174205
}
175206

176207
for _, file := range expectedFiles {
@@ -218,3 +249,10 @@ const payloadTemplate = `
218249
}
219250
}
220251
`
252+
253+
func compact(t *testing.T, s string) string {
254+
buffer := new(bytes.Buffer)
255+
err := json.Compact(buffer, []byte(s))
256+
assert.NoError(t, err)
257+
return buffer.String()
258+
}

cmd/submit.go

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ func runSubmit(cfg config.Configuration, flags *pflag.FlagSet, args []string) er
5353
usrCfg := cfg.UserViperConfig
5454

5555
if usrCfg.GetString("token") == "" {
56-
tokenURL := config.InferSiteURL(usrCfg.GetString("apibaseurl")) + "/my/settings"
57-
return fmt.Errorf(msgWelcomePleaseConfigure, tokenURL, BinaryName)
56+
return fmt.Errorf(msgWelcomePleaseConfigure, config.SettingsURL(usrCfg.GetString("apibaseurl")), BinaryName)
5857
}
5958

6059
if usrCfg.GetString("workspace") == "" {
@@ -255,16 +254,6 @@ func runSubmit(cfg config.Configuration, flags *pflag.FlagSet, args []string) er
255254
return nil
256255
}
257256

258-
func initSubmitCmd() {
259-
setupSubmitFlags(submitCmd.Flags())
260-
}
261-
262-
func setupSubmitFlags(flags *pflag.FlagSet) {
263-
flags.StringP("track", "t", "", "the track ID")
264-
flags.StringP("exercise", "e", "", "the exercise ID")
265-
flags.StringSliceP("files", "f", make([]string, 0), "files to submit")
266-
}
267-
268257
func init() {
269258
RootCmd.AddCommand(submitCmd)
270259
}

cmd/submit_relative_path_test.go

Lines changed: 0 additions & 59 deletions
This file was deleted.

cmd/submit_relative_path_windows_test.go

Lines changed: 0 additions & 60 deletions
This file was deleted.

cmd/submit_test.go

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@ func TestSubmitWithoutToken(t *testing.T) {
2020
cfg := config.Configuration{
2121
Persister: config.InMemoryPersister{},
2222
UserViperConfig: viper.New(),
23-
DefaultBaseURL: "http://example.com",
2423
}
2524

2625
err := runSubmit(cfg, pflag.NewFlagSet("fake", pflag.PanicOnError), []string{})
2726
assert.Regexp(t, "Welcome to Exercism", err.Error())
27+
assert.Regexp(t, "exercism.io/my/settings", err.Error())
2828
}
2929

3030
func TestSubmitWithoutWorkspace(t *testing.T) {
@@ -368,6 +368,50 @@ func fakeSubmitServer(t *testing.T, submittedFiles map[string]string) *httptest.
368368
return httptest.NewServer(handler)
369369
}
370370

371+
func TestSubmitRelativePath(t *testing.T) {
372+
oldOut := Out
373+
oldErr := Err
374+
Out = ioutil.Discard
375+
Err = ioutil.Discard
376+
defer func() {
377+
Out = oldOut
378+
Err = oldErr
379+
}()
380+
// The fake endpoint will populate this when it receives the call from the command.
381+
submittedFiles := map[string]string{}
382+
ts := fakeSubmitServer(t, submittedFiles)
383+
defer ts.Close()
384+
385+
tmpDir, err := ioutil.TempDir("", "relative-path")
386+
assert.NoError(t, err)
387+
388+
dir := filepath.Join(tmpDir, "bogus-track", "bogus-exercise")
389+
os.MkdirAll(dir, os.FileMode(0755))
390+
391+
writeFakeSolution(t, dir, "bogus-track", "bogus-exercise")
392+
393+
v := viper.New()
394+
v.Set("token", "abc123")
395+
v.Set("workspace", tmpDir)
396+
v.Set("apibaseurl", ts.URL)
397+
398+
cfg := config.Configuration{
399+
Persister: config.InMemoryPersister{},
400+
UserViperConfig: v,
401+
}
402+
403+
err = ioutil.WriteFile(filepath.Join(dir, "file.txt"), []byte("This is a file."), os.FileMode(0755))
404+
405+
err = os.Chdir(dir)
406+
assert.NoError(t, err)
407+
408+
err = runSubmit(cfg, pflag.NewFlagSet("fake", pflag.PanicOnError), []string{"file.txt"})
409+
assert.NoError(t, err)
410+
411+
assert.Equal(t, 1, len(submittedFiles))
412+
assert.Equal(t, "This is a file.", submittedFiles[string(os.PathSeparator)+"file.txt"])
413+
}
414+
371415
func writeFakeSolution(t *testing.T, dir, trackID, exerciseSlug string) {
372416
solution := &workspace.Solution{
373417
ID: "bogus-solution-uuid",

config/config.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,17 @@ func ensureDir(f filer) error {
6969
// InferSiteURL guesses what the website URL is.
7070
// The basis for the guess is which API we're submitting to.
7171
func InferSiteURL(apiURL string) string {
72+
if apiURL == "" {
73+
apiURL = defaultBaseURL
74+
}
7275
if apiURL == "https://api.exercism.io/v1" {
7376
return "https://exercism.io"
7477
}
7578
re := regexp.MustCompile("^(https?://[^/]*).*")
7679
return re.ReplaceAllString(apiURL, "$1")
7780
}
81+
82+
// SettingsURL provides a link to where the user can find their API token.
83+
func SettingsURL(apiURL string) string {
84+
return fmt.Sprintf("%s%s", InferSiteURL(apiURL), "/my/settings")
85+
}

config/config_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ func TestInferSiteURL(t *testing.T) {
104104
{"https://v2.exercism.io/api/v1", "https://v2.exercism.io"},
105105
{"https://mentors-beta.exercism.io/api/v1", "https://mentors-beta.exercism.io"},
106106
{"http://localhost:3000/api/v1", "http://localhost:3000"},
107+
{"", "https://exercism.io"}, // use the default
107108
{"http://whatever", "http://whatever"}, // you're on your own, pal
108109
}
109110

0 commit comments

Comments
 (0)