Skip to content

feat: Private gomod repo support#80

Open
js-murph wants to merge 4 commits intomainfrom
johnm/gomod-private-attempt-three
Open

feat: Private gomod repo support#80
js-murph wants to merge 4 commits intomainfrom
johnm/gomod-private-attempt-three

Conversation

@js-murph
Copy link
Collaborator

@js-murph js-murph commented Feb 3, 2026

What?

Re-implements #77, which adds support for private gomod repositories.

Why?

So that we are able to cache private go modules.

Tests?

Includes new unit tests. Additionally some manual testing has been performed...

time curl http://localhost:8080/gomod/github.com/<org>/<repo>/@latest
{"Version":"v0.0.6","Time":"2021-08-12T18:29:12Z"}
real	1m43.818s
user	0m0.009s
sys	0m0.017s

time curl http://localhost:8080/gomod/github.com/<org>/<repo>/@latest
{"Version":"v0.0.6","Time":"2021-08-12T18:29:12Z"}
real	0m0.070s
user	0m0.006s
sys	0m0.011s

@js-murph js-murph requested a review from a team as a code owner February 3, 2026 08:45
@js-murph js-murph requested review from alecthomas and removed request for a team February 3, 2026 08:45
@js-murph js-murph marked this pull request as draft February 3, 2026 08:45
@js-murph js-murph marked this pull request as ready for review February 3, 2026 22:51
Copy link
Collaborator

@alecthomas alecthomas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall LGTM if it works! :)

Comment on lines +18 to +33
var (
sharedManager *Manager
sharedManagerMu sync.RWMutex
)

func SetShared(m *Manager) {
sharedManagerMu.Lock()
defer sharedManagerMu.Unlock()
sharedManager = m
}

func GetShared() *Manager {
sharedManagerMu.RLock()
defer sharedManagerMu.RUnlock()
return sharedManager
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't tell why this exists. We should be constructing a single Manager in main, then passing it everywhere, so AFAICT we shouldn't need this?

"github.com/goproxy/goproxy"
)

type compositeFetcher struct {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a comment here describing the purpose would be good - I think it's for routing between public/private repo's though?

fetcher = newCompositeFetcher(publicFetcher, privateFetcher, config.PrivatePaths)

s.logger.InfoContext(ctx, "Configured private module support",
slog.Any("private_paths", config.PrivatePaths))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
slog.Any("private_paths", config.PrivatePaths))
slog.Any("private-paths", config.PrivatePaths))

Comment on lines +8 to +23
type ModulePathMatcher struct {
patterns []string
}

func NewModulePathMatcher(patterns []string) *ModulePathMatcher {
return &ModulePathMatcher{patterns: patterns}
}

func (m *ModulePathMatcher) IsPrivate(modulePath string) bool {
for _, pattern := range m.patterns {
matched, err := path.Match(pattern, modulePath)
if err == nil && matched {
return true
}

if strings.HasPrefix(modulePath, pattern+"/") || modulePath == pattern {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This type doesn't seem like it needs to exist - it could just be a method on compositeFetcher

}

func (p *privateFetcher) Query(ctx context.Context, path, query string) (version string, t time.Time, err error) {
logger := p.gomod.logger.With(slog.String("module", path), slog.String("query", query))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be reaching into other objects private variables. Create a new logger for this object if necessary.

var output []byte
var err error

repo.WithReadLock(func() {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noice

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could also use generics here, so you can return values:

func WithRepoReadLock[R any](repo *Repository, apply func() (R, error)) (value R, err error) {
  repo.WithReadLock(func() { value, err = apply() })
  return
}

Usage:

output, err := gitclone.WithRepoReadLock(repo, func() ([]byte, error) {
		cmd := exec.CommandContext(ctx, "git", "-C", repo.Path(), "log", "-1", "--format=%cI", ref)
		return cmd.CombinedOutput()
})

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slightly clearer, but eh, your call

return nil, err
}

info := fmt.Sprintf(`{"Version":"%s","Time":"%s"}`, version, commitTime.Format(time.RFC3339))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this?

Generally I wouldn't construct JSON in a string, but maybe we know that version can't include any characters that will cause us difficulties?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants