Skip to content

Commit ff29956

Browse files
authored
Merge pull request #6 from mouuff/feature/provider/gitlab
Feature/provider/gitlab
2 parents 51e86eb + e69f63b commit ff29956

File tree

5 files changed

+216
-7
lines changed

5 files changed

+216
-7
lines changed

README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ It provides the flexibility to implement different updating user experiences lik
1616
*The gopher in this image was created by [Takuya Ueda][tu], licensed under [Creative Commons 3.0 Attributions license][cc3-by].*
1717

1818
## Features
19-
* Flexible way to provide updates (ex: using Github!)
19+
* Flexible way to provide updates (ex: using Github or Gitlab!)
2020
* Cross platform support (Mac, Linux, Arm, and Windows)
2121
* RSA signature verification
2222
* Tooling to generate and verify signatures
@@ -54,10 +54,11 @@ The updater uses a `Provider` as an input source for updates. It provides files
5454

5555
Here is few examples of providers:
5656
* `provider.Github`: It will check for the latest release on Github with a specific zip name
57+
* `provider.Gitlab`: It will check for the latest release on Gitlab with a specific zip name
5758
* `provider.Local`: It will use a local folder, version will be defined in the VERSION file (can be used for testing, or in a company with a shared folder for example)
5859
* `provider.Zip`: Same as provider.Local but with a `Zip` file
5960

60-
*In the future there will be providers for FTP servers and Gitlab.*
61+
*In the future there will be providers for FTP servers and Google cloud storage.*
6162

6263
The updater will list the files and retrieve them the same way for all the providers:
6364

@@ -74,7 +75,7 @@ We recommend using [goxc](https://github.com/laher/goxc) for compiling your Go a
7475
### Planned features
7576
This project is currently under construction, here is some of the things to come:
7677
* More documentation and examples
77-
* Gitlab and FTP providers
78+
* Google cloud storage and FTP providers
7879
* Mutliple providers (enables the use of another provider if the first one is down)
7980
* Update channels for Github provider (alpha, beta, ...)
8081
* Rollback feature

examples/gitlab-simple/main.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
package main
2+
3+
import (
4+
"log"
5+
"runtime"
6+
7+
"github.com/mouuff/go-rocket-update/pkg/provider"
8+
"github.com/mouuff/go-rocket-update/pkg/updater"
9+
)
10+
11+
func main() {
12+
// Example project here: https://gitlab.com/arnaudalies.py/go-rocket-update-example
13+
u := &updater.Updater{
14+
Provider: &provider.Gitlab{
15+
ProjectID: 24021648,
16+
ZipName: "binaries_" + runtime.GOOS + ".zip",
17+
},
18+
BinaryName: "go-rocket-update-example",
19+
Version: "v0.3.0",
20+
}
21+
22+
log.Println(u.Version)
23+
if err := u.Update(); err != nil {
24+
log.Println(err)
25+
}
26+
}

pkg/provider/provider_github.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,21 @@ type githubTag struct {
2929
Name string `json:"name"`
3030
}
3131

32-
// repositoryInfo is used to get the name of the project and the owner name
32+
// githubRepositoryInfo is used to get the name of the project and the owner name
3333
// from this fields we are able to get other links (such as the release and tags link)
34-
type repositoryInfo struct {
34+
type githubRepositoryInfo struct {
3535
RepositoryOwner string
3636
RepositoryName string
3737
}
3838

3939
// getRepositoryInfo parses the github repository URL
40-
func (c *Github) repositoryInfo() (*repositoryInfo, error) {
40+
func (c *Github) repositoryInfo() (*githubRepositoryInfo, error) {
4141
re := regexp.MustCompile(`github\.com/(.*?)/(.*?)$`)
4242
submatches := re.FindAllStringSubmatch(c.RepositoryURL, 1)
4343
if len(submatches) < 1 {
4444
return nil, errors.New("Invalid github URL:" + c.RepositoryURL)
4545
}
46-
return &repositoryInfo{
46+
return &githubRepositoryInfo{
4747
RepositoryOwner: submatches[0][1],
4848
RepositoryName: submatches[0][2],
4949
}, nil

pkg/provider/provider_gitlab.go

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package provider
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"io"
8+
"net/http"
9+
"os"
10+
"path/filepath"
11+
"strings"
12+
13+
"github.com/mouuff/go-rocket-update/internal/fileio"
14+
)
15+
16+
// Gitlab provider finds a zip file in the repository's releases to provide files
17+
type Gitlab struct {
18+
ProjectID int
19+
ZipName string // Zip name (the zip you upload for a release on gitlab), example: binaries.zip
20+
21+
tmpDir string // temporary directory this is used internally
22+
zipProvider *Zip // provider used to unzip the downloaded zip
23+
zipPath string // path to the downloaded zip (should be in tmpDir)
24+
}
25+
26+
// gitlabRelease struct used to unmarshal response from gitlab
27+
// https://gitlab.com/api/v4/projects/24021648/releases
28+
type gitlabRelease struct {
29+
TagName string `json:"tag_name"`
30+
Assets *gitlabReleaseAssets `json:"assets"`
31+
}
32+
33+
type gitlabReleaseAssets struct {
34+
Links []gitlabReleaseLink `json:"links"`
35+
}
36+
37+
type gitlabReleaseLink struct {
38+
Name string `json:"name"`
39+
DirectURL string `json:"direct_asset_url"`
40+
}
41+
42+
// getReleasesURL get the releases URL for the gitlab repository
43+
func (c *Gitlab) getReleasesURL() (string, error) {
44+
return fmt.Sprintf("https://gitlab.com/api/v4/projects/%d/releases",
45+
c.ProjectID,
46+
), nil
47+
}
48+
49+
// getZipURL get the zip URL for the gitlab repository
50+
// the latest version is selected
51+
func (c *Gitlab) getZipURL() (string, error) {
52+
release, err := c.getLatestRelease()
53+
if err != nil {
54+
return "", err
55+
}
56+
for _, link := range release.Assets.Links {
57+
if strings.HasSuffix(link.Name, c.ZipName) {
58+
return link.DirectURL, nil
59+
}
60+
}
61+
return "", errors.New("Link not found for name: " + c.ZipName)
62+
}
63+
64+
// getReleases gets tags of the repository
65+
func (c *Gitlab) getReleases() (releases []gitlabRelease, err error) {
66+
releasesURL, err := c.getReleasesURL()
67+
if err != nil {
68+
return
69+
}
70+
resp, err := http.Get(releasesURL)
71+
if err != nil {
72+
return
73+
}
74+
defer resp.Body.Close()
75+
err = json.NewDecoder(resp.Body).Decode(&releases)
76+
if err != nil {
77+
return
78+
}
79+
return
80+
}
81+
82+
// getReleases gets tags of the repository
83+
func (c *Gitlab) getLatestRelease() (*gitlabRelease, error) {
84+
releases, err := c.getReleases()
85+
if err != nil {
86+
return nil, err
87+
}
88+
if len(releases) < 1 {
89+
return nil, errors.New("This gitlab project has no releases")
90+
}
91+
return &releases[0], nil
92+
}
93+
94+
// Open opens the provider
95+
func (c *Gitlab) Open() (err error) {
96+
zipURL, err := c.getZipURL() // get zip url for latest version
97+
if err != nil {
98+
return
99+
}
100+
resp, err := http.Get(zipURL)
101+
if err != nil {
102+
return
103+
}
104+
defer resp.Body.Close()
105+
106+
c.tmpDir, err = fileio.TempDir()
107+
if err != nil {
108+
return
109+
}
110+
111+
c.zipPath = filepath.Join(c.tmpDir, c.ZipName)
112+
zipFile, err := os.Create(c.zipPath)
113+
if err != nil {
114+
return
115+
}
116+
_, err = io.Copy(zipFile, resp.Body)
117+
zipFile.Close()
118+
if err != nil {
119+
return
120+
}
121+
c.zipProvider = &Zip{Path: c.zipPath}
122+
return c.zipProvider.Open()
123+
}
124+
125+
// Close closes the provider
126+
func (c *Gitlab) Close() error {
127+
if c.zipProvider != nil {
128+
c.zipProvider.Close()
129+
c.zipProvider = nil
130+
}
131+
132+
if len(c.tmpDir) > 0 {
133+
os.RemoveAll(c.tmpDir)
134+
c.tmpDir = ""
135+
c.zipPath = ""
136+
}
137+
return nil
138+
}
139+
140+
// GetLatestVersion gets the latest version
141+
func (c *Gitlab) GetLatestVersion() (string, error) {
142+
release, err := c.getLatestRelease()
143+
if err != nil {
144+
return "", err
145+
}
146+
return release.TagName, nil
147+
}
148+
149+
// Walk walks all the files provided
150+
func (c *Gitlab) Walk(walkFn WalkFunc) error {
151+
return c.zipProvider.Walk(walkFn)
152+
}
153+
154+
// Retrieve file relative to "provider" to destination
155+
func (c *Gitlab) Retrieve(src string, dest string) error {
156+
return c.zipProvider.Retrieve(src, dest)
157+
}

pkg/provider/provider_gitlab_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package provider_test
2+
3+
import (
4+
"runtime"
5+
"testing"
6+
7+
provider "github.com/mouuff/go-rocket-update/pkg/provider"
8+
)
9+
10+
func TestProviderGitlab(t *testing.T) {
11+
p := &provider.Gitlab{
12+
ProjectID: 24021648,
13+
ZipName: "binaries_" + runtime.GOOS + ".zip",
14+
}
15+
16+
if err := p.Open(); err != nil {
17+
t.Fatal(err)
18+
}
19+
defer p.Close()
20+
21+
err := ProviderTestWalkAndRetrieve(p)
22+
if err != nil {
23+
t.Fatal(err)
24+
}
25+
}

0 commit comments

Comments
 (0)