Skip to content

Commit

Permalink
Add support for GitLab CI
Browse files Browse the repository at this point in the history
- adding support for GitLab CI
  • Loading branch information
nejec committed Sep 18, 2022
1 parent 3416752 commit e129eea
Show file tree
Hide file tree
Showing 4 changed files with 201 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Cargo, Go modules, NPM, Pip, or Yarn, but for CI/CD workflows. Ratchet supports:

- Circle CI
- GitHub Actions
- GitLab CI
- Google Cloud Build


Expand Down
80 changes: 80 additions & 0 deletions parser/gitlabci.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
package parser

import (
"fmt"

"github.com/sethvargo/ratchet/resolver"
"gopkg.in/yaml.v3"
)

type GitlabCI struct{}

// Parse pulls the image references from Gitlab CI configuration files.
// It does not support references with variables.

func (C *GitlabCI) Parse(m *yaml.Node) (*RefsList, error) {
var refs RefsList
var imageRef *yaml.Node

// Gitlab CI global top level keywords
var globalKeywords = map[string]bool{
"default": true,
"include": true,
"stages": true,
"variables": true,
"workflow": true,
}

if m == nil {
return nil, nil
}

if m.Kind != yaml.DocumentNode {
return nil, fmt.Errorf("expected document node, got %v", m.Kind)
}

// Top-level object map
for _, docMap := range m.Content {
if docMap.Kind != yaml.MappingNode {
continue
}
// jobs names
for i, keysMap := range docMap.Content {

// exclude global keywords
if globalKeywords[keysMap.Value] || keysMap.Value == "" {
continue
}

job := docMap.Content[i+1]
if job.Kind != yaml.MappingNode {
continue
}

for k, property := range job.Content {
if property.Value == "image" {

image := job.Content[k+1]

// match image reference with name key
if image.Kind == yaml.MappingNode {

for j, nameRef := range image.Content {
if nameRef.Value == "name" {
imageRef = image.Content[j+1]
break
}
}
} else {
imageRef = image
}

ref := resolver.NormalizeContainerRef(imageRef.Value)
refs.Add(ref, imageRef)
}
}
}
}

return &refs, nil
}
119 changes: 119 additions & 0 deletions parser/gitlabci_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package parser

import (
"fmt"
"reflect"
"testing"
)

func TestGitlabCI_Parse(t *testing.T) {
t.Parallel()

cases := []struct {
name string
in string
exp []string
}{
{
name: "no_image_reference",
in: `
stages:
- plan
- destroy
workflow:
rules:
- if: $CI_COMMIT_TAG
- if: $CI_COMMIT_BRANCH
variables:
VAR1: example
`,
exp: []string{},
},
{
name: "wrong_image_reference",
in: `
test_job:
stage: lint
variables:
SCAN_DIR: .
image: $CI_REGISTRY/image:tag
`,
exp: []string{
"container://$CI_REGISTRY/image:tag",
},
},
{
name: "multiline_image_ref",
in: `
test_job:
stage: test
variables:
SCAN_DIR: .
image:
name: alpine:3.15.0
entrypoint: [""]
script:
- printenv
`,
exp: []string{
"container://alpine:3.15.0",
},
},
{
name: "job_with_include",
in: `
.test:base:
stage: test
image: python
retry:
max: 1
variables:
VAR1: true
script:
- test command
job:
extends:
- .test:base
image: node:12
stage: test
script:
- test command
job2:
image: gcr.io/project/image:tag
stage: test
script:
- test command
`,
exp: []string{
"container://gcr.io/project/image:tag",
"container://node:12",
"container://python",
},
},
}

for _, tc := range cases {
tc := tc

t.Run(tc.name, func(t *testing.T) {
t.Parallel()

m := helperStringToYAML(t, tc.in)

refs, err := new(GitlabCI).Parse(m)

if err != nil {
fmt.Println(refs)
t.Fatal(err)
}

if got, want := refs.Refs(), tc.exp; !reflect.DeepEqual(got, want) {
t.Errorf("expected %q to be %q", got, want)
}
})
}
}
1 change: 1 addition & 0 deletions parser/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var parserFactory = map[string]func() Parser{
"actions": func() Parser { return new(Actions) },
"circleci": func() Parser { return new(CircleCI) },
"cloudbuild": func() Parser { return new(CloudBuild) },
"gitlabci": func() Parser { return new(GitlabCI) },
}

// For returns the parser that corresponds to the given name.
Expand Down

0 comments on commit e129eea

Please sign in to comment.