Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: initial GitHub support #18

Merged
merged 1 commit into from
May 12, 2024
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
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,11 @@ jobs:
- name: Ensure scm-engine binary work
run: ./scm-engine -h

- name: Test scm-engine against test GitLab project
- name: Test scm-engine against a GitLab project
run: ./scm-engine evaluate all
env:
SCM_ENGINE_TOKEN: "${{ secrets.GITLAB_INTEGRATION_TEST_API_TOKEN }}"
SCM_ENGINE_CONFIG_FILE: ".scm-engine.example.yml"
SCM_ENGINE_CONFIG_FILE: ".scm-engine.gitlab.example.yml"
GITLAB_PROJECT: "jippi/scm-engine-schema-test"
GITLAB_BASEURL: https://gitlab.com/

Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,4 @@
/scm-engine
/scm-engine.exe
/docs/gitlab/script-attributes.md
/docs/github/script-attributes.md
File renamed without changes.
3 changes: 3 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ tasks:

setup:
desc: Install dependencies
vars:
# don't use the automatic provider detection in CI
SCM_ENGINE_DONT_DETECT_PROVIDER: 1
cmds:
- go mod tidy
- go generate ./...
Expand Down
7 changes: 5 additions & 2 deletions cmd/cmd_evaluate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,26 @@ import (

"github.com/jippi/scm-engine/pkg/config"
"github.com/jippi/scm-engine/pkg/scm"
"github.com/jippi/scm-engine/pkg/scm/gitlab"
"github.com/jippi/scm-engine/pkg/state"
"github.com/urfave/cli/v2"
)

func Evaluate(cCtx *cli.Context) error {
ctx := state.WithProjectID(cCtx.Context, cCtx.String(FlagSCMProject))
ctx = state.WithBaseURL(ctx, cCtx.String(FlagSCMBaseURL))
ctx = state.WithCommitSHA(ctx, cCtx.String(FlagCommitSHA))
ctx = state.WithDryRun(ctx, cCtx.Bool(FlagDryRun))
ctx = state.WithProvider(ctx, cCtx.String(FlagProvider))
ctx = state.WithToken(ctx, cCtx.String(FlagAPIToken))
ctx = state.WithToken(ctx, cCtx.String(FlagAPIToken))
ctx = state.WithUpdatePipeline(ctx, cCtx.Bool(FlagUpdatePipeline))

cfg, err := config.LoadFile(cCtx.String(FlagConfigFile))
if err != nil {
return err
}

client, err := gitlab.NewClient(cCtx.String(FlagAPIToken), cCtx.String(FlagSCMBaseURL))
client, err := getClient(ctx)
if err != nil {
return err
}
Expand Down
19 changes: 11 additions & 8 deletions cmd/cmd_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"time"

"github.com/jippi/scm-engine/pkg/config"
"github.com/jippi/scm-engine/pkg/scm/gitlab"
"github.com/jippi/scm-engine/pkg/state"
"github.com/urfave/cli/v2"
slogctx "github.com/veqryn/slog-context"
Expand Down Expand Up @@ -55,15 +54,22 @@ func errHandler(ctx context.Context, w http.ResponseWriter, code int, err error)
return
}

func Server(cCtx *cli.Context) error { //nolint:unparam
slogctx.Info(cCtx.Context, "Starting HTTP server", slog.String("listen", cCtx.String(FlagServerListen)))
func Server(cCtx *cli.Context) error {
// Initialize context
ctx := state.WithDryRun(cCtx.Context, cCtx.Bool(FlagDryRun))
ctx = state.WithBaseURL(ctx, cCtx.String(FlagSCMBaseURL))
ctx = state.WithToken(ctx, cCtx.String(FlagAPIToken))
ctx = state.WithProvider(ctx, cCtx.String(FlagProvider))
ctx = state.WithUpdatePipeline(ctx, cCtx.Bool(FlagUpdatePipeline))

slogctx.Info(ctx, "Starting HTTP server", slog.String("listen", cCtx.String(FlagServerListen)))

mux := http.NewServeMux()

ourSecret := cCtx.String(FlagWebhookSecret)

// Initialize GitLab client
client, err := gitlab.NewClient(cCtx.String(FlagAPIToken), cCtx.String(FlagSCMBaseURL))
// Initialize client
client, err := getClient(cCtx.Context)
if err != nil {
return err
}
Expand Down Expand Up @@ -179,9 +185,6 @@ func Server(cCtx *cli.Context) error { //nolint:unparam
ReadTimeout: 5 * time.Second,
WriteTimeout: 5 * time.Second,
BaseContext: func(l net.Listener) context.Context {
ctx := state.WithDryRun(cCtx.Context, cCtx.Bool(FlagDryRun))
ctx = state.WithUpdatePipeline(ctx, cCtx.Bool(FlagUpdatePipeline))

return ctx
},
}
Expand Down
5 changes: 3 additions & 2 deletions cmd/conventions.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ package cmd

const (
FlagAPIToken = "api-token"
FlagCommitSHA = "commit"
FlagConfigFile = "config"
FlagDryRun = "dry-run"
FlagMergeRequestID = "id"
FlagUpdatePipeline = "update-pipeline"
FlagCommitSHA = "commit"
FlagProvider = "provider"
FlagSCMBaseURL = "base-url"
FlagSCMProject = "project"
FlagServerListen = "listen"
FlagUpdatePipeline = "update-pipeline"
FlagWebhookSecret = "webhook-secret"
)
21 changes: 18 additions & 3 deletions cmd/shared.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,29 @@ import (

"github.com/jippi/scm-engine/pkg/config"
"github.com/jippi/scm-engine/pkg/scm"
"github.com/jippi/scm-engine/pkg/scm/github"
"github.com/jippi/scm-engine/pkg/scm/gitlab"
"github.com/jippi/scm-engine/pkg/state"
slogctx "github.com/veqryn/slog-context"
)

func getClient(ctx context.Context) (scm.Client, error) {
switch state.Provider(ctx) {
case "github":
return github.NewClient(ctx), nil

case "gitlab":
return gitlab.NewClient(ctx)

default:
return nil, fmt.Errorf("unknown provider %q - we only support 'github' and 'gitlab'", state.Provider(ctx))
}
}

func ProcessMR(ctx context.Context, client scm.Client, cfg *config.Config, event any) (err error) {
// Stop the pipeline when we leave this func
defer func() {
if stopErr := client.Stop(ctx, err); err != nil {
if stopErr := client.Stop(ctx, err); stopErr != nil {
slogctx.Error(ctx, "Failed to update pipeline", slog.Any("error", stopErr))
}
}()
Expand Down Expand Up @@ -157,12 +172,12 @@ func syncLabels(ctx context.Context, client scm.Client, remote []*scm.Label, req

// Update
for _, label := range required {
e, ok := remoteLabels[label.Name]
remote, ok := remoteLabels[label.Name]
if !ok {
continue
}

if label.IsEqual(e) {
if label.IsEqual(ctx, remote) {
continue
}

Expand Down
11 changes: 6 additions & 5 deletions docs/commands/evaluate.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,17 @@ USAGE:
scm-engine evaluate [command options] [mr_id, mr_id, ...]

OPTIONS:
--project value GitLab project (example: 'gitlab-org/gitlab') [$GITLAB_PROJECT, $CI_PROJECT_PATH]
--id value The pull/merge ID to process, if not provided as a CLI flag [$CI_MERGE_REQUEST_IID]
--commit value The git commit sha [$CI_COMMIT_SHA]
--update-pipeline Update the CI pipeline status with progress (default: false) [$SCM_ENGINE_UPDATE_PIPELINE]
--project value GitLab project (example: 'gitlab-org/gitlab') [$GITLAB_PROJECT, $CI_PROJECT_PATH, $GITHUB_REPOSITORY]
--id value The pull/merge ID to process, if not provided as a CLI flag [$CI_MERGE_REQUEST_IID]
--commit value The git commit sha [$CI_COMMIT_SHA, $GITHUB_SHA]
--help, -h show help

GLOBAL OPTIONS:
--config value Path to the scm-engine config file (default: ".scm-engine.yml") [$SCM_ENGINE_CONFIG_FILE]
--api-token value GitHub/GitLab API token [$SCM_ENGINE_TOKEN]
--base-url value Base URL for the SCM instance (default: "https://gitlab.com/") [$GITLAB_BASEURL, $CI_SERVER_URL]
--provider value SCM provider to use. Must be either "github" or "gitlab". SCM Engine will automatically detect "github" if "GITHUB_ACTIONS" environment variable is set (e.g., inside GitHub Actions) and detect "gitlab" if "GITLAB_CI" environment variable is set (e.g., inside GitLab CI). [$SCM_ENGINE_PROVIDER]
--api-token value GitHub/GitLab API token [$SCM_ENGINE_TOKEN, $GITHUB_TOKEN]
--base-url value Base URL for the SCM instance (default: "https://gitlab.com/") [$GITLAB_BASEURL, $CI_SERVER_URL, $GITHUB_API_URL]
--dry-run Dry run, don't actually _do_ actions, just print them (default: false)
--help, -h show help
--version, -v print the version
Expand Down
5 changes: 3 additions & 2 deletions docs/commands/server.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,9 @@ OPTIONS:

GLOBAL OPTIONS:
--config value Path to the scm-engine config file (default: ".scm-engine.yml") [$SCM_ENGINE_CONFIG_FILE]
--api-token value GitHub/GitLab API token [$SCM_ENGINE_TOKEN]
--base-url value Base URL for the SCM instance (default: "https://gitlab.com/") [$GITLAB_BASEURL, $CI_SERVER_URL]
--provider value SCM provider to use. Must be either "github" or "gitlab". SCM Engine will automatically detect "github" if "GITHUB_ACTIONS" environment variable is set (e.g., inside GitHub Actions) and detect "gitlab" if "GITLAB_CI" environment variable is set (e.g., inside GitLab CI). [$SCM_ENGINE_PROVIDER]
--api-token value GitHub/GitLab API token [$SCM_ENGINE_TOKEN, $GITHUB_TOKEN]
--base-url value Base URL for the SCM instance (default: "https://gitlab.com/") [$GITLAB_BASEURL, $CI_SERVER_URL, $GITHUB_API_URL]
--dry-run Dry run, don't actually _do_ actions, just print them (default: false)
--help, -h show help
--version, -v print the version
Expand Down
6 changes: 3 additions & 3 deletions docs/configuration/index.md → docs/configuration.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Options
# Configuration file

The default configuration filename is `.scm-engine.yml`, either in current working directory, or if you are in a Git repository, the root of the project.

Expand Down Expand Up @@ -105,15 +105,15 @@ SCM Engine supports two strategies for managing labels, each changes the behavio

Use the `#!yaml conditional` strategy when you want to add/remove a label on a Merge Request depending on *something*. It's the default strategy, and the most simple one to use.

!!! example "Please see the [*Add label if a file extension is modified*](examples.md#add-label-if-a-file-extension-is-modified) example for how to use this"
!!! example "Please see the [*Add label if a file extension is modified*](./gitlab/examples.md#add-label-if-a-file-extension-is-modified) example for how to use this"

#### `label[].strategy = generate` {#label.strategy-generate data-toc-label="generate"}

Use the [`#!yaml generate`](#label.strategy) strategy if you want to create dynamic labels, for example, depending labels based on the file structure within your project.

Thanks to the dynamic nature of the `#!yaml generate` strategy, it has fantastic flexibility, at the cost of greater complexity.

!!! example "Please see the [*generate labels from directory layout*](examples.md#generate-labels-via-script) example for how to use this"
!!! example "Please see the [*generate labels from directory layout*](./gitlab/examples.md#generate-labels-via-script) example for how to use this"

### `label[].name` {#label.name data-toc-label="name"}

Expand Down
10 changes: 10 additions & 0 deletions docs/github/.pages
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
title: >
<svg style="vertical-align: sub" aria-hidden="true" viewBox="0 0 16 16" version="1.1" data-view-component="true" class="octicon octicon-mark-github v-align-middle">
<path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45.68 1.31 2.69.94 0 .67.01 1.3.01 1.49 0 .21-.15.45-.55.38A7.995 7.995 0 0 1 0 8c0-4.42 3.58-8 8-8Z"></path>
</svg>

GitHub (WIP)

arrange:
- setup.md
- ...
103 changes: 103 additions & 0 deletions docs/github/script-functions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# Script Functions

!!! tip "The [Expr Language Definition](https://expr-lang.org/docs/language-definition) is a great resource to learn more about the language"

## pull_request

### `pull_request.state_is(string...) -> boolean` {: #pull_request.state_is data-toc-label="state_is"}

Check if the `pull_request` state is any of the provided states

**Valid options**:

- `CLOSED` - In closed state
- `MERGED` - Pull Request has been merged
- `OPEN` - Opened Pull Request

```css
pull_request.state_is("MERGED")
pull_request.state_is("CLOSED", "MERGED")
```

### `pull_request.modified_files(string...) -> boolean` {: #pull_request.modified_files data-toc-label="modified_files"}

Returns wether any of the provided files patterns have been modified in the Pull Request.

The file patterns use the [`.gitignore` format](https://git-scm.com/docs/gitignore#_pattern_format).

```css
pull_request.modified_files("*.go", "docs/") == true
```

### `pull_request.modified_files_list(string...) -> []string` {: #pull_request.modified_files_list data-toc-label="modified_files_list"}

Returns an array of files matching the provided (optional) pattern thas has been modified in the Pull Request.

The file patterns use the [`.gitignore` format](https://git-scm.com/docs/gitignore#_pattern_format).

```css
pull_request.modified_files_list("*.go", "docs/") == ["example/file.go", "docs/index.md"]
```

### `pull_request.has_label(string) -> boolean` {: #pull_request.has_label data-toc-label="has_label"}

Returns wether any of the provided label exist on the Pull Request.

```css
pull_request.labels = ["hello"]
pull_request.has_label("hello") == true
pull_request.has_label("world") == false
```

### `pull_request.has_no_label(string) -> boolean` {: #pull_request.has_no_label data-toc-label="has_no_label"}

Returns wether the Pull Request has the provided label or not.

```css
pull_request.labels = ["hello"]
pull_request.has_no_label("hello") == false
pull_request.has_no_label("world") == true
```

## Global

### `duration(string) -> duration` {: #duration data-toc-label="duration"}

Returns the [`time.Duration`](https://pkg.go.dev/time#Duration) value of the given string str.

Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h", "d" and "w".

```css
duration("1h").Seconds() == 3600
```

### `uniq([]string) -> []string` {: #uniq data-toc-label="uniq"}

Returns a new array where all duplicate values has been removed.

```css
(["hello", "world", "world"] | uniq) == ["hello", "world"]
```

### `filepath_dir` {: #filepath_dir data-toc-label="filepath_dir"}

`filepath_dir` returns all but the last element of path, typically the path's directory. After dropping the final element,

Dir calls [Clean](https://pkg.go.dev/path/filepath#Clean) on the path and trailing slashes are removed.

If the path is empty, `filepath_dir` returns ".". If the path consists entirely of separators, `filepath_dir` returns a single separator.

The returned path does not end in a separator unless it is the root directory.

```css
filepath_dir("example/directory/file.go") == "example/directory"
```

### `limit_path_depth_to` {: #limit_path_depth_to data-toc-label="limit_path_depth_to"}

`limit_path_depth_to` takes a path structure, and limits it to the configured maximum depth. Particularly useful when using `generated` labels from a directory structure, and want to to have a label naming scheme that only uses path of the path.

```css
limit_path_depth_to("path1/path2/path3/path4", 2), == "path1/path2"
limit_path_depth_to("path1/path2", 3), == "path1/path2"
```
3 changes: 3 additions & 0 deletions docs/github/setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Setup

TODO
24 changes: 24 additions & 0 deletions docs/gitlab/.pages
Original file line number Diff line number Diff line change
@@ -1,3 +1,27 @@
title: >
<svg style="enable-background:new 0 0 100 92;vertical-align: sub;" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 100 92" xml:space="preserve">
<style type="text/css">
.st0{fill:#E24329;}
.st1{fill:#FC6D26;}
.st2{fill:#FCA326;}
</style>
<desc>Created with Sketch.</desc>
<g>
<path class="st0" d="M95.9,36.5l-0.1-0.3L82.8,2.4c-0.3-0.7-0.7-1.2-1.3-1.6c-0.6-0.4-1.3-0.6-2-0.5c-0.7,0-1.4,0.3-2,0.7
c-0.6,0.4-1,1.1-1.1,1.7l-8.7,26.7H32.3L23.6,2.7C23.4,2.1,23,1.4,22.5,1c-0.6-0.4-1.2-0.7-2-0.7c-0.7,0-1.4,0.1-2,0.5
c-0.6,0.4-1.1,0.9-1.3,1.6L4.2,36.1l-0.1,0.3c-3.8,10-0.6,21.3,8,27.7c0,0,0,0,0,0l0.1,0.1l19.7,14.7l9.7,7.4l5.9,4.5
c1.4,1.1,3.4,1.1,4.8,0l5.9-4.5l9.7-7.4l19.8-14.8c0,0,0,0,0.1,0C96.5,57.8,99.7,46.5,95.9,36.5z"/>
<path class="st1" d="M95.9,36.5l-0.1-0.3c-6.4,1.3-12.3,4-17.4,7.8C78.3,44,63,55.6,50,65.4c9.7,7.3,18.1,13.7,18.1,13.7l19.8-14.8
c0,0,0,0,0.1,0C96.5,57.8,99.7,46.5,95.9,36.5z"/>
<path class="st2" d="M31.9,79.1l9.7,7.4l5.9,4.5c1.4,1.1,3.4,1.1,4.8,0l5.9-4.5l9.7-7.4c0,0-8.4-6.4-18.1-13.7
C40.3,72.7,31.9,79.1,31.9,79.1z"/>
<path class="st1" d="M21.6,43.9c-5.1-3.8-11-6.5-17.4-7.8l-0.1,0.3c-3.8,10-0.6,21.3,8,27.7c0,0,0,0,0,0l0.1,0.1l19.7,14.7
c0,0,8.4-6.4,18.1-13.7C37,55.6,21.7,44,21.6,43.9z"/>
</g>
</svg>

GitLab

arrange:
- setup.md
- ...
File renamed without changes.
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ hide:

## What does it look like?

!!! tip "Please see the [Configuration Examples page](configuration/examples.md) for more use-cases"
!!! tip "Please see the [Configuration Examples page](gitlab/examples.md) for more use-cases"

!!! info "Please see the [Configuration Options page](configuration/index.md) for all options and explanations"
!!! info "Please see the [Configuration Options page](configuration.md) for all options and explanations"

```yaml
--8<-- ".scm-engine.example.yml"
--8<-- ".scm-engine.gitlab.example.yml"
```
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ require (
github.com/expr-lang/expr v1.16.7
github.com/fatih/structtag v1.2.0
github.com/golang-cz/devslog v0.0.8
github.com/google/go-github/v62 v62.0.0
github.com/guregu/null/v5 v5.0.0
github.com/hasura/go-graphql-client v0.12.1
github.com/iancoleman/strcase v0.3.0
Expand Down
Loading
Loading