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

mlange-42 / modo / 13168851212

06 Feb 2025 12:00AM CUT coverage: 72.707%. Remained the same
13168851212

push

github

web-flow
Add ease of setup to features (#209)

1649 of 2268 relevant lines covered (72.71%)

26.89 hits per line

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

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

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

11
        "github.com/mlange-42/modo/assets"
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
type GitInfo struct {
27
        Title    string
28
        Repo     string
29
        Pages    string
30
        GoModule string
31
        BasePath string
32
}
33

34
func getFenceType(line string) fenceType {
258✔
35
        isFence4 := strings.HasPrefix(line, codeFence4)
258✔
36
        if strings.HasPrefix(line, codeFence3) && !isFence4 {
300✔
37
                return fenceThree
42✔
38
        }
42✔
39
        if isFence4 {
220✔
40
                return fenceFour
4✔
41
        }
4✔
42
        return fenceNone
212✔
43
}
44

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

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

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

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

95
func fileExists(file string) (exists, isDir bool, err error) {
4✔
96
        var s os.FileInfo
4✔
97
        if s, err = os.Stat(file); err == nil {
5✔
98
                exists = true
1✔
99
                isDir = s.IsDir()
1✔
100
                return
1✔
101
        } else if !errors.Is(err, os.ErrNotExist) {
4✔
102
                return
×
103
        }
×
104
        err = nil
3✔
105
        return
3✔
106
}
107

108
func toFileName(name string) string {
261✔
109
        if caseSensitiveSystem {
372✔
110
                return name
111✔
111
        }
111✔
112
        if isCap(name) {
246✔
113
                return name + capitalFileMarker
96✔
114
        }
96✔
115
        return name
54✔
116
}
117

118
func findTemplates(dir string) ([]string, error) {
×
119
        allTemplates := []string{}
×
120
        err := filepath.WalkDir(dir,
×
121
                func(path string, info os.DirEntry, err error) error {
×
122
                        if err != nil {
×
123
                                return err
×
124
                        }
×
125
                        if !info.IsDir() {
×
126
                                allTemplates = append(allTemplates, path)
×
127
                        }
×
128
                        return nil
×
129
                })
130
        if err != nil {
×
131
                return nil, err
×
132
        }
×
133
        return allTemplates, nil
×
134
}
135

136
func GetCwdName() (string, error) {
1✔
137
        cwd, err := os.Getwd()
1✔
138
        if err != nil {
1✔
139
                return cwd, err
×
140
        }
×
141
        return filepath.Base(cwd), nil
1✔
142
}
143

144
func GetGitOrigin(outDir string) (*GitInfo, error) {
2✔
145
        gitFiles := []string{
2✔
146
                ".git/config",
2✔
147
                "../.git/config",
2✔
148
        }
2✔
149

2✔
150
        var content *ini.File
2✔
151
        found := false
2✔
152
        basePath := ""
2✔
153
        for _, f := range gitFiles {
6✔
154
                exists, isDir, err := fileExists(f)
4✔
155
                if err != nil {
4✔
156
                        return nil, err
×
157
                }
×
158
                if !exists || isDir {
7✔
159
                        continue
3✔
160
                }
161
                content, err = ini.Load(f)
1✔
162
                if err != nil {
1✔
163
                        return nil, err
×
164
                }
×
165

166
                if strings.HasPrefix(f, "..") {
2✔
167
                        basePath, err = GetCwdName()
1✔
168
                        if err != nil {
1✔
169
                                return nil, err
×
170
                        }
×
171
                }
172
                found = true
1✔
173
                break
1✔
174
        }
175

176
        url := "https://github.com/your/package"
2✔
177
        ok := false
2✔
178
        if found {
3✔
179
                section := content.Section(`remote "origin"`)
1✔
180
                if section != nil {
2✔
181
                        value := section.Key("url")
1✔
182
                        if value != nil {
2✔
183
                                url = strings.TrimSuffix(value.String(), ".git")
1✔
184
                                ok = true
1✔
185
                        }
1✔
186
                }
187
        }
188
        if !ok {
3✔
189
                fmt.Printf("WARNING: No Git repository or no remote 'origin' found.\n         Using dummy %s\n", url)
1✔
190
        }
1✔
191
        title, pages := repoToTitleAndPages(url)
2✔
192
        module := strings.ReplaceAll(strings.ReplaceAll(url, "https://", ""), "http://", "")
2✔
193
        module = fmt.Sprintf("%s/%s", module, outDir)
2✔
194

2✔
195
        return &GitInfo{
2✔
196
                Title:    title,
2✔
197
                Repo:     url,
2✔
198
                Pages:    pages,
2✔
199
                GoModule: module,
2✔
200
                BasePath: basePath,
2✔
201
        }, nil
2✔
202
}
203

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

7✔
214
        var title, user, pages string
7✔
215
        switch len(parts) {
7✔
216
        case 1:
1✔
217
                title = "unknown"
1✔
218
                pages = fmt.Sprintf("%s//%s.io/", protocolAddress[0], domain)
1✔
219
        case 2:
1✔
220
                title = parts[1]
1✔
221
                pages = fmt.Sprintf("%s//%s.io/%s/", protocolAddress[0], domain, title)
1✔
222
        default:
5✔
223
                user = parts[1]
5✔
224
                title = parts[2]
5✔
225
                pages = fmt.Sprintf("%s//%s.%s.io/%s/", protocolAddress[0], user, domain, title)
5✔
226
        }
227
        return title, pages
7✔
228
}
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