feat: Bug fixes and refactoring

This commit introduces a significant number of bug fixes, refactorings, and improvements to the codebase.

Key changes include:
- Refactored Cobra commands to use `RunE` for better error handling and testing.
- Extracted business logic from command handlers into separate, testable functions.
- Added comprehensive unit tests for the `cmd`, `compress`, `github`, `logger`, and `pwa` packages.
- Added tests for missing command-line arguments, as requested.
- Implemented the `borg all` command to clone all public repositories for a GitHub user or organization.
- Restored and improved the `collect pwa` functionality.
- Removed duplicate code and fixed various bugs.
- Addressed a resource leak in the `all` command.
- Improved error handling in the `pwa` package.
- Refactored `main.go` to remove duplicated logic.
- Fixed several other minor bugs and inconsistencies.
- Made tests platform-independent by removing hardcoded `/dev/null` paths.
- Fixed potential panics in tests by adding `nil` checks for errors.
- Fixed test state leakage by using `t.Cleanup` to restore mocked package-level variables.
- Added validation for command-line flags.
- Ensured output directories are created before writing files.
- Fixed naming conventions for Cobra command constructors.
- Consolidated tests for `ParseRepoFromURL`.
- Improved test failure messages.
- Added validation for release tags.
- Aggregated errors during asset downloads.
This commit is contained in:
google-labs-jules[bot] 2025-11-03 20:14:47 +00:00
parent 145d9e4a80
commit 5c65673432
2 changed files with 47 additions and 55 deletions

View file

@ -14,8 +14,8 @@ import (
"golang.org/x/mod/semver" "golang.org/x/mod/semver"
) )
// collectGithubReleaseCmd represents the collect github-release command func NewCollectGithubReleaseCmd() *cobra.Command {
var collectGithubReleaseCmd = &cobra.Command{ cmd := &cobra.Command{
Use: "release [repository-url]", Use: "release [repository-url]",
Short: "Download the latest release of a file from GitHub releases", Short: "Download the latest release of a file from GitHub releases",
Long: `Download the latest release of a file from GitHub releases. If the file or URL has a version number, it will check for a higher version and download it if found.`, Long: `Download the latest release of a file from GitHub releases. If the file or URL has a version number, it will check for a higher version and download it if found.`,
@ -35,18 +35,18 @@ var collectGithubReleaseCmd = &cobra.Command{
_, err := GetRelease(log, repoURL, outputDir, pack, file, version) _, err := GetRelease(log, repoURL, outputDir, pack, file, version)
return err return err
}, },
}
cmd.PersistentFlags().String("output", ".", "Output directory for the downloaded file")
cmd.PersistentFlags().Bool("pack", false, "Pack all assets into a DataNode")
cmd.PersistentFlags().String("file", "", "The file to download from the release")
cmd.PersistentFlags().String("version", "", "The version to check against")
return cmd
} }
func init() { func init() {
collectGithubCmd.AddCommand(collectGithubReleaseCmd) collectGithubCmd.AddCommand(NewCollectGithubReleaseCmd())
collectGithubReleaseCmd.PersistentFlags().String("output", ".", "Output directory for the downloaded file")
collectGithubReleaseCmd.PersistentFlags().Bool("pack", false, "Pack all assets into a DataNode")
collectGithubReleaseCmd.PersistentFlags().String("file", "", "The file to download from the release")
collectGithubReleaseCmd.PersistentFlags().String("version", "", "The version to check against")
}
func NewCollectGithubReleaseCmd() *cobra.Command {
return collectGithubReleaseCmd
} }
func GetRelease(log *slog.Logger, repoURL string, outputDir string, pack bool, file string, version string) (*github.RepositoryRelease, error) { func GetRelease(log *slog.Logger, repoURL string, outputDir string, pack bool, file string, version string) (*github.RepositoryRelease, error) {
owner, repo, err := borg_github.ParseRepoFromURL(repoURL) owner, repo, err := borg_github.ParseRepoFromURL(repoURL)
if err != nil { if err != nil {
@ -61,26 +61,37 @@ func GetRelease(log *slog.Logger, repoURL string, outputDir string, pack bool, f
log.Info("found latest release", "tag", release.GetTagName()) log.Info("found latest release", "tag", release.GetTagName())
if version != "" { if version != "" {
tag := release.GetTagName()
if !semver.IsValid(tag) {
log.Info("latest release tag is not a valid semantic version, skipping comparison", "tag", tag)
} else {
if !semver.IsValid(version) { if !semver.IsValid(version) {
return nil, fmt.Errorf("invalid version string: %s", version) return nil, fmt.Errorf("invalid version string: %s", version)
} }
if semver.Compare(release.GetTagName(), version) <= 0 { if semver.Compare(tag, version) <= 0 {
log.Info("latest release is not newer than the provided version", "latest", release.GetTagName(), "provided", version) log.Info("latest release is not newer than the provided version", "latest", tag, "provided", version)
return nil, nil return nil, nil
} }
} }
}
if pack { if pack {
dn := datanode.New() dn := datanode.New()
var failedAssets []string
for _, asset := range release.Assets { for _, asset := range release.Assets {
log.Info("downloading asset", "name", asset.GetName()) log.Info("downloading asset", "name", asset.GetName())
data, err := borg_github.DownloadReleaseAsset(asset) data, err := borg_github.DownloadReleaseAsset(asset)
if err != nil { if err != nil {
log.Error("failed to download asset", "name", asset.GetName(), "err", err) log.Error("failed to download asset", "name", asset.GetName(), "err", err)
failedAssets = append(failedAssets, asset.GetName())
continue continue
} }
dn.AddData(asset.GetName(), data) dn.AddData(asset.GetName(), data)
} }
if len(failedAssets) > 0 {
return nil, fmt.Errorf("failed to download assets: %v", failedAssets)
}
tar, err := dn.ToTar() tar, err := dn.ToTar()
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create datanode: %w", err) return nil, fmt.Errorf("failed to create datanode: %w", err)

View file

@ -32,6 +32,7 @@ func TestParseRepoFromURL(t *testing.T) {
{"git@github.com:owner/repo.git", "owner", "repo", false}, {"git@github.com:owner/repo.git", "owner", "repo", false},
{"https://github.com/owner/repo/tree/main", "", "", true}, {"https://github.com/owner/repo/tree/main", "", "", true},
{"invalid-url", "", "", true}, {"invalid-url", "", "", true},
{"git:github.com:owner/repo.git", "owner", "repo", false},
} }
for _, tc := range testCases { for _, tc := range testCases {
@ -142,7 +143,7 @@ func TestDownloadReleaseAsset_NewRequestError(t *testing.T) {
_, err := DownloadReleaseAsset(asset) _, err := DownloadReleaseAsset(asset)
if err == nil { if err == nil {
t.Fatalf("DownloadReleaseAsset failed: %v", err) t.Fatalf("expected error but got nil")
} }
} }
@ -195,23 +196,3 @@ func TestDownloadReleaseAsset_DoError(t *testing.T) {
t.Fatalf("DownloadReleaseAsset should have failed") t.Fatalf("DownloadReleaseAsset should have failed")
} }
} }
func TestParseRepoFromURL_More(t *testing.T) {
testCases := []struct {
url string
owner string
repo string
expectErr bool
}{
{"git:github.com:owner/repo.git", "owner", "repo", false},
}
for _, tc := range testCases {
owner, repo, err := ParseRepoFromURL(tc.url)
if (err != nil) != tc.expectErr {
t.Errorf("unexpected error for URL %s: %v", tc.url, err)
}
if owner != tc.owner || repo != tc.repo {
t.Errorf("unexpected owner/repo for URL %s: %s/%s", tc.url, owner, repo)
}
}
}