Resolve convert-sha256 positionals against unset fields · Entire
Resolve convert-sha256 positionals against unset fields
4562077→main·
nodo·1mo ago·2 files·+107 added/-8 removed
The previous code assigned args[0] to SourceURL and args[1] to TargetDir unconditionally, so --source-url <url> <dir> left TargetDir empty (len(args) == 1, so args[1] was never read) and failed the "requires a source URL and a target directory" check.
Consume positionals left-to-right against fields the user has not yet supplied via flags. The four flag/positional shapes (zero/one/two flags) now all yield the correct assignment. Extracted into resolveConvertSHA256Args for a unit test that covers every shape including the regression case.
Sessions
Transcript data is unavailable for this checkpoint.
Changes
2
cmd/git-sync
Mconvert_sha256.go+23/-8
Aconvert_sha256_test.go+84
41 unmodified lines
42
43
44
45
46
47
48
49
50
51
52
45
46
47
48
49
44 unmodified lines
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
41 unmodified lines
SilenceUsage: true,
RunE: func(cmd *cobra.Command, args []string) error {
req.ProtocolMode = gitsync.ProtocolMode(protocolVal)
if req.SourceURL == "" && len(args) > 0 {
req.SourceURL = args[0]
}
if req.TargetDir == "" && len(args) > 1 {
req.TargetDir = args[1]
}
if req.SourceURL == "" || req.TargetDir == "" {
return errors.New("convert-sha256 requires a source URL and a target directory")
}
if err := resolveConvertSHA256Args(&req, args); err != nil {
return err
}
result, err := sha256convert.Run(cmd.Context(), req)
41 unmodified lines
return cmd
}
// resolveConvertSHA256Args consumes positional args left-to-right,
// skipping fields the user already supplied via flags. Without that
// rule, `--source-url <url> <dir>` would look like one positional and
// land in SourceURL — leaving TargetDir empty even though the user
// gave both. The two-flags-no-positionals and zero-flags-two-positionals
// shapes also work, as do the symmetric --target-dir + positional URL.
func resolveConvertSHA256Args(req *sha256convert.Request, args []string) error {
positional := args
if req.SourceURL == "" && len(positional) > 0 {
req.SourceURL = positional[0]
positional = positional[1:]
}
if req.TargetDir == "" && len(positional) > 0 {
req.TargetDir = positional[0]
}
if req.SourceURL == "" || req.TargetDir == "" {
return errors.New("convert-sha256 requires a source URL and a target directory")
}
return nil
}
Mcmd/git-sync/convert_sha256.go+23/-8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package main
import (
"strings"
"testing"
"entire.io/entire/git-sync/cmd/git-sync/internal/sha256convert"
)
func TestResolveConvertSHA256Args(t *testing.T) {
const url = "http://example.invalid/repo.git"
const dir = "/tmp/out"
tests := []struct {
name string
req sha256convert.Request
args []string
wantURL string
wantDir string
wantErr string
}{
{
name: "both positionals",
args: []string{url, dir},
wantURL: url,
wantDir: dir,
},
{
name: "url flag plus positional dir — the reported bug",
req: sha256convert.Request{SourceURL: url},
args: []string{dir},
wantURL: url,
wantDir: dir,
},
{
name: "dir flag plus positional url",
req: sha256convert.Request{TargetDir: dir},
args: []string{url},
wantURL: url,
wantDir: dir,
},
{
name: "both flags, no positionals",
req: sha256convert.Request{SourceURL: url, TargetDir: dir},
args: nil,
wantURL: url,
wantDir: dir,
},
{
name: "missing dir",
req: sha256convert.Request{SourceURL: url},
args: nil,
wantErr: "requires a source URL and a target directory",
},
{
name: "missing both",
args: nil,
wantErr: "requires a source URL and a target directory",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := tt.req
err := resolveConvertSHA256Args(&req, tt.args)
switch {
case tt.wantErr == "" && err != nil:
t.Fatalf("unexpected error: %v", err)
case tt.wantErr != "" && err == nil:
t.Fatalf("expected error containing %q, got nil", tt.wantErr)
case tt.wantErr != "" && !strings.Contains(err.Error(), tt.wantErr):
t.Fatalf("error %q does not contain %q", err.Error(), tt.wantErr)
}
if tt.wantErr != "" {
return
}
if req.SourceURL != tt.wantURL {
t.Errorf("SourceURL: got %q, want %q", req.SourceURL, tt.wantURL)
}
if req.TargetDir != tt.wantDir {
t.Errorf("TargetDir: got %q, want %q", req.TargetDir, tt.wantDir)
}
}
}
}
Acmd/git-sync/convert_sha256_test.go+84