Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions docs/plugins/gitlab-repo-scaffolding-golang.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,24 @@ tools:
options:
# the repo's owner. It should be case-sensitive here; strictly use your GitLab user name; please change the value below.
owner: YOUR_GITLAB_USERNAME
# the repo's org. If you set this property, then the new repo will be created under the org you're given, and the "owner" setting above will be ignored.
org: YOUR_ORGANIZATION_NAME
# the repo's org or group (if subgroup, the value is `groupname/subgroup`.) If you set this property, the new repo will be created under the org or group, and the "owner" setting above will be ignored.
org: YOUR_ORG_OR_GROUP_NAME
# the repo which you'd like to create; please change the value below.
repo: YOUR_REPO_NAME
# the branch of the repo you'd like to hold the code
branch: main
# the visibility of the created project. Value can be `public`, `private`, or `internal`.
visibility: private
# set to null if you are using GitLab cloud. For self-hosted GitLab, set this value to your GitLab URL.
baseURL: https://yourselfhost.com
# the image repo you'd like to push the container image; please change the value below.
image_repo: YOUR_DOCKERHUB_USERNAME/YOUR_DOCKERHUB_REPOSITORY
```

Replace the following from the config above:

- `YOUR_GITLAB_USERNAME`
- `YOUR_ORGANIZATION_NAME`
- `YOUR_ORG_OR_GROUP_NAME`
- `YOUR_REPO_NAME`
- `YOUR_DOCKERHUB_USERNAME`
- `YOUR_DOCKERHUB_REPOSITORY`
Expand All @@ -57,9 +61,9 @@ You have to specify either "owner" or "org".

## Outputs

This plugin has three outputs:
This plugin has four outputs:

- `org`
- `owner`
- `repo`
- `repoURL` (example: "https://gitlab.com/ironcore864/dtm-app-test.git")
- `repoURL` (example: "https://gitlab.com/ironcore864/dtm-app-test.git")
8 changes: 5 additions & 3 deletions docs/plugins/gitlabci-generic.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@ tools:
dependsOn: []
# options for the plugin
options:
# owner/repo; "path with namespace" is only GitLab API's way of saying the same thing; please change the values below.
pathWithNamespace: YOUR_GITLAB_USERNAME/YOUR_GITLAB_REPO_NAME
# owner/repo or group/repo or group/subgroup/repo; "path with namespace" is only GitLab API's way of saying the same thing; please change the values below.
pathWithNamespace: YOUR_GITLAB_USERNAME_OR_GROUP/YOUR_GITLAB_REPO_NAME
# main branch of the repo (to which branch the plugin will submit the workflows)
branch: main
# url of the GitLab CI template
# if you are using self-hosted gitlab, set this value to your site address, otherwise set it to null
baseURL: https://yourselfhost.com
# url of the GitLab CI template, if your
templateURL: https://someplace.com/to/download/your/template
# custom variables keys and values
templateVariables:
Expand Down
6 changes: 4 additions & 2 deletions docs/plugins/gitlabci-golang.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,12 @@ tools:
dependsOn: []
# options for the plugin
options:
# owner/repo; "path with namespace" is only GitLab API's way of saying the same thing; please change the values below.
pathWithNamespace: YOUR_GITLAB_USERNAME/YOUR_GITLAB_REPO_NAME
# owner/repo or group/repo or group/subgroup/repo; "path with namespace" is only GitLab API's way of saying the same thing; please change the values below.
pathWithNamespace: YOUR_GITLAB_USERNAME_OR_GROUP/YOUR_GITLAB_REPO_NAME
# main branch of the repo (to which branch the plugin will submit the workflows)
branch: main
# if you are using self-hosted gitlab, set this value to your site address, otherwise set it to null
baseURL: https://yourselfhost.com
```

All parameters are mandatory.
10 changes: 9 additions & 1 deletion internal/pkg/plugin/common/reposcaffolding/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package reposcaffolding

import (
"fmt"
"path/filepath"

"github.com/devstream-io/devstream/pkg/util/validator"
)
Expand All @@ -12,15 +13,22 @@ type Options struct {
Repo string `validate:"required"`
Branch string `validate:"required"`
PathWithNamespace string
BaseURL string `validate:"omitempty,url"`
ImageRepo string `mapstructure:"image_repo"`
Visibility string `validate:"omitempty,oneof=public private internal"`
}

// Validate validates the options provided by the core.
func Validate(opts *Options) []error {
retErrors := make([]error, 0)
retErrors = append(retErrors, validator.Struct(opts)...)
// set PathWithNamespace for GitLab. GitHub won't need to use this
opts.PathWithNamespace = fmt.Sprintf("%s/%s", opts.Owner, opts.Repo)
// opts.PathWithNamespace = fmt.Sprintf("%s/%s", opts.Owner, opts.Repo)
if opts.Org != "" {
opts.PathWithNamespace = filepath.Clean(fmt.Sprintf("%s/%s", opts.Org, opts.Repo))
} else {
opts.PathWithNamespace = filepath.Clean(fmt.Sprintf("%s/%s", opts.Owner, opts.Repo))
}

return retErrors
}
2 changes: 1 addition & 1 deletion internal/pkg/plugin/gitlabci/generic/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func Create(options map[string]interface{}) (map[string]interface{}, error) {
}

// commit file
client, err := gitlab.NewClient()
client, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/plugin/gitlabci/generic/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func Delete(options map[string]interface{}) (bool, error) {
return false, fmt.Errorf("opts are illegal")
}

client, err := gitlab.NewClient()
client, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return false, err
}
Expand Down
5 changes: 5 additions & 0 deletions internal/pkg/plugin/gitlabci/generic/generic.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package generic

import (
"fmt"
"io"
"net/http"
)
Expand All @@ -26,6 +27,10 @@ func download(url string) (string, error) {
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("failed to download template: %s %s", url, resp.Status)
}

resBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
Expand Down
1 change: 1 addition & 0 deletions internal/pkg/plugin/gitlabci/generic/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ type Options struct {
PathWithNamespace string `validate:"required"`
Branch string `validate:"required"`
TemplateURL string `validate:"required"`
BaseURL string `validate:"omitempty,url"`
TemplateVariables map[string]interface{}
}
2 changes: 1 addition & 1 deletion internal/pkg/plugin/gitlabci/generic/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func Read(options map[string]interface{}) (map[string]interface{}, error) {
return nil, fmt.Errorf("opts are illegal")
}

client, err := gitlab.NewClient()
client, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/plugin/gitlabci/generic/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ func Update(options map[string]interface{}) (map[string]interface{}, error) {
}

// update file
client, err := gitlab.NewClient()
client, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/plugin/gitlabci/golang/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func Create(options map[string]interface{}) (map[string]interface{}, error) {
return nil, fmt.Errorf("opts are illegal")
}

client, err := gitlab.NewClient()
client, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/plugin/gitlabci/golang/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ func Delete(options map[string]interface{}) (bool, error) {
}
return false, fmt.Errorf("opts are illegal")
}
client, err := gitlab.NewClient()
client, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return false, err
}
Expand Down
1 change: 1 addition & 0 deletions internal/pkg/plugin/gitlabci/golang/gitlabci.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const (
type Options struct {
PathWithNamespace string `validate:"required"`
Branch string `validate:"required"`
BaseURL string `validate:"omitempty,url"`
}

func buildState(opts *Options) map[string]interface{} {
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/plugin/gitlabci/golang/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ func Read(options map[string]interface{}) (map[string]interface{}, error) {
}
return nil, fmt.Errorf("opts are illegal")
}
client, err := gitlab.NewClient()
client, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion internal/pkg/plugin/gitlabci/golang/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func Update(options map[string]interface{}) (map[string]interface{}, error) {
return nil, fmt.Errorf("opts are illegal")
}

client, err := gitlab.NewClient()
client, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return nil, err
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func Delete(options map[string]interface{}) (bool, error) {
}

func uninstall(opts *rs.Options) (bool, error) {
c, err := gitlab.NewClient()
c, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return false, err
}
Expand Down
30 changes: 22 additions & 8 deletions internal/pkg/plugin/reposcaffolding/gitlab/golang/golang.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,21 @@ type Repo struct {

func pushToRemote(repoPath string, opts *rs.Options) error {
// create a GitLab client
c, err := gitlab.NewClient()
c, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return err
}

var retErr error
createProjOpts := &gitlab.CreateProjectOptions{
Name: opts.Repo,
Branch: opts.Branch,
Namespace: opts.Org,
Visibility: opts.Visibility,
}

// create the project
if err := c.CreateProject(opts.Repo, opts.Branch); err != nil {
if err := c.CreateProject(createProjOpts); err != nil {
log.Errorf("Failed to create repo: %s.", err)
return err
}
Expand All @@ -51,9 +57,10 @@ func pushToRemote(repoPath string, opts *rs.Options) error {
if retErr == nil {
return
}
log.Errorf("Failed to push to remote: %s.", retErr)
// need to clean the repo created when retErr != nil
if err := c.DeleteProject(opts.Repo); err != nil {
log.Errorf("Failed to delete the repo %s: %s.", opts.Repo, err)
if err := c.DeleteProject(opts.PathWithNamespace); err != nil {
log.Errorf("Failed to delete the repo %s: %s.", opts.PathWithNamespace, err)
}
}()

Expand Down Expand Up @@ -87,7 +94,6 @@ func walkLocalRepoPath(repoPath string, opts *rs.Options, c *gitlab.Client) erro
if err != nil {
return err
}

gitlabPath := strings.Join(strings.Split(path, "/")[2:], "/")
files[gitlabPath] = content
return nil
Expand Down Expand Up @@ -115,10 +121,18 @@ func buildState(opts *rs.Options) map[string]interface{} {
outputs["owner"] = opts.Owner
outputs["org"] = opts.Org
outputs["repo"] = opts.Repo
if opts.Owner != "" {
outputs["repoURL"] = fmt.Sprintf("https://gitlab.com/%s/%s.git", opts.Owner, opts.Repo)

var gitlabURL string
if opts.BaseURL != "" {
gitlabURL = opts.BaseURL
} else {
gitlabURL = gitlab.DefaultGitlabHost
}

if opts.Org != "" {
outputs["repoURL"] = fmt.Sprintf("%s/%s/%s.git", gitlabURL, opts.Org, opts.Repo)
} else {
outputs["repoURL"] = fmt.Sprintf("https://gitlab.com/%s/%s.git", opts.Org, opts.Repo)
outputs["repoURL"] = fmt.Sprintf("%s/%s/%s.git", gitlabURL, opts.Owner, opts.Repo)
}
res["outputs"] = outputs

Expand Down
26 changes: 14 additions & 12 deletions internal/pkg/plugin/reposcaffolding/gitlab/golang/read.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func Read(options map[string]interface{}) (map[string]interface{}, error) {
}

func buildReadState(opts *rs.Options) (map[string]interface{}, error) {
c, err := gitlab.NewClient()
c, err := gitlab.NewClient(gitlab.WithBaseURL(opts.BaseURL))
if err != nil {
return nil, err
}
Expand All @@ -41,21 +41,23 @@ func buildReadState(opts *rs.Options) (map[string]interface{}, error) {
}

res := make(map[string]interface{})
res["owner"] = project.Owner.Username
res["org"] = project.Owner.Organization
res["repoName"] = project.Name

outputs := make(map[string]interface{})
if opts.Owner == "" {
outputs["owner"] = opts.Owner
} else {

log.Debugf("GitLab Project is: %#v\n", project)

if project.Owner != nil {
log.Debugf("GitLab project owner is: %#v.\n", project.Owner)
res["owner"] = project.Owner.Username
res["org"] = project.Owner.Organization
outputs["owner"] = project.Owner.Username
}
if opts.Org == "" {
outputs["org"] = opts.Org
} else {
outputs["org"] = project.Owner.Organization
} else {
res["owner"] = opts.Owner
res["org"] = opts.Org
outputs["owner"] = opts.Owner
outputs["org"] = opts.Org
}
res["repoName"] = project.Name
outputs["repo"] = project.Name
outputs["repoURL"] = project.HTTPURLToRepo
res["outputs"] = outputs
Expand Down
39 changes: 34 additions & 5 deletions pkg/util/gitlab/gitlab.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package gitlab

import (
"fmt"
"errors"
"os"

"github.com/xanzy/go-gitlab"
Expand All @@ -11,24 +11,53 @@ import (

var client *Client

const (
DefaultGitlabHost = "https://gitlab.com"
)

type OptionFunc func(*Client)

func WithBaseURL(baseURL string) OptionFunc {
return func(c *Client) {
c.baseURL = baseURL
}
}

type Client struct {
baseURL string
*gitlab.Client
}

func NewClient() (*Client, error) {
func NewClient(opts ...OptionFunc) (*Client, error) {
if client != nil {
log.Debug("Use a cached client.")
return client, nil
}

token := os.Getenv("GITLAB_TOKEN")
if token == "" {
return nil, fmt.Errorf("failed to read GITLAB_TOKEN from environment variable")
return nil, errors.New("failed to read GITLAB_TOKEN from environment variable")
}
client, err := gitlab.NewClient(token)

c := &Client{}

for _, opt := range opts {
opt(c)
}

var err error

if c.baseURL == "" {
c.Client, err = gitlab.NewClient(token)
} else {
c.Client, err = gitlab.NewClient(token, gitlab.WithBaseURL(c.baseURL))

}

if err != nil {
return nil, err
}

return &Client{Client: client}, nil
return c, nil

}
Loading