Skip to content

Commit

Permalink
Move GitLab to GitHub (#1)
Browse files Browse the repository at this point in the history
* Added repo

* Changed docker image to alpine

* Added README.md

* Release v1.1.1
  • Loading branch information
applejag authored Apr 12, 2021
1 parent 97f28e4 commit 413c450
Show file tree
Hide file tree
Showing 28 changed files with 2,574 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.dockerignore
Dockerfile
.wharf-ci.yml
docs/
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/docs/
*.swp
*.exe
5 changes: 5 additions & 0 deletions .wharf-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
build:
gitlab:
docker:
file: Dockerfile
tag: ${GIT_COMMIT},${GIT_TAG},latest
90 changes: 90 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Wharf GitLab plugin changelog

This project tries to follow [SemVer 2.0.0](https://semver.org/).

<!--
When composing new changes to this list, try to follow convention.
The WIP release shall be updated just before adding the Git tag.
From (WIP) to (YYYY-MM-DD), ex: (2021-02-09) for 9th of Febuary, 2021
A good source on conventions can be found here:
https://changelog.md/
-->

## v1.1.1 (2021-04-09)

- Added CHANGELOG.md to repository. (!10)

- Changed to use new open sourced Wharf API client
[github.com/iver-wharf/wharf-api-client-go](https://github.com/iver-wharf/wharf-api-client-go)
and bumped said package version from v1.1.0 to v1.2.0. (!11)

- Added `.dockerignore` to make Docker builds agnostic to wether you've ran
`swag init` locally. (!12)

- Changed base Docker image to be `alpine:3.13.4` instead of `scratch` to get
certificates from the Alpine package manager, APK, instead of embedding a
list of certificates inside the repository. (#1)

## v1.1.0 (2021-01-07)

- Fixed bug where GitLab access token was not correctly loaded. (!7, !8)

- Fixed failing unit tests. (!6)

- Changed version of Wharf API Go client, from v0.1.5 to v1.1.0, that contained
a lot of refactors in type and package name changes. (!5, !9)

- Changed version of package
[github.com/xanzy/go-gitlab](https://github.com/xanzy/go-gitlab) from v0.39.0
to v0.40.0. (!8)

## v1.0.0 (2020-11-27)

- Removed groups table, a reflection of the changes from the API v1.0.0. (!4)

## v0.7.2 (2020-11-27)

- Added logging via
[github.com/sirupsen/logrus](https://github.com/sirupsen/logrus) instead of
logging via the standard `fmt.Println`. (!3)

- Added testing library
[github.com/stretchr/testify](https://github.com/stretchr/testify) for
`assert.Equal`'esque unit test assertion style. (!3)

- Added abstractions for the GitLab library to make the code testable. (!3)

- Changed to using `PUT /branches` on main API to update the list of branches
for a project instead of `PUT /branch` to let the main API discard the old
ones. (!1)

- Changed version of package
[github.com/xanzy/go-gitlab](https://github.com/xanzy/go-gitlab) from v0.22.1
to v0.39.0. (!3)

- Removed unused package references from `go.mod`. (!2)

- Removed `docs/` files as they are autogenerated. (!3)

## v0.7.1 (2020-01-22)

- *Version bump.*

## v0.7.0 (2020-01-22)

- *Version bump.*

## v0.6.0 (2020-01-22)

- *Version bump.*

## v0.5.5 (2020-01-22)

- Added GitLab webhook endpoint `POST /import/gitlab/trigger`.
(389980cf, 2a53f399)

- Added repo, as extracted from previous mono-repo. (567d3197)

- Added `.wharf-ci.yml`. (4a62b241)
12 changes: 12 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
FROM golang:1.13.4 AS build
WORKDIR /src
ENV GO111MODULE=on
RUN go get -u github.com/swaggo/swag/cmd/[email protected]
COPY . /src
RUN swag init && CGO_ENABLED=0 go build -o main && go test -v

FROM alpine:3.13.4 AS final
RUN apk add --no-cache ca-certificates
WORKDIR /app
COPY --from=build /src/main ./
ENTRYPOINT ["/app/main"]
49 changes: 49 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# GitLab provider for Wharf

Import Wharf projects from GitLab repositories. Mainly focused on
importing from self hosted GitLab CE instances, importing from
gitlab.com is not well tested.

## Components

- HTTP API using the [gin-gonic/gin](https://github.com/gin-gonic/gin)
web framework.

- Swagger documentation generated using
[swaggo/swag](https://github.com/swaggo/swag) and hosted using
[swaggo/gin-swagger](https://github.com/swaggo/gin-swagger)

- GitLab API access using [xanzy/go-gitlab](https://github.com/xanzy/go-gitlab)

## Development

1. Install Go 1.13 or later: <https://golang.org/>

2. Install the [swaggo/swag](https://github.com/swaggo/swag) CLI globally:

```sh
# Run this outside of any Go module, including this repository, to not
# have `go get` update the go.mod file.
$ cd ..

$ go get -u github.com/swaggo/swag
```

3. Generate the swaggo files (this has to be redone each time the swaggo
documentation comments has been altered):

```sh
# Navigate back to this repository
$ cd wharf-provider-github

# Generate the files into docs/
$ swag
```

4. Start hacking with your favorite tool. For example VS Code, GoLand,
Vim, Emacs, or whatnot.

---

Maintained by [Iver](https://www.iver.com/en).
Licensed under the [MIT license](./LICENSE).
28 changes: 28 additions & 0 deletions event.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package main

type Change struct {
Before string `json:"before"`
After string `json:"after"`
Ref string `json:"ref"`
}

type Project struct {
Name string `json:"name"`
Description string `json:"description"`
Url string `json:"url"`
SshUrl string `json:"ssh_url"`
Namespace string `json:"namespace"`
}

const RepositoryUpdateEvent = "repository_update"

type RepositoryUpdate struct {
Name string `json:"event_name"`
Project Project `json:"project"`
Changes []Change `json:"changes"`
Refs []string `json:"refs"`
}

type Event struct {
Name string `json:"event_name"`
}
60 changes: 60 additions & 0 deletions event_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
package main

import (
"encoding/json"
"testing"
)

func TestDeserializeRepoUpdate(t *testing.T) {
example_update := `
{
"event_name": "repository_update",
"user_id": 1,
"user_name": "John Smith",
"user_email": "[email protected]",
"user_avatar": "https://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=8://s.gravatar.com/avatar/d4c74594d841139328695756648b6bd6?s=80",
"project_id": 1,
"project": {
"name":"Example",
"description":"",
"web_url":"http://example.com/jsmith/example",
"avatar_url":null,
"git_ssh_url":"[email protected]:jsmith/example.git",
"git_http_url":"http://example.com/jsmith/example.git",
"namespace":"Jsmith",
"visibility_level":0,
"path_with_namespace":"jsmith/example",
"default_branch":"master",
"homepage":"http://example.com/jsmith/example",
"url":"[email protected]:jsmith/example.git",
"ssh_url":"[email protected]:jsmith/example.git",
"http_url":"http://example.com/jsmith/example.git"
},
"changes": [
{
"before":"8205ea8d81ce0c6b90fbe8280d118cc9fdad6130",
"after":"4045ea7a3df38697b3730a20fb73c8bed8a3e69e",
"ref":"refs/heads/master"
}
],
"refs":["refs/heads/master"]
}
`

var got RepositoryUpdate

bytes := []byte(example_update)
err := json.Unmarshal(bytes, &got)

if err != nil {
t.Errorf("Error deserializing: %v", err)
}

if got.Name != "repository_update" {
t.Errorf("Expected repository_update, got %v", got.Name)
}

if got.Project.Name != "Example" {
t.Errorf("Expected name to be Example, got: %v", got.Project.Name)
}
}
135 changes: 135 additions & 0 deletions gitlab.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
package main

import (
"fmt"
"net/http"

log "github.com/sirupsen/logrus"
"github.com/xanzy/go-gitlab"
)

// REF is a default branch name. Used when default not set.
const REF = "master"

type gitLabClient struct {
*gitlab.Client
repositoryFiles gitLabRepoFilesReader
branches gitLabBranchesReader
projects gitLabProjectsReader
}

func getGitLabClient(token string, url string) (*gitLabClient, error) {
git, err := gitlab.NewClient(token, gitlab.WithBaseURL(url))
if err != nil {
log.WithError(err).Fatalf("Failed to create client.")
return nil, err
}

return &gitLabClient{git, git.RepositoryFiles, git.Branches, git.Projects}, nil
}

func (client *gitLabClient) listProjects(page int) ([]*gitlab.Project, gitLabPaging, error) {
opt := gitlab.ListProjectsOptions{OrderBy: gitlab.String("id")}
if page != 0 {
opt.Page = page
}

projects, resp, err := client.Projects.ListProjects(&opt)
if err != nil {
log.WithError(err).
WithField("page", page).
Errorln("failed to list projects")
return nil, mapToPaging(resp), err
}

return projects, mapToPaging(resp), nil
}

func (client *gitLabClient) getProject(groupName string, projectName string) (*gitlab.Project, error) {
projects, _, err := client.listProjectsFromGroup(fmt.Sprintf("%v/%v", groupName, projectName), 0)
if err != nil {
log.WithError(err).Errorln("failed to list projects")
return nil, err
}

if len(projects) == 1 {
return projects[0], nil
}

log.WithFields(log.Fields{
"projects": projects,
"group name": groupName,
"project name": projectName}).
Infoln("Invalid projects count")

return nil, fmt.Errorf("unable to get project %v/%v", groupName, projectName)
}

func (client *gitLabClient) listProjectsFromGroup(groupName string, page int) ([]*gitlab.Project, gitLabPaging, error) {
opt := gitlab.ListProjectsOptions{
OrderBy: gitlab.String("id"),
SearchNamespaces: gitlab.Bool(true),
Search: gitlab.String(groupName),
}
if page != 0 {
opt.Page = page
}

projects, resp, err := client.Projects.ListProjects(&opt)
if err != nil {
log.WithError(err).
WithFields(log.Fields{"group name": groupName, "page": page}).
Errorln("failed to list projects")
return nil, mapToPaging(resp), err
}

return projects, mapToPaging(resp), nil
}

func (client *gitLabClient) getBuildDefinitionIfExists(projectID int, defaultBranch string) (string, error) {
if defaultBranch == "" {
log.Debugln("default branch name cannot be empty")
defaultBranch = REF
}

ref := defaultBranch
opts := &gitlab.GetRawFileOptions{Ref: &ref}
bytes, resp, err := client.repositoryFiles.GetRawFile(projectID, BUILD_DEFINITION_FILE_NAME, opts)
if resp == nil {
return "", err
}

if resp.StatusCode == http.StatusNotFound {
return "", nil
}

if resp.StatusCode != http.StatusOK {
log.WithError(err).
WithFields(log.Fields{
"project ID": projectID,
"default branch name": defaultBranch,
"file name": BUILD_DEFINITION_FILE_NAME,
"status code": resp.StatusCode}).
Errorln("unable to get build definition")
return "", err
}

return string(bytes), err
}

func (client *gitLabClient) getBranches(gitLabProjectID int, page int) ([]*gitlab.Branch, gitLabPaging, error) {
opt := gitlab.ListBranchesOptions{}
if page != 0 {
opt.Page = page
}

branches, resp, err := client.branches.ListBranches(gitLabProjectID, &opt)
if err != nil {
log.WithError(err).
WithFields(log.Fields{"project id": gitLabProjectID, "page": page}).
Errorln("unable to list branches")
return nil, mapToPaging(resp), err
}

return branches, mapToPaging(resp), nil
}
Loading

0 comments on commit 413c450

Please sign in to comment.