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:
parent
145d9e4a80
commit
5c65673432
2 changed files with 47 additions and 55 deletions
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue