• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mlange-42 / modo / 13240312600

10 Feb 2025 11:59AM CUT coverage: 74.164% (-0.04%) from 74.2%
13240312600

Pull #221

github

web-flow
Merge 196b78158 into c08a38311
Pull Request #221: Support SSL remote repositories

11 of 16 new or added lines in 1 file covered. (68.75%)

2374 of 3201 relevant lines covered (74.16%)

48.19 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.61
/internal/document/util.go
1
package document
2

3
import (
4
        "fmt"
5
        "os"
6
        "path/filepath"
7
        "strings"
8
        "text/template"
9

10
        "github.com/mlange-42/modo/assets"
11
        "github.com/mlange-42/modo/internal/util"
12
        "gopkg.in/ini.v1"
13
)
14

15
const codeFence3 = "```"
16
const codeFence4 = "````"
17

18
type fenceType uint8
19

20
const (
21
        fenceNone fenceType = iota
22
        fenceThree
23
        fenceFour
24
)
25

26
// GitInfo contains information about a Git repository.
27
type GitInfo struct {
28
        Title    string
29
        Repo     string
30
        Pages    string
31
        GoModule string
32
        BasePath string
33
}
34

35
func getFenceType(line string) fenceType {
710✔
36
        isFence4 := strings.HasPrefix(line, codeFence4)
710✔
37
        if strings.HasPrefix(line, codeFence3) && !isFence4 {
824✔
38
                return fenceThree
114✔
39
        }
114✔
40
        if isFence4 {
600✔
41
                return fenceFour
4✔
42
        }
4✔
43
        return fenceNone
592✔
44
}
45

46
// appends to a slice, but guaranties to return a new one and not alter the original.
47
func appendNew[T any](sl []T, elems ...T) []T {
1,528✔
48
        sl2 := make([]T, len(sl), len(sl)+len(elems))
1,528✔
49
        copy(sl2, sl)
1,528✔
50
        sl2 = append(sl2, elems...)
1,528✔
51
        return sl2
1,528✔
52
}
1,528✔
53

54
func warnOrError(strict bool, pattern string, args ...any) error {
2✔
55
        if strict {
3✔
56
                return fmt.Errorf(pattern, args...)
1✔
57
        }
1✔
58
        fmt.Printf("WARNING: "+pattern+"\n", args...)
1✔
59
        return nil
1✔
60
}
61

62
// LoadTemplates loads all templates from the assets and additional directories.
63
func LoadTemplates(f Formatter, sourceURL string, additional ...string) (*template.Template, error) {
21✔
64
        templ := template.New("all")
21✔
65
        templ = templ.Funcs(template.FuncMap{
21✔
66
                "toLink":    f.ToLinkPath,
21✔
67
                "sourceUrl": func() string { return sourceURL },
119✔
68
        })
69
        templ, err := templ.ParseFS(assets.Templates, "templates/*.*", "templates/**/*.*")
21✔
70
        if err != nil {
21✔
71
                return nil, err
×
72
        }
×
73

74
        for _, dir := range additional {
22✔
75
                if dir == "" {
1✔
76
                        continue
×
77
                }
78
                exists, isDir, err := util.FileExists(dir)
1✔
79
                if err != nil {
1✔
80
                        return nil, err
×
81
                }
×
82
                if !exists || !isDir {
1✔
83
                        return nil, fmt.Errorf("template directory '%s' does not exist", dir)
×
84
                }
×
85
                moreTemplates, err := findTemplates(dir)
1✔
86
                if err != nil {
1✔
87
                        return nil, err
×
88
                }
×
89
                templ, err = templ.ParseFiles(moreTemplates...)
1✔
90
                if err != nil {
1✔
91
                        return nil, err
×
92
                }
×
93
        }
94
        return templ, nil
21✔
95
}
96

97
func toFileName(name string) string {
510✔
98
        if caseSensitiveSystem {
621✔
99
                return name
111✔
100
        }
111✔
101
        if isCap(name) {
650✔
102
                return name + capitalFileMarker
251✔
103
        }
251✔
104
        return name
148✔
105
}
106

107
func findTemplates(dir string) ([]string, error) {
1✔
108
        allTemplates := []string{}
1✔
109
        err := filepath.WalkDir(dir,
1✔
110
                func(path string, info os.DirEntry, err error) error {
6✔
111
                        if err != nil {
5✔
112
                                return err
×
113
                        }
×
114
                        if !info.IsDir() {
9✔
115
                                allTemplates = append(allTemplates, path)
4✔
116
                        }
4✔
117
                        return nil
5✔
118
                })
119
        if err != nil {
1✔
120
                return nil, err
×
121
        }
×
122
        return allTemplates, nil
1✔
123
}
124

125
// GetGitOrigin tries to determine the `origin` remote repository.
126
func GetGitOrigin(outDir string) (*GitInfo, error) {
10✔
127
        gitFiles := []string{
10✔
128
                ".git/config",
10✔
129
                "../.git/config",
10✔
130
        }
10✔
131

10✔
132
        var content *ini.File
10✔
133
        found := false
10✔
134
        basePath := ""
10✔
135
        for _, f := range gitFiles {
30✔
136
                exists, isDir, err := util.FileExists(f)
20✔
137
                if err != nil {
20✔
138
                        return nil, err
×
139
                }
×
140
                if !exists || isDir {
39✔
141
                        continue
19✔
142
                }
143
                content, err = ini.Load(f)
1✔
144
                if err != nil {
1✔
145
                        return nil, err
×
146
                }
×
147

148
                if strings.HasPrefix(f, "..") {
2✔
149
                        basePath, err = util.GetCwdName()
1✔
150
                        if err != nil {
1✔
151
                                return nil, err
×
152
                        }
×
153
                }
154
                found = true
1✔
155
                break
1✔
156
        }
157

158
        url := "https://github.com/your/package"
10✔
159
        ok := false
10✔
160
        if found {
11✔
161
                section := content.Section(`remote "origin"`)
1✔
162
                if section != nil {
2✔
163
                        value := section.Key("url")
1✔
164
                        if value != nil {
2✔
165
                                url = value.String()
1✔
166
                                ok = true
1✔
167
                        }
1✔
168
                }
169
        }
170
        if !ok {
19✔
171
                fmt.Printf("WARNING: No Git repository or no remote 'origin' found.\n         Using dummy %s\n", url)
9✔
172
        }
9✔
173
        url, err := getRepoUrl(url)
10✔
174
        if err != nil {
10✔
NEW
175
                url = "https://github.com/your/package"
×
NEW
176
                fmt.Printf("WARNING: Git remote 'origin' could not be parsed.\n         Using dummy %s\n", url)
×
NEW
177
        }
×
178
        title, pages := repoToTitleAndPages(url)
10✔
179
        module := strings.ReplaceAll(strings.ReplaceAll(url, "https://", ""), "http://", "")
10✔
180
        module = fmt.Sprintf("%s/%s", module, outDir)
10✔
181

10✔
182
        return &GitInfo{
10✔
183
                Title:    title,
10✔
184
                Repo:     url,
10✔
185
                Pages:    pages,
10✔
186
                GoModule: module,
10✔
187
                BasePath: basePath,
10✔
188
        }, nil
10✔
189
}
190

191
func getRepoUrl(url string) (string, error) {
12✔
192
        if strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "https://") {
23✔
193
                return strings.TrimSuffix(url, ".git"), nil
11✔
194
        }
11✔
195
        if !strings.HasPrefix(url, "git@") {
1✔
NEW
196
                return "", fmt.Errorf("git remote 'origin' could not be parsed")
×
NEW
197
        }
×
198
        url = strings.TrimPrefix(url, "git@")
1✔
199
        domainRepo := strings.SplitN(url, ":", 2)
1✔
200
        return fmt.Sprintf("https://%s/%s", domainRepo[0], domainRepo[1]), nil
1✔
201
}
202

203
func repoToTitleAndPages(repo string) (string, string) {
15✔
204
        repo = strings.TrimSuffix(repo, "/")
15✔
205
        protocolAddress := strings.Split(repo, "//")
15✔
206
        if len(protocolAddress) < 2 {
15✔
207
                return "unknown", "https://example.com"
×
208
        }
×
209
        parts := strings.Split(protocolAddress[1], "/")
15✔
210
        domainParts := strings.Split(parts[0], ".")
15✔
211
        domain := strings.Join(domainParts[:len(domainParts)-1], ".")
15✔
212

15✔
213
        var title, user, pages string
15✔
214
        switch len(parts) {
15✔
215
        case 1:
1✔
216
                title = "unknown"
1✔
217
                pages = fmt.Sprintf("%s//%s.io/", protocolAddress[0], domain)
1✔
218
        case 2:
1✔
219
                title = parts[1]
1✔
220
                pages = fmt.Sprintf("%s//%s.io/%s/", protocolAddress[0], domain, title)
1✔
221
        default:
13✔
222
                user = parts[1]
13✔
223
                title = parts[2]
13✔
224
                pages = fmt.Sprintf("%s//%s.%s.io/%s/", protocolAddress[0], user, domain, title)
13✔
225
        }
226
        return title, pages
15✔
227
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc