Merge pull request #4 from Snider/feature-github-release-downloader
feat: Add ability to download from GitHub releases
This commit is contained in:
commit
c96f8cfcfa
11 changed files with 388 additions and 8 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
borg
|
||||
*.cube
|
||||
.idea
|
||||
58
cmd/all.go
Normal file
58
cmd/all.go
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/Snider/Borg/pkg/github"
|
||||
"github.com/Snider/Borg/pkg/vcs"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// allCmd represents the all command
|
||||
var allCmd = &cobra.Command{
|
||||
Use: "all [user/org]",
|
||||
Short: "Collect all public repositories from a user or organization",
|
||||
Long: `Collect all public repositories from a user or organization and store them in a DataNode.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
repos, err := github.GetPublicRepos(args[0])
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
outputDir, _ := cmd.Flags().GetString("output")
|
||||
|
||||
for _, repoURL := range repos {
|
||||
fmt.Printf("Cloning %s...\n", repoURL)
|
||||
|
||||
dn, err := vcs.CloneGitRepository(repoURL)
|
||||
if err != nil {
|
||||
fmt.Printf("Error cloning %s: %s\n", repoURL, err)
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := dn.ToTar()
|
||||
if err != nil {
|
||||
fmt.Printf("Error serializing DataNode for %s: %v\n", repoURL, err)
|
||||
continue
|
||||
}
|
||||
|
||||
repoName := strings.Split(repoURL, "/")[len(strings.Split(repoURL, "/"))-1]
|
||||
outputFile := fmt.Sprintf("%s/%s.dat", outputDir, repoName)
|
||||
err = os.WriteFile(outputFile, data, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("Error writing DataNode for %s to file: %v\n", repoURL, err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(allCmd)
|
||||
allCmd.PersistentFlags().String("output", ".", "Output directory for the DataNodes")
|
||||
}
|
||||
16
cmd/collect_github.go
Normal file
16
cmd/collect_github.go
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// collectGithubCmd represents the collect github command
|
||||
var collectGithubCmd = &cobra.Command{
|
||||
Use: "github",
|
||||
Short: "Collect a resource from GitHub.",
|
||||
Long: `Collect a resource from a GitHub repository, such as a repository or a release.`,
|
||||
}
|
||||
|
||||
func init() {
|
||||
collectCmd.AddCommand(collectGithubCmd)
|
||||
}
|
||||
128
cmd/collect_github_release_subcommand.go
Normal file
128
cmd/collect_github_release_subcommand.go
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Snider/Borg/pkg/datanode"
|
||||
borg_github "github.com/Snider/Borg/pkg/github"
|
||||
gh "github.com/google/go-github/v39/github"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/mod/semver"
|
||||
)
|
||||
|
||||
// collectGithubReleaseCmd represents the collect github-release command
|
||||
var collectGithubReleaseCmd = &cobra.Command{
|
||||
Use: "release [repository-url]",
|
||||
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.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
repoURL := args[0]
|
||||
outputDir, _ := cmd.Flags().GetString("output")
|
||||
pack, _ := cmd.Flags().GetBool("pack")
|
||||
file, _ := cmd.Flags().GetString("file")
|
||||
version, _ := cmd.Flags().GetString("version")
|
||||
|
||||
owner, repo, err := borg_github.ParseRepoFromURL(repoURL)
|
||||
if err != nil {
|
||||
fmt.Printf("Error parsing repository URL: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
release, err := borg_github.GetLatestRelease(owner, repo)
|
||||
if err != nil {
|
||||
fmt.Printf("Error getting latest release: %v\n", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Found latest release: %s\n", release.GetTagName())
|
||||
|
||||
if version != "" {
|
||||
if !semver.IsValid(version) {
|
||||
fmt.Printf("Invalid version string: %s\n", version)
|
||||
return
|
||||
}
|
||||
if semver.Compare(release.GetTagName(), version) <= 0 {
|
||||
fmt.Printf("Latest release (%s) is not newer than the provided version (%s).\n", release.GetTagName(), version)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if pack {
|
||||
dn := datanode.New()
|
||||
for _, asset := range release.Assets {
|
||||
fmt.Printf("Downloading asset: %s\n", asset.GetName())
|
||||
resp, err := http.Get(asset.GetBrowserDownloadURL())
|
||||
if err != nil {
|
||||
fmt.Printf("Error downloading asset: %v\n", err)
|
||||
continue
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
var buf bytes.Buffer
|
||||
_, err = io.Copy(&buf, resp.Body)
|
||||
if err != nil {
|
||||
fmt.Printf("Error reading asset: %v\n", err)
|
||||
continue
|
||||
}
|
||||
dn.AddData(asset.GetName(), buf.Bytes())
|
||||
}
|
||||
tar, err := dn.ToTar()
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating DataNode: %v\n", err)
|
||||
return
|
||||
}
|
||||
outputFile := outputDir
|
||||
if !strings.HasSuffix(outputFile, ".dat") {
|
||||
outputFile = outputFile + ".dat"
|
||||
}
|
||||
err = os.WriteFile(outputFile, tar, 0644)
|
||||
if err != nil {
|
||||
fmt.Printf("Error writing DataNode: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("DataNode saved to %s\n", outputFile)
|
||||
} else {
|
||||
if len(release.Assets) == 0 {
|
||||
fmt.Println("No assets found in the latest release.")
|
||||
return
|
||||
}
|
||||
var assetToDownload *gh.ReleaseAsset
|
||||
if file != "" {
|
||||
for _, asset := range release.Assets {
|
||||
if asset.GetName() == file {
|
||||
assetToDownload = asset
|
||||
break
|
||||
}
|
||||
}
|
||||
if assetToDownload == nil {
|
||||
fmt.Printf("Asset '%s' not found in the latest release.\n", file)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
assetToDownload = release.Assets[0]
|
||||
}
|
||||
outputPath := filepath.Join(outputDir, assetToDownload.GetName())
|
||||
fmt.Printf("Downloading asset: %s\n", assetToDownload.GetName())
|
||||
err = borg_github.DownloadReleaseAsset(assetToDownload, outputPath)
|
||||
if err != nil {
|
||||
fmt.Printf("Error downloading asset: %v\n", err)
|
||||
return
|
||||
}
|
||||
fmt.Printf("Asset downloaded to %s\n", outputPath)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
collectGithubCmd.AddCommand(collectGithubReleaseCmd)
|
||||
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")
|
||||
}
|
||||
|
|
@ -6,11 +6,19 @@ import (
|
|||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/Snider/Borg/pkg/vcs"
|
||||
|
||||
"github.com/Snider/Borg/pkg/github"
|
||||
"github.com/Snider/Borg/pkg/vcs"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// collectGithubRepoCmd represents the collect github repo command
|
||||
var collectGithubRepoCmd = &cobra.Command{
|
||||
Use: "repo [repository-url]",
|
||||
Short: "Collect a single Git repository",
|
||||
Long: `Collect a single Git repository and store it in a DataNode.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
// collectGitCmd represents the collect git command
|
||||
var collectGitCmd = &cobra.Command{
|
||||
Use: "git",
|
||||
|
|
@ -93,8 +101,8 @@ var collectGitCmd = &cobra.Command{
|
|||
}
|
||||
|
||||
func init() {
|
||||
collectCmd.AddCommand(collectGitCmd)
|
||||
collectGitCmd.Flags().String("uri", "", "URL of the Git repository to collect")
|
||||
collectGithubCmd.AddCommand(collectGithubRepoCmd)
|
||||
collectGithubRepoCmd.Flags().String("uri", "", "URL of the Git repository to collect")
|
||||
collectGitCmd.Flags().String("user", "", "GitHub user or organization to collect all repositories from")
|
||||
collectGitCmd.Flags().String("output", "repo.dat", "Output file (for --uri) or directory (for --user)")
|
||||
}
|
||||
|
|
@ -11,14 +11,21 @@ import (
|
|||
|
||||
// collectPWACmd represents the collect pwa command
|
||||
var collectPWACmd = &cobra.Command{
|
||||
Use: "pwa [url]",
|
||||
Short: "Collect a single PWA",
|
||||
Long: `Collect a single PWA and store it in a DataNode.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Use: "pwa",
|
||||
Short: "Collect a single PWA using a URI",
|
||||
Long: `Collect a single PWA and store it in a DataNode.
|
||||
|
||||
Example:
|
||||
borg collect pwa --uri https://example.com --output mypwa.dat`,
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
pwaURL := args[0]
|
||||
pwaURL, _ := cmd.Flags().GetString("uri")
|
||||
outputFile, _ := cmd.Flags().GetString("output")
|
||||
|
||||
if pwaURL == "" {
|
||||
fmt.Println("Error: uri is required")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Finding PWA manifest...")
|
||||
manifestURL, err := pwa.FindManifest(pwaURL)
|
||||
if err != nil {
|
||||
|
|
@ -52,5 +59,6 @@ var collectPWACmd = &cobra.Command{
|
|||
|
||||
func init() {
|
||||
collectCmd.AddCommand(collectPWACmd)
|
||||
collectPWACmd.PersistentFlags().String("output", "pwa.dat", "Output file for the DataNode")
|
||||
collectPWACmd.Flags().String("uri", "", "The URI of the PWA to collect")
|
||||
collectPWACmd.Flags().String("output", "pwa.dat", "Output file for the DataNode")
|
||||
}
|
||||
|
|
|
|||
3
go.mod
3
go.mod
|
|
@ -4,8 +4,10 @@ go 1.24.3
|
|||
|
||||
require (
|
||||
github.com/go-git/go-git/v5 v5.16.3
|
||||
github.com/google/go-github/v39 v39.2.0
|
||||
github.com/schollz/progressbar/v3 v3.18.0
|
||||
github.com/spf13/cobra v1.10.1
|
||||
golang.org/x/mod v0.12.0
|
||||
golang.org/x/net v0.46.0
|
||||
)
|
||||
|
||||
|
|
@ -19,6 +21,7 @@ require (
|
|||
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
|
||||
github.com/go-git/go-billy/v5 v5.6.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect
|
||||
github.com/google/go-querystring v1.1.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/kevinburke/ssh_config v1.2.0 // indirect
|
||||
|
|
|
|||
21
go.sum
21
go.sum
|
|
@ -35,8 +35,16 @@ github.com/go-git/go-git/v5 v5.16.3 h1:Z8BtvxZ09bYm/yYNgPKCzgWtaRqDTgIKRgIRHBfU6
|
|||
github.com/go-git/go-git/v5 v5.16.3/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ=
|
||||
github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ=
|
||||
github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
|
||||
|
|
@ -86,14 +94,22 @@ github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOf
|
|||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
|
||||
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04=
|
||||
golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
|
||||
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4=
|
||||
golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
|
@ -105,10 +121,15 @@ golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
|||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q=
|
||||
golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k=
|
||||
golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
|
|
|
|||
43
go.work.sum
Normal file
43
go.work.sum
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
github.com/bwesterb/go-ristretto v1.2.3 h1:1w53tCkGhCQ5djbat3+MH0BAQ5Kfgbt56UZQ/JMzngw=
|
||||
github.com/bwesterb/go-ristretto v1.2.3/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-github/v39 v39.2.0 h1:rNNM311XtPOz5rDdsJXAp2o8F67X9FnROXTvto3aSnQ=
|
||||
github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
|
||||
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
|
||||
github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 h1:qGQQKEcAR99REcMpsXCp3lJ03zYT1PkRd3kQGPn9GVg=
|
||||
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
|
||||
github.com/kr/pty v1.1.1 h1:VkoXIwSboBpnk99O/KFauAEILuNHv5DVFKZMBN/gUgw=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be h1:vEDujvNQGv4jgYKudGeI/+DAX4Jffq6hpD55MmoEvKs=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8=
|
||||
golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
|
||||
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
81
pkg/github/release.go
Normal file
81
pkg/github/release.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package github
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/google/go-github/v39/github"
|
||||
)
|
||||
|
||||
// GetLatestRelease gets the latest release for a repository.
|
||||
func GetLatestRelease(owner, repo string) (*github.RepositoryRelease, error) {
|
||||
client := github.NewClient(nil)
|
||||
release, _, err := client.Repositories.GetLatestRelease(context.Background(), owner, repo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return release, nil
|
||||
}
|
||||
|
||||
// DownloadReleaseAsset downloads a release asset.
|
||||
func DownloadReleaseAsset(asset *github.ReleaseAsset, path string) error {
|
||||
client := &http.Client{}
|
||||
req, err := http.NewRequest("GET", asset.GetBrowserDownloadURL(), nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Accept", "application/octet-stream")
|
||||
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return fmt.Errorf("bad status: %s", resp.Status)
|
||||
}
|
||||
|
||||
f, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
_, err = io.Copy(f, resp.Body)
|
||||
return err
|
||||
}
|
||||
|
||||
// ParseRepoFromURL parses the owner and repository from a GitHub URL.
|
||||
func ParseRepoFromURL(u string) (owner, repo string, err error) {
|
||||
u = strings.TrimSuffix(u, ".git")
|
||||
|
||||
prefixesToTrim := []string{
|
||||
"https://github.com/",
|
||||
"http://github.com/",
|
||||
"git://github.com/",
|
||||
"github.com/",
|
||||
}
|
||||
|
||||
// Handle scp-like and other formats by replacing them first.
|
||||
u = strings.Replace(u, "git@github.com:", "", 1)
|
||||
u = strings.Replace(u, "git:github.com:", "", 1)
|
||||
|
||||
for _, p := range prefixesToTrim {
|
||||
if strings.HasPrefix(u, p) {
|
||||
u = strings.TrimPrefix(u, p)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
parts := strings.Split(u, "/")
|
||||
if len(parts) != 2 {
|
||||
return "", "", fmt.Errorf("invalid or unsupported github url format: %s", u)
|
||||
}
|
||||
|
||||
return parts[0], parts[1], nil
|
||||
}
|
||||
|
|
@ -44,6 +44,19 @@ func TestCloneGitRepository(t *testing.T) {
|
|||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("Failed to git add: %v", err)
|
||||
}
|
||||
|
||||
cmd = exec.Command("git", "config", "user.email", "test@example.com")
|
||||
cmd.Dir = clonePath
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("Failed to set git user.email: %v", err)
|
||||
}
|
||||
|
||||
cmd = exec.Command("git", "config", "user.name", "Test User")
|
||||
cmd.Dir = clonePath
|
||||
if err := cmd.Run(); err != nil {
|
||||
t.Fatalf("Failed to set git user.name: %v", err)
|
||||
}
|
||||
|
||||
cmd = exec.Command("git", "commit", "-m", "Initial commit")
|
||||
cmd.Dir = clonePath
|
||||
if err := cmd.Run(); err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue