Merge branch 'master' into master
This commit is contained in:
commit
a6f931e697
143 changed files with 4412 additions and 23114 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
.vscode
|
||||
__debug_bin
|
||||
*.sqlite
|
||||
*.txt
|
||||
*.out
|
||||
|
|
2
BUILDING
2
BUILDING
|
@ -2,8 +2,6 @@
|
|||
2. Install go 1.11 or later with Go modules enabled
|
||||
3. Install binaries to $GOPATH/bin
|
||||
|
||||
go install github.com/drone/drone/cmd/drone-agent
|
||||
go install github.com/drone/drone/cmd/drone-controller
|
||||
go install github.com/drone/drone/cmd/drone-server
|
||||
|
||||
4. Start the server at localhost:8080
|
||||
|
|
16
CHANGELOG.md
16
CHANGELOG.md
|
@ -5,6 +5,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## Unreleased
|
||||
|
||||
## [2.0.1]
|
||||
### Added
|
||||
- support for configuring the internal yaml cache size.
|
||||
|
||||
## [2.0.0]
|
||||
### Added
|
||||
- feature flags for mixed-mode database encryption.
|
||||
|
||||
### Changed
|
||||
- user-interface re-design
|
||||
|
||||
### Breaking
|
||||
- removed deprecated kubernetes integration in favor of official kubernetes runner.
|
||||
- removed deprecated nomad integration in favor of official nomad runner.
|
||||
|
@ -82,13 +94,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- page to view the latest build per branch.
|
||||
|
||||
### Fixed
|
||||
- sync routine not executing asyncronously, being cancelled by http context.
|
||||
- sync routine not executing asynchronously, being cancelled by http context.
|
||||
- sync routine should ignore gitlab subrepositories
|
||||
- convert deploy events in 0.8 yaml to promote events.
|
||||
- do not execute cron job for disabled repositories. [#2931](https://github.com/drone/drone/issues/2931).
|
||||
- remove trailing slash from gitea url to prevent oauth2 token refresh errors, by [@cmj0121](https://github.com/cmj0121). [#2920](https://github.com/drone/drone/issues/2920).
|
||||
- disable font ligatures in build log output. [drone/drone-ui#322](https://github.com/drone/drone-ui/pull/322).
|
||||
- missing am/pm in timstamps
|
||||
- missing am/pm in timestamps
|
||||
|
||||
## [1.6.5] - 2020-01-29
|
||||
### Changed
|
||||
|
|
|
@ -87,6 +87,7 @@ tasks:
|
|||
- cmd: go test -count=1 github.com/drone/drone/store/secret/global
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/stage
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/step
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/template
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/user
|
||||
- cmd: docker kill mysql
|
||||
|
||||
|
@ -120,6 +121,7 @@ tasks:
|
|||
- cmd: go test -count=1 github.com/drone/drone/store/secret/global
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/stage
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/step
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/template
|
||||
- cmd: go test -count=1 github.com/drone/drone/store/user
|
||||
- cmd: docker kill postgres
|
||||
silent: true
|
||||
|
|
|
@ -111,12 +111,17 @@ type (
|
|||
|
||||
// Database provides the database configuration.
|
||||
Database struct {
|
||||
Driver string `envconfig:"DRONE_DATABASE_DRIVER" default:"sqlite3"`
|
||||
Datasource string `envconfig:"DRONE_DATABASE_DATASOURCE" default:"core.sqlite"`
|
||||
Secret string `envconfig:"DRONE_DATABASE_SECRET"`
|
||||
Driver string `envconfig:"DRONE_DATABASE_DRIVER" default:"sqlite3"`
|
||||
Datasource string `envconfig:"DRONE_DATABASE_DATASOURCE" default:"core.sqlite"`
|
||||
Secret string `envconfig:"DRONE_DATABASE_SECRET"`
|
||||
MaxConnections int `envconfig:"DRONE_DATABASE_MAX_CONNECTIONS" default:"0"`
|
||||
|
||||
// Feature flag
|
||||
LegacyBatch bool `envconfig:"DRONE_DATABASE_LEGACY_BATCH"`
|
||||
|
||||
// Feature flag
|
||||
EncryptUserTable bool `envconfig:"DRONE_DATABASE_ENCRYPT_USER_TABLE"`
|
||||
EncryptMixedContent bool `envconfig:"DRONE_DATABASE_ENCRYPT_MIXED_MODE"`
|
||||
}
|
||||
|
||||
// Docker provides docker configuration
|
||||
|
@ -302,6 +307,7 @@ type (
|
|||
Endpoint string `envconfig:"DRONE_CONVERT_PLUGIN_ENDPOINT"`
|
||||
Secret string `envconfig:"DRONE_CONVERT_PLUGIN_SECRET"`
|
||||
SkipVerify bool `envconfig:"DRONE_CONVERT_PLUGIN_SKIP_VERIFY"`
|
||||
CacheSize int `envconfig:"DRONE_CONVERT_PLUGIN_CACHE_SIZE" default:"10"`
|
||||
Timeout time.Duration `envconfig:"DRONE_CONVERT_TIMEOUT" default:"1m"`
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ import (
|
|||
"github.com/drone/drone/plugin/admission"
|
||||
"github.com/drone/drone/plugin/config"
|
||||
"github.com/drone/drone/plugin/converter"
|
||||
"github.com/drone/drone/plugin/converter/starlark"
|
||||
"github.com/drone/drone/plugin/registry"
|
||||
"github.com/drone/drone/plugin/secret"
|
||||
"github.com/drone/drone/plugin/validator"
|
||||
|
@ -77,15 +76,18 @@ func provideConfigPlugin(client *scm.Client, contents core.FileService, conf spe
|
|||
// provideConvertPlugin is a Wire provider function that returns
|
||||
// a yaml conversion plugin based on the environment
|
||||
// configuration.
|
||||
func provideConvertPlugin(client *scm.Client, conf spec.Config) core.ConvertService {
|
||||
func provideConvertPlugin(client *scm.Client, conf spec.Config, templateStore core.TemplateStore) core.ConvertService {
|
||||
return converter.Combine(
|
||||
converter.Legacy(false),
|
||||
starlark.New(
|
||||
converter.Starlark(
|
||||
conf.Starlark.Enabled,
|
||||
),
|
||||
converter.Jsonnet(
|
||||
conf.Jsonnet.Enabled,
|
||||
),
|
||||
converter.Template(
|
||||
templateStore,
|
||||
),
|
||||
converter.Memoize(
|
||||
converter.Remote(
|
||||
conf.Convert.Endpoint,
|
||||
|
@ -94,6 +96,7 @@ func provideConvertPlugin(client *scm.Client, conf spec.Config) core.ConvertServ
|
|||
conf.Convert.SkipVerify,
|
||||
conf.Convert.Timeout,
|
||||
),
|
||||
conf.Convert.CacheSize,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -31,9 +31,11 @@ import (
|
|||
"github.com/drone/drone/store/shared/encrypt"
|
||||
"github.com/drone/drone/store/stage"
|
||||
"github.com/drone/drone/store/step"
|
||||
"github.com/drone/drone/store/template"
|
||||
"github.com/drone/drone/store/user"
|
||||
|
||||
"github.com/google/wire"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// wire set for loading the stores.
|
||||
|
@ -52,6 +54,7 @@ var storeSet = wire.NewSet(
|
|||
secret.New,
|
||||
global.New,
|
||||
step.New,
|
||||
template.New,
|
||||
)
|
||||
|
||||
// provideDatabase is a Wire provider function that provides a
|
||||
|
@ -60,13 +63,27 @@ func provideDatabase(config config.Config) (*db.DB, error) {
|
|||
return db.Connect(
|
||||
config.Database.Driver,
|
||||
config.Database.Datasource,
|
||||
config.Database.MaxConnections,
|
||||
)
|
||||
}
|
||||
|
||||
// provideEncrypter is a Wire provider function that provides a
|
||||
// database encrypter, configured from the environment.
|
||||
func provideEncrypter(config config.Config) (encrypt.Encrypter, error) {
|
||||
return encrypt.New(config.Database.Secret)
|
||||
enc, err := encrypt.New(config.Database.Secret)
|
||||
// mixed-content mode should be set to true if the database
|
||||
// originally had encryption disabled and therefore has
|
||||
// plaintext entries. This prevents Drone from returning an
|
||||
// error if decryption fails; on failure, the ciphertext is
|
||||
// returned as-is and the error is ignored.
|
||||
if aesgcm, ok := enc.(*encrypt.Aesgcm); ok {
|
||||
logrus.Debugln("main: database encryption enabled")
|
||||
if config.Database.EncryptMixedContent {
|
||||
logrus.Debugln("main: database encryption mixed-mode enabled")
|
||||
aesgcm.Compat = true
|
||||
}
|
||||
}
|
||||
return enc, err
|
||||
}
|
||||
|
||||
// provideBuildStore is a Wire provider function that provides a
|
||||
|
@ -123,15 +140,6 @@ func provideRepoStore(db *db.DB) core.RepositoryStore {
|
|||
return repos
|
||||
}
|
||||
|
||||
// provideUserStore is a Wire provider function that provides a
|
||||
// user datastore, configured from the environment, with metrics
|
||||
// enabled.
|
||||
func provideUserStore(db *db.DB) core.UserStore {
|
||||
users := user.New(db)
|
||||
metric.UserCount(users)
|
||||
return users
|
||||
}
|
||||
|
||||
// provideBatchStore is a Wire provider function that provides a
|
||||
// batcher. If the experimental batcher is enabled it is returned.
|
||||
func provideBatchStore(db *db.DB, config config.Config) core.Batcher {
|
||||
|
@ -140,3 +148,32 @@ func provideBatchStore(db *db.DB, config config.Config) core.Batcher {
|
|||
}
|
||||
return batch2.New(db)
|
||||
}
|
||||
|
||||
// provideUserStore is a Wire provider function that provides a
|
||||
// user datastore, configured from the environment, with metrics
|
||||
// enabled.
|
||||
func provideUserStore(db *db.DB, enc encrypt.Encrypter, config config.Config) core.UserStore {
|
||||
// create the user store with encryption iff the user
|
||||
// encryption feature flag is enabled.
|
||||
//
|
||||
// why not enable by default? because the user table is
|
||||
// accessed on every http request and we are unsure what,
|
||||
// if any performance implications user table encryption
|
||||
// may have on the system.
|
||||
//
|
||||
// it is very possible there are zero material performance
|
||||
// implications, however, if there is a performance regression
|
||||
// we could look at implementing in-memory lru caching, which
|
||||
// we already employ in other areas of the software.
|
||||
if config.Database.EncryptUserTable {
|
||||
logrus.Debugln("main: database encryption enabled for user table")
|
||||
users := user.New(db, enc)
|
||||
metric.UserCount(users)
|
||||
return users
|
||||
}
|
||||
|
||||
noenc, _ := encrypt.New("")
|
||||
users := user.New(db, noenc)
|
||||
metric.UserCount(users)
|
||||
return users
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// Code generated by Wire. DO NOT EDIT.
|
||||
|
||||
//go:generate wire
|
||||
//go:generate go run github.com/google/wire/cmd/wire
|
||||
//+build !wireinject
|
||||
|
||||
package main
|
||||
|
@ -25,6 +25,7 @@ import (
|
|||
"github.com/drone/drone/store/secret"
|
||||
"github.com/drone/drone/store/secret/global"
|
||||
"github.com/drone/drone/store/step"
|
||||
"github.com/drone/drone/store/template"
|
||||
"github.com/drone/drone/trigger"
|
||||
cron2 "github.com/drone/drone/trigger/cron"
|
||||
)
|
||||
|
@ -44,7 +45,11 @@ func InitializeApplication(config2 config.Config) (application, error) {
|
|||
if err != nil {
|
||||
return application{}, err
|
||||
}
|
||||
userStore := provideUserStore(db)
|
||||
encrypter, err := provideEncrypter(config2)
|
||||
if err != nil {
|
||||
return application{}, err
|
||||
}
|
||||
userStore := provideUserStore(db, encrypter, config2)
|
||||
renewer := token.Renewer(refresher, userStore)
|
||||
commitService := commit.New(client, renewer)
|
||||
cronStore := cron.New(db)
|
||||
|
@ -60,7 +65,8 @@ func InitializeApplication(config2 config.Config) (application, error) {
|
|||
coreCanceler := canceler.New(buildStore, corePubsub, repositoryStore, scheduler, stageStore, statusService, stepStore, userStore, webhookSender)
|
||||
fileService := provideContentService(client, renewer)
|
||||
configService := provideConfigPlugin(client, fileService, config2)
|
||||
convertService := provideConvertPlugin(client, config2)
|
||||
templateStore := template.New(db)
|
||||
convertService := provideConvertPlugin(client, config2, templateStore)
|
||||
validateService := provideValidatePlugin(config2)
|
||||
triggerer := trigger.New(coreCanceler, configService, convertService, commitService, statusService, buildStore, scheduler, repositoryStore, userStore, validateService, webhookSender)
|
||||
cronScheduler := cron2.New(commitService, cronStore, repositoryStore, userStore, triggerer)
|
||||
|
@ -70,10 +76,6 @@ func InitializeApplication(config2 config.Config) (application, error) {
|
|||
logStore := provideLogStore(db, config2)
|
||||
logStream := livelog.New()
|
||||
netrcService := provideNetrcService(client, renewer, config2)
|
||||
encrypter, err := provideEncrypter(config2)
|
||||
if err != nil {
|
||||
return application{}, err
|
||||
}
|
||||
secretStore := secret.New(db, encrypter)
|
||||
globalSecretStore := global.New(db, encrypter)
|
||||
buildManager := manager.New(buildStore, configService, convertService, corePubsub, logStore, logStream, netrcService, repositoryStore, scheduler, secretStore, globalSecretStore, statusService, stageStore, stepStore, system, userStore, webhookSender)
|
||||
|
@ -93,7 +95,7 @@ func InitializeApplication(config2 config.Config) (application, error) {
|
|||
syncer := provideSyncer(repositoryService, repositoryStore, userStore, batcher, config2)
|
||||
transferer := transfer.New(repositoryStore, permStore)
|
||||
userService := user.New(client, renewer)
|
||||
server := api.New(buildStore, commitService, cronStore, corePubsub, globalSecretStore, hookService, logStore, coreLicense, licenseService, organizationService, permStore, repositoryStore, repositoryService, scheduler, secretStore, stageStore, stepStore, statusService, session, logStream, syncer, system, transferer, triggerer, userStore, userService, webhookSender)
|
||||
server := api.New(buildStore, commitService, cronStore, corePubsub, globalSecretStore, hookService, logStore, coreLicense, licenseService, organizationService, permStore, repositoryStore, repositoryService, scheduler, secretStore, stageStore, stepStore, statusService, session, logStream, syncer, system, templateStore, transferer, triggerer, userStore, userService, webhookSender)
|
||||
admissionService := provideAdmissionPlugin(client, organizationService, userService, config2)
|
||||
hookParser := parser.New(client)
|
||||
coreLinker := linker.New(client)
|
||||
|
|
|
@ -77,7 +77,7 @@ type BuildStore interface {
|
|||
LatestBranches(context.Context, int64) ([]*Build, error)
|
||||
|
||||
// LatestPulls returns the latest builds from the
|
||||
// datastore by pull requeset.
|
||||
// datastore by pull request.
|
||||
LatestPulls(context.Context, int64) ([]*Build, error)
|
||||
|
||||
// LatestDeploys returns the latest builds from the
|
||||
|
|
25
core/step.go
25
core/step.go
|
@ -19,17 +19,20 @@ import "context"
|
|||
type (
|
||||
// Step represents an individual step in the stage.
|
||||
Step struct {
|
||||
ID int64 `json:"id"`
|
||||
StageID int64 `json:"step_id"`
|
||||
Number int `json:"number"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Error string `json:"error,omitempty"`
|
||||
ErrIgnore bool `json:"errignore,omitempty"`
|
||||
ExitCode int `json:"exit_code"`
|
||||
Started int64 `json:"started,omitempty"`
|
||||
Stopped int64 `json:"stopped,omitempty"`
|
||||
Version int64 `json:"version"`
|
||||
ID int64 `json:"id"`
|
||||
StageID int64 `json:"step_id"`
|
||||
Number int `json:"number"`
|
||||
Name string `json:"name"`
|
||||
Status string `json:"status"`
|
||||
Error string `json:"error,omitempty"`
|
||||
ErrIgnore bool `json:"errignore,omitempty"`
|
||||
ExitCode int `json:"exit_code"`
|
||||
Started int64 `json:"started,omitempty"`
|
||||
Stopped int64 `json:"stopped,omitempty"`
|
||||
Version int64 `json:"version"`
|
||||
DependsOn []string `json:"depends_on,omitempty"`
|
||||
Image string `json:"image,omitempty"`
|
||||
Detached bool `json:"detached,omitempty"`
|
||||
}
|
||||
|
||||
// StepStore persists build step information to storage.
|
||||
|
|
79
core/template.go
Normal file
79
core/template.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
// Copyright 2019 Drone IO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
errTemplateNameInvalid = errors.New("No Template Name Provided")
|
||||
errTemplateDataInvalid = errors.New("No Template Data Provided")
|
||||
)
|
||||
|
||||
type (
|
||||
TemplateArgs struct {
|
||||
Kind string
|
||||
Load string
|
||||
Data map[string]interface{}
|
||||
}
|
||||
|
||||
Template struct {
|
||||
Id int64 `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Namespace string `json:"namespace,omitempty"`
|
||||
Data string `json:"data,omitempty"`
|
||||
Created int64 `json:"created,omitempty"`
|
||||
Updated int64 `json:"updated,omitempty"`
|
||||
}
|
||||
|
||||
// TemplateStore manages repository templates.
|
||||
TemplateStore interface {
|
||||
// List returns template list at org level
|
||||
List(ctx context.Context, namespace string) ([]*Template, error)
|
||||
|
||||
// ListAll returns templates list from the datastore.
|
||||
ListAll(ctx context.Context) ([]*Template, error)
|
||||
|
||||
// Find returns a template from the datastore.
|
||||
Find(ctx context.Context, id int64) (*Template, error)
|
||||
|
||||
// FindName returns a template from the data store
|
||||
FindName(ctx context.Context, name string, namespace string) (*Template, error)
|
||||
|
||||
// Create persists a new template to the datastore.
|
||||
Create(ctx context.Context, template *Template) error
|
||||
|
||||
// Update persists an updated template to the datastore.
|
||||
Update(ctx context.Context, template *Template) error
|
||||
|
||||
// Delete deletes a template from the datastore.
|
||||
Delete(ctx context.Context, template *Template) error
|
||||
}
|
||||
)
|
||||
|
||||
// Validate validates the required fields and formats.
|
||||
func (s *Template) Validate() error {
|
||||
switch {
|
||||
case len(s.Name) == 0:
|
||||
return errTemplateNameInvalid
|
||||
case len(s.Data) == 0:
|
||||
return errTemplateDataInvalid
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@ package core
|
|||
|
||||
import "context"
|
||||
|
||||
// Transferer handles transfering repository ownership from one
|
||||
// Transferer handles transferring repository ownership from one
|
||||
// user to another user account.
|
||||
type Transferer interface {
|
||||
Transfer(ctx context.Context, user *User) error
|
||||
|
|
17
core/user.go
17
core/user.go
|
@ -47,6 +47,16 @@ type (
|
|||
Hash string `json:"-"`
|
||||
}
|
||||
|
||||
// UserParams defines user query parameters.
|
||||
UserParams struct {
|
||||
// Sort instructs the system to sort by Login if true,
|
||||
// else sort by primary key.
|
||||
Sort bool
|
||||
|
||||
Page int64
|
||||
Size int64
|
||||
}
|
||||
|
||||
// UserStore defines operations for working with users.
|
||||
UserStore interface {
|
||||
// Find returns a user from the datastore.
|
||||
|
@ -61,6 +71,9 @@ type (
|
|||
// List returns a list of users from the datastore.
|
||||
List(context.Context) ([]*User, error)
|
||||
|
||||
// ListRange returns a range of users from the datastore.
|
||||
ListRange(context.Context, UserParams) ([]*User, error)
|
||||
|
||||
// Create persists a new user to the datastore.
|
||||
Create(context.Context, *User) error
|
||||
|
||||
|
@ -88,13 +101,13 @@ type (
|
|||
}
|
||||
)
|
||||
|
||||
// Validate valides the user and returns an error if the
|
||||
// Validate validates the user and returns an error if the
|
||||
// validation fails.
|
||||
func (u *User) Validate() error {
|
||||
switch {
|
||||
case !govalidator.IsByteLength(u.Login, 1, 50):
|
||||
return errUsernameLen
|
||||
case !govalidator.Matches(u.Login, "^[a-zA-Z0-9_-]+$"):
|
||||
case !govalidator.Matches(u.Login, "^[.a-zA-Z0-9_-]+$"):
|
||||
return errUsernameChar
|
||||
default:
|
||||
return nil
|
||||
|
|
|
@ -39,6 +39,10 @@ func TestValidateUser(t *testing.T) {
|
|||
user: &User{Login: "octocat"},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
user: &User{Login: "octocat.with.dot"},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
user: &User{Login: "OctO-Cat_01"},
|
||||
err: nil,
|
||||
|
|
|
@ -1 +1,57 @@
|
|||
This directory contains docker compose files used by the core development team for local development and testing purposes only. These are not part of the core distribution, and are not intended for use outside of the core development team. We are not currently accepting changes or additions to these files.
|
||||
# Local development
|
||||
|
||||
This directory contains Docker compose files used by the core development team for local development and testing purposes only. These are not part of the core distribution, and are not intended for use outside of the core development team. We are not currently accepting changes or additions to these files.
|
||||
|
||||
## Running a Drone deployment locally using Github
|
||||
|
||||
At the end of this guide you will have a drone server and a drone runner that is hooked up to your Github account. This will allow you to trigger builds on your Github repositories.
|
||||
|
||||
### (prerequisite) Setup a Github oauth application
|
||||
|
||||
Create an oauth application here <https://github.com/settings/developers>
|
||||
|
||||
The most important entry is setting the `Authorization callback URL` you can set this to `http://localhost:8080/login`
|
||||
|
||||
You will also need to create a client secret for the application.
|
||||
|
||||
Now you have the `DRONE_GITHUB_CLIENT_ID` and `DRONE_GITHUB_CLIENT_SECRET`
|
||||
|
||||
### (prerequisite) Setup Ngrok
|
||||
|
||||
Ngrok allows us to send the webhooks from Github to our local Drone setup.
|
||||
|
||||
Follow the guide here <https://dashboard.ngrok.com/get-started/setup>
|
||||
|
||||
### Running Drone
|
||||
|
||||
+ Move into the `drone/docker/compose/drone-github` folder.
|
||||
|
||||
+ Run Ngrok against port `8080` it will run in the foreground.
|
||||
|
||||
``` bash
|
||||
./ngrok http 8080
|
||||
```
|
||||
|
||||
Take note of the forwarding hostname this is your `DRONE_SERVER_PROXY_HOST` EG
|
||||
|
||||
``` bash
|
||||
Forwarding http://c834c33asdde.ngrok.io -> http://localhost:8080
|
||||
```
|
||||
|
||||
+ You will want to edit the Docker compose file `docker-compose.yml` updating in the following entries.
|
||||
|
||||
``` bash
|
||||
DRONE_SERVER_PROXY_HOST=${DRONE_SERVER_PROXY_HOST} # taken from Ngrok
|
||||
DRONE_GITHUB_CLIENT_ID=${DRONE_GITHUB_CLIENT_ID} # taken from your Github oauth application
|
||||
DRONE_GITHUB_CLIENT_SECRET=${DRONE_GITHUB_CLIENT_SECRET} # taken from your Github oauth application
|
||||
```
|
||||
|
||||
NB for `DRONE_SERVER_PROXY_HOST` do not include http/https.
|
||||
|
||||
+ Run docker compose
|
||||
|
||||
``` bash
|
||||
docker-compose up
|
||||
```
|
||||
|
||||
Now you can go access the Drone ui at <http://localhost:8080>
|
||||
|
|
|
@ -24,5 +24,6 @@ services:
|
|||
- DRONE_RPC_HOST=drone
|
||||
- DRONE_RPC_PROTO=http
|
||||
- DRONE_RPC_SECRET=bea26a2221fd8090ea38720fc445eca6
|
||||
- DRONE_TMATE_ENABLED=true
|
||||
volumes:
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
|
|
6
go.mod
6
go.mod
|
@ -15,12 +15,12 @@ require (
|
|||
github.com/dgrijalva/jwt-go v3.2.0+incompatible
|
||||
github.com/drone/drone-go v1.4.1-0.20201109202657-b9e58bbbcf27
|
||||
github.com/drone/drone-runtime v1.1.1-0.20200623162453-61e33e2cab5d
|
||||
github.com/drone/drone-ui v0.0.0-20201110214517-ac1349fcc19c
|
||||
github.com/drone/drone-ui v0.0.0-20210623224836-9a5c77ebfdb7
|
||||
github.com/drone/drone-yaml v1.2.4-0.20200326192514-6f4d6dfb39e4
|
||||
github.com/drone/envsubst v1.0.3-0.20200709231038-aa43e1c1a629
|
||||
github.com/drone/go-license v1.0.2
|
||||
github.com/drone/go-login v1.0.4-0.20190311170324-2a4df4f242a2
|
||||
github.com/drone/go-scm v1.8.0
|
||||
github.com/drone/go-scm v1.15.1
|
||||
github.com/drone/signal v1.0.0
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/go-chi/chi v3.3.3+incompatible
|
||||
|
@ -29,7 +29,7 @@ require (
|
|||
github.com/go-sql-driver/mysql v1.4.0
|
||||
github.com/golang/mock v1.3.1
|
||||
github.com/google/go-cmp v0.4.0
|
||||
github.com/google/go-jsonnet v0.16.0
|
||||
github.com/google/go-jsonnet v0.17.0
|
||||
github.com/google/wire v0.2.1
|
||||
github.com/gorhill/cronexpr v0.0.0-20140423231348-a557574d6c02 // indirect
|
||||
github.com/gosimple/slug v1.3.0
|
||||
|
|
49
go.sum
49
go.sum
|
@ -92,6 +92,42 @@ github.com/drone/drone-ui v0.0.0-20200701170131-2b91a041998b h1:8VfphhR5arTUOFGf
|
|||
github.com/drone/drone-ui v0.0.0-20200701170131-2b91a041998b/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20201110214517-ac1349fcc19c h1:RHVLOVo6vC/p3i64XMQ6lcURQCeqUbg+7vyhCAy8hq0=
|
||||
github.com/drone/drone-ui v0.0.0-20201110214517-ac1349fcc19c/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210318043635-d92124ef8c6b h1:SR3ORKKtSGLA2oGHBr6tP+KaHRB7JSveYreZVxnfQgA=
|
||||
github.com/drone/drone-ui v0.0.0-20210318043635-d92124ef8c6b/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210318051923-d744fdf178d7 h1:KpTwlg8z0xcT7UZXTzK8G0r5+1CeXKkglZwsg6wHuK4=
|
||||
github.com/drone/drone-ui v0.0.0-20210318051923-d744fdf178d7/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210318173335-90cdf440f023 h1:xy7suHSQ4wEuOa8EnCmBpuMEXcfG66QJxY0rdDG9w3c=
|
||||
github.com/drone/drone-ui v0.0.0-20210318173335-90cdf440f023/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210318184040-660cf374c83a h1:b36lw0bXDWRB8miPIA59SUgpV+mTvoUX7otADm8SwyQ=
|
||||
github.com/drone/drone-ui v0.0.0-20210318184040-660cf374c83a/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210318190358-0fd3dd080c5b h1:CfVtYTmPVUm5x2UTUvFF8NtQMYWwlVWz9OiRfxuiLQg=
|
||||
github.com/drone/drone-ui v0.0.0-20210318190358-0fd3dd080c5b/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210318211453-780e11c45d95 h1:8JsUeiL9slNUbMUYGINI0gi2owD/0JnzKgNrv6EmxHY=
|
||||
github.com/drone/drone-ui v0.0.0-20210318211453-780e11c45d95/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210319172440-b892bff542b5 h1:6mjZNWxqVKkBt1Pc2ChdMFOzwa8+7oTVX4dTLnEx4dA=
|
||||
github.com/drone/drone-ui v0.0.0-20210319172440-b892bff542b5/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210322195809-43fc5b050223 h1:lyWHV4jHKzF8kKBrEXjlZDTyuuXuAQ2BabeURGt5hLo=
|
||||
github.com/drone/drone-ui v0.0.0-20210322195809-43fc5b050223/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210324203842-aaae3627e294 h1:ifbOWfDF/4zNxXW69f4XL06D7aA7cdp5U0moNNh60nw=
|
||||
github.com/drone/drone-ui v0.0.0-20210324203842-aaae3627e294/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210331233327-772f24b7f519 h1:zEPxQwLA/dI6sQ9htLPWcDT+EKms09w4TSAYk1lOQiA=
|
||||
github.com/drone/drone-ui v0.0.0-20210331233327-772f24b7f519/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210427231613-96a9f6e17fb7 h1:EUvu5J51N2diuFqLjFTiu65m0EK0TlLD66qDyi43tVE=
|
||||
github.com/drone/drone-ui v0.0.0-20210427231613-96a9f6e17fb7/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210505020539-1b93fc25c7d8 h1:mIFBOdP8Tif/4li4bmiVjqp6vbxMpTHOuZR80eypm6A=
|
||||
github.com/drone/drone-ui v0.0.0-20210505020539-1b93fc25c7d8/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210512200715-d96f1e26d448 h1:skfTTwMRWSSi3Dv5NrpU8mJn7faccG5q+lqiBQikLiw=
|
||||
github.com/drone/drone-ui v0.0.0-20210512200715-d96f1e26d448/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210602131102-d9e6fc7e8e68 h1:MFiB2sySRfQfdGyzCw6ii45IVgNXS1Ho+YmKxdmp9eU=
|
||||
github.com/drone/drone-ui v0.0.0-20210602131102-d9e6fc7e8e68/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210616003421-c6bb64fb3c3b h1:w7zIfuX1sv491AC0hGQzbtGQ/IXfiQmLbBKVrIuEC+0=
|
||||
github.com/drone/drone-ui v0.0.0-20210616003421-c6bb64fb3c3b/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210616023721-d11e2b9d4c32 h1:pnrIQX6PDZCXs8uh6kvWrjXwhw3ZSg6D1Yp6W+Pe5Pw=
|
||||
github.com/drone/drone-ui v0.0.0-20210616023721-d11e2b9d4c32/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210623033012-76a6768a4050 h1:VjS2w8DtcdOajM11UYc2bzlqXONna5MnyToMWO6uCJk=
|
||||
github.com/drone/drone-ui v0.0.0-20210623033012-76a6768a4050/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-ui v0.0.0-20210623224836-9a5c77ebfdb7 h1:gqEVIHEIdzBtoeL0fE33Ba+OD1QARTGRZTw4jrGOxCk=
|
||||
github.com/drone/drone-ui v0.0.0-20210623224836-9a5c77ebfdb7/go.mod h1:NBtVWW7NNJpD9+huMD/5TAE1db2nrEh0i35/9Rf1MPI=
|
||||
github.com/drone/drone-yaml v1.2.4-0.20200326192514-6f4d6dfb39e4 h1:XsstoCeXC2t8lA9OLTdoFwckaptqahxwjCWsenySfX8=
|
||||
github.com/drone/drone-yaml v1.2.4-0.20200326192514-6f4d6dfb39e4/go.mod h1:QsqliFK8nG04AHFN9tTn9XJomRBQHD4wcejWW1uz/10=
|
||||
github.com/drone/envsubst v1.0.3-0.20200709231038-aa43e1c1a629 h1:rIaZZalMGGPb2cU/+ypuggZ8aMlpa17RUlJUtsMv8pw=
|
||||
|
@ -110,6 +146,12 @@ github.com/drone/go-scm v1.7.2-0.20201111225713-c0438b46084b h1:ivLeFPmHN+9sLMVA
|
|||
github.com/drone/go-scm v1.7.2-0.20201111225713-c0438b46084b/go.mod h1:lXwfbyrIJwFFME5TpzavkwO2T5X8yBK6t6cve7g91x0=
|
||||
github.com/drone/go-scm v1.8.0 h1:kDHu38a11loKf6uaBu75TmY1YPwsSaZdseET738Oy0o=
|
||||
github.com/drone/go-scm v1.8.0/go.mod h1:lXwfbyrIJwFFME5TpzavkwO2T5X8yBK6t6cve7g91x0=
|
||||
github.com/drone/go-scm v1.9.0 h1:KgaGREXA7Ncu4ccdnk7p93hJwE8B8GLaBHfRprwtUCE=
|
||||
github.com/drone/go-scm v1.9.0/go.mod h1:lXwfbyrIJwFFME5TpzavkwO2T5X8yBK6t6cve7g91x0=
|
||||
github.com/drone/go-scm v1.15.0 h1:yBO6lcCeegbEuEaH0QUvJmBVQS/RpYKzuzULHHMT2A4=
|
||||
github.com/drone/go-scm v1.15.0/go.mod h1:lXwfbyrIJwFFME5TpzavkwO2T5X8yBK6t6cve7g91x0=
|
||||
github.com/drone/go-scm v1.15.1 h1:35m/CcHkYjQ4BlOM7rIIwrki6uDUbUH+Kkb9rv6om3M=
|
||||
github.com/drone/go-scm v1.15.1/go.mod h1:lXwfbyrIJwFFME5TpzavkwO2T5X8yBK6t6cve7g91x0=
|
||||
github.com/drone/signal v1.0.0 h1:NrnM2M/4yAuU/tXs6RP1a1ZfxnaHwYkd0kJurA1p6uI=
|
||||
github.com/drone/signal v1.0.0/go.mod h1:S8t92eFT0g4WUgEc/LxG+LCuiskpMNsG0ajAMGnyZpc=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
|
@ -158,6 +200,8 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
|||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-jsonnet v0.16.0 h1:Nb4EEOp+rdeGGyB1rQ5eisgSAqrTnhf9ip+X6lzZbY0=
|
||||
github.com/google/go-jsonnet v0.16.0/go.mod h1:sOcuej3UW1vpPTZOr8L7RQimqai1a57bt5j22LzGZCw=
|
||||
github.com/google/go-jsonnet v0.17.0 h1:/9NIEfhK1NQRKl3sP2536b2+x5HnZMdql7x3yK/l8JY=
|
||||
github.com/google/go-jsonnet v0.17.0/go.mod h1:sOcuej3UW1vpPTZOr8L7RQimqai1a57bt5j22LzGZCw=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf h1:+RRA9JqSOZFfKrOeqr2z77+8R2RKyh8PG66dcu1V0ck=
|
||||
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
|
||||
github.com/google/wire v0.2.1 h1:TYj4Z2qjqxa2ufb34UJqVeO9aznL+i0fLO6TqThKZ7Y=
|
||||
|
@ -337,6 +381,7 @@ github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi
|
|||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
|
@ -396,6 +441,7 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
|||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
|
@ -414,6 +460,7 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR
|
|||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478 h1:l5EDrHhldLYb3ZRHDUhXF7Om7MvYXnkV9/iQNo1lX6g=
|
||||
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b h1:uwuIcX0g4Yl1NC5XAz37xsr2lTtcqevgzYNVt49waME=
|
||||
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890 h1:uESlIz09WIHT2I+pasSXcpLYqYK8wHcdCetU3VuMBJE=
|
||||
|
@ -444,11 +491,13 @@ golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9 h1:1/DFK4b7JH8DmkqhUk48onnSf
|
|||
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642 h1:B6caxRw+hozq68X2MY7jEpZh/cr4/aHLv9xU8Kkadrw=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
|
||||
|
|
|
@ -40,6 +40,7 @@ import (
|
|||
"github.com/drone/drone/handler/api/repos/sign"
|
||||
globalsecrets "github.com/drone/drone/handler/api/secrets"
|
||||
"github.com/drone/drone/handler/api/system"
|
||||
"github.com/drone/drone/handler/api/template"
|
||||
"github.com/drone/drone/handler/api/user"
|
||||
"github.com/drone/drone/handler/api/user/remote"
|
||||
"github.com/drone/drone/handler/api/users"
|
||||
|
@ -82,6 +83,7 @@ func New(
|
|||
stream core.LogStream,
|
||||
syncer core.Syncer,
|
||||
system *core.System,
|
||||
template core.TemplateStore,
|
||||
transferer core.Transferer,
|
||||
triggerer core.Triggerer,
|
||||
users core.UserStore,
|
||||
|
@ -111,6 +113,7 @@ func New(
|
|||
Stream: stream,
|
||||
Syncer: syncer,
|
||||
System: system,
|
||||
Template: template,
|
||||
Transferer: transferer,
|
||||
Triggerer: triggerer,
|
||||
Users: users,
|
||||
|
@ -143,6 +146,7 @@ type Server struct {
|
|||
Stream core.LogStream
|
||||
Syncer core.Syncer
|
||||
System *core.System
|
||||
Template core.TemplateStore
|
||||
Transferer core.Transferer
|
||||
Triggerer core.Triggerer
|
||||
Users core.UserStore
|
||||
|
@ -353,6 +357,16 @@ func (s Server) Handler() http.Handler {
|
|||
r.With(acl.CheckMembership(s.Orgs, true)).Delete("/{namespace}/{name}", globalsecrets.HandleDelete(s.Globals))
|
||||
})
|
||||
|
||||
r.Route("/templates", func(r chi.Router) {
|
||||
r.With(acl.CheckMembership(s.Orgs, false)).Get("/", template.HandleListAll(s.Template))
|
||||
r.With(acl.CheckMembership(s.Orgs, true)).Post("/", template.HandleCreate(s.Template))
|
||||
r.With(acl.CheckMembership(s.Orgs, false)).Get("/{namespace}", template.HandleList(s.Template))
|
||||
r.With(acl.CheckMembership(s.Orgs, false)).Get("/{namespace}/{name}", template.HandleFind(s.Template))
|
||||
r.With(acl.CheckMembership(s.Orgs, true)).Put("/{namespace}/{name}", template.HandleUpdate(s.Template))
|
||||
r.With(acl.CheckMembership(s.Orgs, true)).Patch("/{namespace}/{name}", template.HandleUpdate(s.Template))
|
||||
r.With(acl.CheckMembership(s.Orgs, true)).Delete("/{namespace}/{name}", template.HandleDelete(s.Template))
|
||||
})
|
||||
|
||||
r.Route("/system", func(r chi.Router) {
|
||||
r.Use(acl.AuthorizeAdmin)
|
||||
// r.Get("/license", system.HandleLicense())
|
||||
|
|
27
handler/api/template/all.go
Normal file
27
handler/api/template/all.go
Normal file
|
@ -0,0 +1,27 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/render"
|
||||
)
|
||||
|
||||
// HandleListAll returns an http.HandlerFunc that writes a json-encoded
|
||||
// list of templates to the response body.
|
||||
func HandleListAll(templateStore core.TemplateStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
list, err := templateStore.ListAll(r.Context())
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
render.JSON(w, list, 200)
|
||||
}
|
||||
}
|
84
handler/api/template/all_test.go
Normal file
84
handler/api/template/all_test.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
"github.com/drone/drone/mock"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
var (
|
||||
dummyTemplate = &core.Template{
|
||||
Name: "my_template",
|
||||
Data: "my_data",
|
||||
Created: 1,
|
||||
Updated: 2,
|
||||
Namespace: "my_org",
|
||||
}
|
||||
dummyTemplateList = []*core.Template{
|
||||
dummyTemplate,
|
||||
}
|
||||
)
|
||||
|
||||
func TestHandleAll(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
templates := mock.NewMockTemplateStore(controller)
|
||||
templates.EXPECT().ListAll(gomock.Any()).Return(dummyTemplateList, nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleListAll(templates).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusOK; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleAll_TemplateListErr(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
templates := mock.NewMockTemplateStore(controller)
|
||||
templates.EXPECT().ListAll(gomock.Any()).Return(nil, errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleListAll(templates).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusNotFound; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), errors.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
54
handler/api/template/create.go
Normal file
54
handler/api/template/create.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/render"
|
||||
)
|
||||
|
||||
type templateInput struct {
|
||||
Name string `json:"name"`
|
||||
Data string `json:"data"`
|
||||
Namespace string `json:"namespace"`
|
||||
}
|
||||
|
||||
// HandleCreate returns an http.HandlerFunc that processes http
|
||||
// requests to create a new template.
|
||||
func HandleCreate(templateStore core.TemplateStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
in := new(templateInput)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
t := &core.Template{
|
||||
Name: in.Name,
|
||||
Data: in.Data,
|
||||
Namespace: in.Namespace,
|
||||
}
|
||||
|
||||
err = t.Validate()
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = templateStore.Create(r.Context(), t)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, t, 200)
|
||||
}
|
||||
}
|
154
handler/api/template/create_test.go
Normal file
154
handler/api/template/create_test.go
Normal file
|
@ -0,0 +1,154 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
"github.com/drone/drone/mock"
|
||||
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestHandleCreate(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
templates := mock.NewMockTemplateStore(controller)
|
||||
templates.EXPECT().Create(gomock.Any(), gomock.Any()).Return(nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyTemplate)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleCreate(templates).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusOK; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleCreate_ValidationErrorName(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
c := new(chi.Context)
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(&core.Template{Name: "", Data: "my_data"})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleCreate(nil).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusBadRequest; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := &errors.Error{}, &errors.Error{Message: "No Template Name Provided"}
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleCreate_ValidationErrorData(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
c := new(chi.Context)
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(&core.Template{Name: "my_template", Data: ""})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleCreate(nil).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusBadRequest; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := &errors.Error{}, &errors.Error{Message: "No Template Data Provided"}
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleCreate_BadRequest(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
c := new(chi.Context)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleCreate(nil).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusBadRequest; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := &errors.Error{}, &errors.Error{Message: "EOF"}
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleCreate_CreateError(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
templates := mock.NewMockTemplateStore(controller)
|
||||
templates.EXPECT().Create(gomock.Any(), gomock.Any()).Return(errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyTemplate)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleCreate(templates).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusInternalServerError; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), errors.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
38
handler/api/template/delete.go
Normal file
38
handler/api/template/delete.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/render"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
// HandleDelete returns an http.HandlerFunc that processes http
|
||||
// requests to delete a template.
|
||||
func HandleDelete(template core.TemplateStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
name = chi.URLParam(r, "name")
|
||||
namespace = chi.URLParam(r, "namespace")
|
||||
)
|
||||
s, err := template.FindName(r.Context(), name, namespace)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
err = template.Delete(r.Context(), s)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusNoContent)
|
||||
}
|
||||
}
|
105
handler/api/template/delete_test.go
Normal file
105
handler/api/template/delete_test.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
"github.com/drone/drone/mock"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestHandleDelete(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := mock.NewMockTemplateStore(controller)
|
||||
template.EXPECT().FindName(gomock.Any(), dummyTemplate.Name, dummyTemplate.Namespace).Return(dummyTemplate, nil)
|
||||
template.EXPECT().Delete(gomock.Any(), dummyTemplate).Return(nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("name", "my_template")
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleDelete(template).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusNoContent; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleDelete_TemplateNotFound(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := mock.NewMockTemplateStore(controller)
|
||||
template.EXPECT().FindName(gomock.Any(), dummyTemplate.Name, dummyTemplate.Namespace).Return(nil, errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("name", "my_template")
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleDelete(template).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusNotFound; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), errors.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleDelete_DeleteError(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := mock.NewMockTemplateStore(controller)
|
||||
template.EXPECT().FindName(gomock.Any(), dummyTemplate.Name, dummyTemplate.Namespace).Return(dummyTemplate, nil)
|
||||
template.EXPECT().Delete(gomock.Any(), dummyTemplate).Return(errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("name", "my_template")
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleDelete(template).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusInternalServerError; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), errors.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
33
handler/api/template/find.go
Normal file
33
handler/api/template/find.go
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/render"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
// HandleFind returns an http.HandlerFunc that writes json-encoded
|
||||
// template details to the the response body.
|
||||
func HandleFind(templateStore core.TemplateStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
name = chi.URLParam(r, "name")
|
||||
namespace = chi.URLParam(r, "namespace")
|
||||
)
|
||||
template, err := templateStore.FindName(r.Context(), name, namespace)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
render.JSON(w, template, 200)
|
||||
}
|
||||
}
|
74
handler/api/template/find_test.go
Normal file
74
handler/api/template/find_test.go
Normal file
|
@ -0,0 +1,74 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
"github.com/drone/drone/mock"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestHandleFind(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := mock.NewMockTemplateStore(controller)
|
||||
template.EXPECT().FindName(gomock.Any(), dummyTemplate.Name, dummyTemplate.Namespace).Return(dummyTemplate, nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("name", "my_template")
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleFind(template).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusOK; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleFind_TemplateNotFound(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := mock.NewMockTemplateStore(controller)
|
||||
template.EXPECT().FindName(gomock.Any(), dummyTemplate.Name, dummyTemplate.Namespace).Return(nil, errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("name", "my_template")
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleFind(template).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusNotFound; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), errors.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
30
handler/api/template/list.go
Normal file
30
handler/api/template/list.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/render"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
// HandleList returns an http.HandlerFunc that writes a json-encoded
|
||||
// list of templates to the response body by namespace
|
||||
func HandleList(templateStore core.TemplateStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
namespace := chi.URLParam(r, "namespace")
|
||||
list, err := templateStore.List(r.Context(), namespace)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
render.JSON(w, list, 200)
|
||||
}
|
||||
}
|
70
handler/api/template/list_test.go
Normal file
70
handler/api/template/list_test.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
package template
|
||||
|
||||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
"github.com/drone/drone/mock"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestHandleList(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
templates := mock.NewMockTemplateStore(controller)
|
||||
templates.EXPECT().List(gomock.Any(), dummyTemplate.Namespace).Return(dummyTemplateList, nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleList(templates).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusOK; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleList_TemplateListErr(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
templates := mock.NewMockTemplateStore(controller)
|
||||
templates.EXPECT().List(gomock.Any(), dummyTemplate.Namespace).Return(nil, errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", nil)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleList(templates).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusNotFound; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), errors.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
56
handler/api/template/none.go
Normal file
56
handler/api/template/none.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
// Copyright 2019 Drone IO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/render"
|
||||
)
|
||||
|
||||
var notImplemented = func(w http.ResponseWriter, r *http.Request) {
|
||||
render.NotImplemented(w, render.ErrNotImplemented)
|
||||
}
|
||||
|
||||
func HandleCreate(store core.TemplateStore) http.HandlerFunc {
|
||||
return notImplemented
|
||||
}
|
||||
|
||||
func HandleUpdate(core.TemplateStore) http.HandlerFunc {
|
||||
return notImplemented
|
||||
}
|
||||
|
||||
func HandleDelete(core.TemplateStore) http.HandlerFunc {
|
||||
return notImplemented
|
||||
}
|
||||
|
||||
func HandleFind(core.TemplateStore) http.HandlerFunc {
|
||||
return notImplemented
|
||||
}
|
||||
|
||||
func HandleList(core.TemplateStore) http.HandlerFunc {
|
||||
return notImplemented
|
||||
}
|
||||
|
||||
func HandleListAll(core.TemplateStore) http.HandlerFunc {
|
||||
return notImplemented
|
||||
}
|
||||
|
||||
func HandleAll(core.TemplateStore) http.HandlerFunc {
|
||||
return notImplemented
|
||||
}
|
67
handler/api/template/update.go
Normal file
67
handler/api/template/update.go
Normal file
|
@ -0,0 +1,67 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/render"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
)
|
||||
|
||||
type templateUpdate struct {
|
||||
Data *string `json:"data"`
|
||||
Namespace *string `json:"namespace"`
|
||||
}
|
||||
|
||||
// HandleUpdate returns an http.HandlerFunc that processes http
|
||||
// requests to update a template.
|
||||
func HandleUpdate(templateStore core.TemplateStore) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
var (
|
||||
name = chi.URLParam(r, "name")
|
||||
namespace = chi.URLParam(r, "namespace")
|
||||
)
|
||||
|
||||
in := new(templateUpdate)
|
||||
err := json.NewDecoder(r.Body).Decode(in)
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
s, err := templateStore.FindName(r.Context(), name, namespace)
|
||||
if err != nil {
|
||||
render.NotFound(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
if in.Data != nil {
|
||||
s.Data = *in.Data
|
||||
}
|
||||
if in.Namespace != nil {
|
||||
s.Namespace = *in.Namespace
|
||||
}
|
||||
|
||||
err = s.Validate()
|
||||
if err != nil {
|
||||
render.BadRequest(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = templateStore.Update(r.Context(), s)
|
||||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
return
|
||||
}
|
||||
|
||||
render.JSON(w, s, 200)
|
||||
}
|
||||
}
|
148
handler/api/template/update_test.go
Normal file
148
handler/api/template/update_test.go
Normal file
|
@ -0,0 +1,148 @@
|
|||
// Copyright 2019 Drone.IO Inc. All rights reserved.
|
||||
// Use of this source code is governed by the Drone Non-Commercial License
|
||||
// that can be found in the LICENSE file.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package template
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
"github.com/drone/drone/mock"
|
||||
|
||||
"github.com/go-chi/chi"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
)
|
||||
|
||||
func TestHandleUpdate(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := mock.NewMockTemplateStore(controller)
|
||||
template.EXPECT().FindName(gomock.Any(), dummyTemplate.Name, dummyTemplate.Namespace).Return(dummyTemplate, nil)
|
||||
template.EXPECT().Update(gomock.Any(), gomock.Any()).Return(nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("name", "my_template")
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(dummyTemplate)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleUpdate(template).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusOK; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleUpdate_ValidationErrorData(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := mock.NewMockTemplateStore(controller)
|
||||
template.EXPECT().FindName(gomock.Any(), dummyTemplate.Name, dummyTemplate.Namespace).Return(&core.Template{Name: "my_template"}, nil)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("name", "my_template")
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(&core.Secret{Data: ""})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleUpdate(template).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusBadRequest; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), &errors.Error{Message: "No Template Data Provided"}
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleUpdate_TemplateNotFound(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := mock.NewMockTemplateStore(controller)
|
||||
template.EXPECT().FindName(gomock.Any(), dummyTemplate.Name, dummyTemplate.Namespace).Return(nil, errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("name", "my_template")
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(&core.Secret{})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleUpdate(template).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusNotFound; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), errors.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleUpdate_UpdateError(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := mock.NewMockTemplateStore(controller)
|
||||
template.EXPECT().FindName(gomock.Any(), dummyTemplate.Name, dummyTemplate.Namespace).Return(&core.Template{Name: "my_template"}, nil)
|
||||
template.EXPECT().Update(gomock.Any(), gomock.Any()).Return(errors.ErrNotFound)
|
||||
|
||||
c := new(chi.Context)
|
||||
c.URLParams.Add("name", "my_template")
|
||||
c.URLParams.Add("namespace", "my_org")
|
||||
|
||||
in := new(bytes.Buffer)
|
||||
json.NewEncoder(in).Encode(&core.Template{Data: "my_data"})
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
r := httptest.NewRequest("GET", "/", in)
|
||||
r = r.WithContext(
|
||||
context.WithValue(context.Background(), chi.RouteCtxKey, c),
|
||||
)
|
||||
|
||||
HandleUpdate(template).ServeHTTP(w, r)
|
||||
if got, want := w.Code, http.StatusInternalServerError; want != got {
|
||||
t.Errorf("Want response code %d, got %d", want, got)
|
||||
}
|
||||
|
||||
got, want := new(errors.Error), errors.ErrNotFound
|
||||
json.NewDecoder(w.Body).Decode(got)
|
||||
if diff := cmp.Diff(got, want); len(diff) != 0 {
|
||||
t.Errorf(diff)
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@ func init() {
|
|||
logrus.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
func TestResitoryList(t *testing.T) {
|
||||
func TestRepositoryList(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
|
@ -63,7 +63,7 @@ func TestResitoryList(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestResitoryListErr(t *testing.T) {
|
||||
func TestRepositoryListErr(t *testing.T) {
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ func HandleSync(syncer core.Syncer, repos core.RepositoryStore) http.HandlerFunc
|
|||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
viewer, _ := request.UserFrom(r.Context())
|
||||
|
||||
// performs asyncrhonous account synchronization.
|
||||
// performs asynchronous account synchronization.
|
||||
// this requires long polling to determine when the
|
||||
// sync is complete.
|
||||
if r.FormValue("async") == "true" {
|
||||
|
@ -57,7 +57,7 @@ func HandleSync(syncer core.Syncer, repos core.RepositoryStore) http.HandlerFunc
|
|||
if err != nil {
|
||||
render.InternalError(w, err)
|
||||
logger.FromRequest(r).WithError(err).
|
||||
Warnln("api: cannot synchrnoize account")
|
||||
Warnln("api: cannot synchronize account")
|
||||
} else {
|
||||
render.JSON(w, list, 200)
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ func HandleCreate(users core.UserStore, service core.UserService, sender core.We
|
|||
if err != nil {
|
||||
render.ErrorCode(w, err, 400)
|
||||
logger.FromRequest(r).WithError(err).
|
||||
Errorln("api: invlid username")
|
||||
Errorln("api: invalid username")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ func TestCreate(t *testing.T) {
|
|||
t.Errorf("Want user login %s, got %s", want, got)
|
||||
}
|
||||
if in.Hash == "" {
|
||||
t.Errorf("Expect user secert generated")
|
||||
t.Errorf("Expect user secret generated")
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
|
|
@ -35,7 +35,7 @@ func HandleFind(users core.UserStore) http.HandlerFunc {
|
|||
if err != nil {
|
||||
// the client can make a user request by providing
|
||||
// the user id as opposed to the username. If a
|
||||
// numberic user id is provided as input, attempt
|
||||
// numeric user id is provided as input, attempt
|
||||
// to lookup the user by id.
|
||||
if id, _ := strconv.ParseInt(login, 10, 64); id != 0 {
|
||||
user, err = users.Find(r.Context(), id)
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,283 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Drone</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Inconsolata|PT+Mono|Roboto+Mono|Source+Code+Pro|Ubuntu+Mono" rel="stylesheet">
|
||||
<link href="/static2/style.css" rel="stylesheet" />
|
||||
</head>
|
||||
<body>
|
||||
<div>
|
||||
<nav>
|
||||
<div class="center">
|
||||
|
||||
<svg class="logo" 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 326.6 103.1" xml:space="preserve">
|
||||
<style type="text/css">
|
||||
.st0{fill:#FFFFFF;}
|
||||
</style>
|
||||
<g>
|
||||
<g>
|
||||
<g>
|
||||
<desc>Created with Sketch.</desc>
|
||||
<g id="Landing_4_">
|
||||
<g id="logos_4_" transform="translate(-151.000000, -3990.000000)">
|
||||
<g id="drone-logo-back-with-text_4_" transform="translate(151.000000, 3986.000000)">
|
||||
<g id="Group-4_4_">
|
||||
<path id="DRONE_4_" class="st0" d="M109.6,28.6H126c5.8,0,10.3,1.5,13.3,4.4c3,2.9,4.5,7.7,4.5,14.1c0,6.2-1.5,10.7-4.5,13.7
|
||||
c-3,2.9-7.4,4.4-13.3,4.4h-16.4V28.6z M124.6,57c1.9,0,3.4-0.3,4.6-0.8c1.2-0.5,2.1-1.5,2.7-3c0.6-1.4,0.9-3.5,0.9-6.1
|
||||
c0-2.7-0.3-4.8-0.9-6.3s-1.5-2.6-2.6-3.2s-2.8-0.9-4.7-0.9h-4.3V57H124.6z M154.1,28.6h19.1c4.3,0,7.6,1.2,9.8,3.5
|
||||
s3.3,5.5,3.3,9.5c0,2.4-0.6,4.6-1.8,6.5c-1.2,1.9-2.9,3.3-4.9,4.4c0.4,0.3,0.8,0.7,1.1,1.2c0.3,0.5,0.6,1.1,1,2l4.2,9.6
|
||||
h-11.1l-3.9-8.8c-0.3-0.7-0.7-1.2-1.1-1.5c-0.4-0.3-1.1-0.4-1.8-0.4h-3v10.7h-10.7V28.6z M170.4,46.3c1.6,0,2.8-0.4,3.6-1.2
|
||||
c0.9-0.8,1.3-2,1.3-3.5c0-3.2-1.5-4.8-4.6-4.8h-6v9.6H170.4z M213.3,65.8c-6.2,0-10.8-1.5-14-4.5c-3.1-3-4.7-7.8-4.7-14.2
|
||||
c0-6.7,1.6-11.5,4.7-14.5s7.8-4.5,14-4.5c6.2,0,10.9,1.5,14,4.5c3.1,3,4.7,7.8,4.7,14.5c0,6.4-1.6,11.2-4.7,14.2
|
||||
C224.1,64.3,219.5,65.8,213.3,65.8z M213.3,56.7c2.7,0,4.7-0.8,5.9-2.3s1.8-4,1.8-7.4c0-3.6-0.6-6.1-1.8-7.6
|
||||
c-1.2-1.5-3.2-2.3-6-2.3s-4.8,0.8-6,2.3c-1.2,1.5-1.8,4.1-1.8,7.6c0,3.4,0.6,5.8,1.8,7.4S210.6,56.7,213.3,56.7z M242.3,28.6
|
||||
h9.1L265.2,48V28.6h10.7v36.6h-9.2L253,45.9v19.3h-10.7V28.6z M287.4,28.6h27.8v8.2h-17.1v6h15v8.3h-15v6h17.1v8.2h-27.8
|
||||
V28.6z"/>
|
||||
<g id="Group-3_4_" transform="translate(0.000000, 4.000000)">
|
||||
<path id="Combined-Shape_4_" class="st0" d="M16.7,9.3l-0.4,0.4L30.8,24c-2,3.2-3.2,7.1-3.2,11.5c0,12.3,9.1,20.5,20.7,20.5
|
||||
c4.3,0,8.3-1.1,11.6-3.2l14.6,14.5c-7.5,9.9-19.5,16.1-33,16.1C18.5,83.4,0,65.6,0,42.4C0,28.5,6.5,16.6,16.7,9.3z
|
||||
M24.8,3.9C30.2,1.4,36.2,0,42.5,0c22.7,0,41.2,17.8,41.2,41c0,6.4-1.4,12.4-3.9,17.7l-13-13c2-3.2,3.2-7.1,3.2-11.5
|
||||
c0-12.3-9.1-20.5-20.6-20.5c-4.3,0-8.3,1.1-11.5,3.2L24.8,3.9z M49.6,46.3c-6.9,0-12.4-4.9-12.4-12.4s5.5-12.4,12.4-12.4
|
||||
S62,26.6,62,34S56.5,46.3,49.6,46.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M167.1,92.8c-1.2,1.1-2.8,1.7-4.9,1.7c-2.5,0-5.1-1.4-6.1-3.7l-0.2,3.3h-1.6V67.3h1.9v11.3
|
||||
c1-2.1,3.6-3.6,6.2-3.6c2.1,0,3.8,0.7,5,1.9c2,1.9,2.9,4.8,2.9,7.8C170.1,88,169.1,90.9,167.1,92.8z M166.1,78.5
|
||||
c-1-1-2.2-1.6-4-1.6c-1.7,0-3,0.6-3.9,1.4c-1.7,1.6-2.3,3.7-2.3,6.5c0,2.6,0.7,4.8,2.4,6.4c0.9,0.9,2.1,1.5,3.8,1.5
|
||||
c1.6,0,2.7-0.5,3.7-1.3c1.7-1.5,2.4-4,2.4-6.6C168.2,82.4,167.6,80,166.1,78.5z"/>
|
||||
<path class="st0" d="M178.2,98c-0.9,2.3-2.4,3.8-5,3.8c-0.7,0-1.7-0.1-2.3-0.3v-1.6c0.7,0.1,1.5,0.2,2.3,0.2
|
||||
c1.8,0,2.8-1.2,3.4-2.7l1.2-3l-7.6-18.8h2l6.5,16.4l6.2-16.4h2L178.2,98z"/>
|
||||
<path class="st0" d="M205.9,94V82.1c0-2.2-0.7-3.6-3.2-3.6c-2.8,0-4,3-4,5.3V94h-4.6V67.3h4.6v9.5c1.1-1.6,3.3-2.5,5.3-2.5
|
||||
c4.1,0,6.5,2.9,6.5,6.9V94H205.9z"/>
|
||||
<path class="st0" d="M228.2,94.3c-2,0-3.1-1.3-3.3-2.7c-0.9,1.6-3.1,2.9-5.8,2.9c-4.6,0-7-2.9-7-6c0-3.7,2.8-5.8,6.5-6l5.7-0.4
|
||||
v-1.2c0-1.8-0.6-3-3.3-3c-2.1,0-3.4,1-3.5,2.7h-4.5c0.3-4.3,3.7-6.3,8-6.3c3.3,0,6.1,1,7.2,3.9c0.5,1.2,0.6,2.6,0.6,3.9v7.1
|
||||
c0,0.9,0.3,1.2,1.1,1.2c0.3,0,0.6-0.1,0.6-0.1v3.4C229.7,94.1,229.3,94.3,228.2,94.3z M224.3,85.5l-4.9,0.4
|
||||
c-1.4,0.1-2.8,1-2.8,2.5c0,1.5,1.3,2.4,2.7,2.4c2.9,0,4.9-1.6,4.9-4.4V85.5z"/>
|
||||
<path class="st0" d="M241.9,78.9c-3.3,0-5,2.3-5,5.4V94h-4.7V74.8h3.9l0.4,2.9c0.9-2.2,3.2-3.1,5.4-3.1c0.5,0,1,0,1.4,0.1v4.4
|
||||
C242.9,79,242.4,78.9,241.9,78.9z"/>
|
||||
<path class="st0" d="M256.3,94V82.2c0-2.3-0.7-3.6-3.2-3.6c-1.6,0-2.7,1-3.3,2.4c-0.7,1.5-0.6,3.5-0.6,5.1V94h-4.6V74.8h3.9
|
||||
l0.3,2.5c1.1-2,3.4-3,5.7-3c4.1,0,6.5,2.9,6.5,6.9V94H256.3z"/>
|
||||
<path class="st0" d="M280.3,85.8h-12.9c0,1.5,0.5,2.9,1.4,3.8c0.7,0.6,1.6,1.2,2.8,1.2c1.3,0,2.1-0.3,2.8-0.9
|
||||
c0.4-0.4,0.7-0.9,0.9-1.6h4.4c-0.1,1.1-0.9,2.7-1.6,3.6c-1.6,1.9-4,2.7-6.5,2.7c-2.6,0-4.6-0.9-6.1-2.4c-1.9-1.8-3-4.6-3-7.7
|
||||
c0-3.1,0.9-5.8,2.8-7.7c1.4-1.5,3.5-2.4,6.1-2.4c2.8,0,5.4,1.1,7,3.6c1.4,2.1,1.7,4.3,1.7,6.7C280.4,84.5,280.3,85.4,280.3,85.8z
|
||||
M274.6,79.1c-0.6-0.7-1.6-1.1-2.9-1.1c-1.4,0-2.6,0.6-3.2,1.5c-0.7,0.9-1,1.7-1,3h8.3C275.7,81,275.3,79.9,274.6,79.1z"/>
|
||||
<path class="st0" d="M295.8,92.3c-1.6,1.6-4,2.2-6.6,2.2c-2.4,0-4.6-0.7-6.2-2.2c-1.1-1.1-2-2.7-2-4.5h4.3c0,0.9,0.4,1.8,1,2.3
|
||||
c0.7,0.6,1.6,0.9,2.9,0.9c1.6,0,3.9-0.3,3.9-2.4c0-1.1-0.7-1.8-1.9-2c-1.7-0.3-3.6-0.4-5.3-0.7c-2.6-0.6-4.4-2.7-4.4-5.1
|
||||
c0-2,0.8-3.3,2-4.3c1.4-1.2,3.4-1.9,5.8-1.9c2.3,0,4.6,0.7,6,2.3c1,1.1,1.7,2.6,1.7,4h-4.4c0-0.7-0.3-1.3-0.8-1.8
|
||||
c-0.6-0.6-1.6-0.9-2.5-0.9c-0.7,0-1.3,0-2,0.3c-0.8,0.3-1.5,1-1.5,2c0,1.4,1.2,1.8,2.2,1.9c1.7,0.2,2.2,0.3,4.1,0.6
|
||||
c3,0.5,5.3,2.4,5.3,5.4C297.4,89.9,296.8,91.3,295.8,92.3z"/>
|
||||
<path class="st0" d="M313.1,92.3c-1.6,1.6-4,2.2-6.6,2.2c-2.4,0-4.6-0.7-6.2-2.2c-1.1-1.1-2-2.7-2-4.5h4.3c0,0.9,0.4,1.8,1,2.3
|
||||
c0.7,0.6,1.6,0.9,2.9,0.9c1.6,0,3.9-0.3,3.9-2.4c0-1.1-0.7-1.8-1.9-2c-1.7-0.3-3.6-0.4-5.3-0.7c-2.6-0.6-4.4-2.7-4.4-5.1
|
||||
c0-2,0.8-3.3,2-4.3c1.4-1.2,3.4-1.9,5.8-1.9c2.3,0,4.6,0.7,6,2.3c1,1.1,1.7,2.6,1.7,4h-4.4c0-0.7-0.3-1.3-0.8-1.8
|
||||
c-0.6-0.6-1.6-0.9-2.5-0.9c-0.7,0-1.3,0-2,0.3c-0.8,0.3-1.5,1-1.5,2c0,1.4,1.2,1.8,2.2,1.9c1.7,0.2,2.2,0.3,4.1,0.6
|
||||
c3,0.5,5.3,2.4,5.3,5.4C314.8,89.9,314.1,91.3,313.1,92.3z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
<path class="st0" d="M321.2,25.2v3.5h-0.5v-3.5h-1.2v-0.5h2.9v0.5H321.2z"/>
|
||||
<path class="st0" d="M326.1,28.7v-3.4l-1.2,3.3h-0.4l-1.2-3.3v3.4h-0.5v-4h0.7l1.2,3.3l1.2-3.3h0.7v4H326.1z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://cloud.drone.io">Cloud</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://drone.io/enterprise">Enterprise</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://docs.drone.io">Docs</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://plugins.drone.io">Plugins</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://discourse.drone.io">Support</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="/login" class="login">Sign In</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<header>
|
||||
<div class="center">
|
||||
<div class="illustration"></div>
|
||||
|
||||
<h1>Continuous Integration,<br/>Free for the Open Source Community</h1>
|
||||
<h2>Drone Cloud is a free Continuous Integration service for the Open Source community,
|
||||
powered by blazing fast bare-metal servers.
|
||||
</h2>
|
||||
<a href="/login" class="button">Get Started</a>
|
||||
<a href="https://docs.drone.io" class="button button-outline">Read the Docs</a>
|
||||
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<section style="padding-bottom: 0px;">
|
||||
<div class="center header">
|
||||
<h2>Accelerating Open Source Development</h2>
|
||||
</div>
|
||||
</section>
|
||||
<section class="columns-3 cards">
|
||||
<div class="center">
|
||||
<div>
|
||||
<h3>Multiple Architectures</h3>
|
||||
<p>Our goal is to upstream all the things! In order to do that with the diverse Arm ecosystem, we're providing gobs of CI/CD infrastructure.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Blazing Fast, Bare Metal Servers</h3>
|
||||
<p>Drone Cloud runs your Continuous Integration workloads on blazing fast, bare metal infrastructure sponsored by Equinix.</p>
|
||||
</div>
|
||||
<div>
|
||||
<h3>100% free for Open Source</h3>
|
||||
<p>Drone Cloud would not be possible without our generous sponsors. If you are interested in becoming a sponsor please <a href="mailto:hello@drone.io">contact us.</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
<section class="columns-2 thanks-packet">
|
||||
<div class="center">
|
||||
<div>
|
||||
<svg 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 103.4 94.2" xml:space="preserve">
|
||||
<rect y="65.5" width="103.4" height="0.5"></rect>
|
||||
<g>
|
||||
<path d="M20.2,82.9h2.2l3.7,5.4l3.6-5.4H32v11.4h-2.1v-8.1l-3.8,5.4h-0.1l-3.7-5.3v8.1h-2.1V82.9z"></path>
|
||||
<path d="M36.2,82.9H45v1.8h-6.7v3h6v1.8h-6v3h6.8v1.8h-8.9L36.2,82.9z"></path>
|
||||
<path d="M52.2,84.7h-3.8v-1.9h9.7v1.9h-3.8v9.5h-2.1V84.7z"></path>
|
||||
<path d="M64.1,82.8h2l5.2,11.4h-2.2l-1.2-2.7h-5.6L61,94.2h-2.1L64.1,82.8z M67.1,89.7L65,85.2l-2,4.5H67.1z"></path>
|
||||
<path d="M74.8,82.9h2.1v9.5h6.3v1.8h-8.4L74.8,82.9z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<polygon points="0,38.6 0,49.2 9.4,49.2 9.4,47.8 1.5,47.8 1.5,44.4 6.6,44.4 6.6,43 1.5,43 1.5,40 9.1,40 9.1,38.6 "></polygon>
|
||||
<path d="M41.8,45c0,1.9-1.2,3.1-3.1,3.1c-1.8,0-2.9-1.3-2.9-3.1v-6.3h-1.5V45c0,2.9,2.1,4.4,4.4,4.4c3.5,0,4.6-2.4,4.6-4.4v-6.4
|
||||
h-1.5V45z"></path>
|
||||
<rect x="51.8" y="38.6" width="1.5" height="10.5"></rect>
|
||||
<polygon points="71.4,38.6 71.4,46.9 63.9,38.6 62.4,38.6 62.4,49.2 63.9,49.2 63.9,40.8 71.4,49.2 72.9,49.2 72.9,38.6 "></polygon>
|
||||
<rect x="82" y="38.6" width="1.5" height="10.5"></rect>
|
||||
<polygon points="100.8,38.6 97.3,42.4 93.9,38.6 91.9,38.6 96.2,43.5 90.9,49.2 92.8,49.2 97.2,44.5 101.3,49.2 103.4,49.2
|
||||
98.3,43.5 102.7,38.6 "></polygon>
|
||||
<path d="M20.9,38.2c-3.1,0-5.6,2.4-5.6,5.7v0c0,3.3,2.5,5.6,5.6,5.6c0.8,0,1.7-0.2,2.5-0.6l0.9,1l1.8,0l-1.5-1.7
|
||||
c1.2-0.9,2-2.5,2-4.4v0C26.5,40.5,24.1,38.2,20.9,38.2 M25,43.9c0,1.5-0.5,2.5-1.4,3.3l-0.8-0.9l-1.8,0l1.4,1.7
|
||||
c-0.4,0.2-1,0.3-1.5,0.3c-2.3,0-4.1-1.8-4.1-4.3l0,0c0-2.5,1.7-4.3,4-4.3C23.2,39.5,25,41.3,25,43.9L25,43.9z"></path>
|
||||
</g>
|
||||
<g>
|
||||
<polygon points="52.5,0 48.2,1.5 48.2,24 45.4,23 45.4,2.5 36.8,5.5 36.8,20 33.9,19 33.9,6.5 31,7.5 31,21.1 39.6,24.1 39.6,7.5
|
||||
42.5,6.5 42.5,25.1 51.1,28.1 51.1,3.5 52.5,3 54,3.5 54,28.1 62.5,25.1 62.5,6.5 65.4,7.5 65.4,24.1 74,21.1 74,7.5 71.1,6.5
|
||||
71.1,19 68.3,20 68.3,5.5 59.7,2.5 59.7,23 56.8,24 56.8,1.5 "></polygon>
|
||||
<path d="M79.5,20.1c1.4,0,2.6-1.2,2.6-2.6v0c0-1.4-1.1-2.6-2.6-2.6c-1.4,0-2.6,1.2-2.6,2.6v0C76.9,19,78,20.1,79.5,20.1 M79.5,19.8
|
||||
c-1.3,0-2.3-1-2.3-2.3v0c0-1.3,1-2.3,2.3-2.3c1.3,0,2.3,1,2.3,2.3v0C81.8,18.8,80.8,19.8,79.5,19.8 M78.4,18.8h0.7V18h0.4l0.6,0.8
|
||||
h0.8l-0.7-1c0.4-0.1,0.6-0.4,0.6-0.8c0-0.6-0.5-0.9-1.1-0.9h-1.3V18.8z M79.1,17.4v-0.7h0.6c0.3,0,0.5,0.1,0.5,0.4
|
||||
c0,0.2-0.2,0.4-0.5,0.4H79.1z"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h3>Thank you to our Infrastructure Sponsor</h3>
|
||||
<p>Drone Cloud is powered by donated infrastructure from Equinix Metal (<a href="https://metal.equinix.com/">metal.equinix.com</a>), the leading bare metal cloud for developers. With datacenters around the world, and a powerful API driven experience, Equinix is well known for bringing the experience of the cloud to bare metal.</p>
|
||||
<p>Want to run Drone on bare metal, but without the hassle? Equinix can help! <em>Use code "DRONE100" to get started with a $100 credit</em></p>
|
||||
<div><a class="button" href="https://metal.equinix.com/">Learn more about Equinix Metal</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="try-drone-panel">
|
||||
<div class="center">
|
||||
<div>
|
||||
<h3>Interested in running Drone on your own, private infrastructure?</h3>
|
||||
<div><a href="https://docs.drone.io/installation/">Download official Docker image</a></div>
|
||||
<div><small>and install Drone in minutes</small></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer>
|
||||
<div>
|
||||
<div class="logo"></div>
|
||||
<section>
|
||||
<h3>Company</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="mailto:hello@drone.io" target="_blank">Contact</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://github.com/drone/brand">Branding</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://drone.io/enterprise/license">License</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Products</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://drone.io/enterprise">Drone Enterprise</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://cloud.drone.io">Drone Cloud</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://autoscale.drone.io" target="_blank">Drone Autoscaler</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Developers</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://docs.drone.io" target="_blank">Documentation</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://plugins.drone.io" target="_blank">Plugins</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://discourse.drone.io" target="_blank">Support</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h3>Community</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<a href="https://github.com/drone" target="_blank">
|
||||
<svg aria-labelledby="simpleicons-github-icon" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title id="simpleicons-github-icon">GitHub icon</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"></path></svg>
|
||||
GitHub
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://twitter.com/droneio" target="_blank">
|
||||
<svg aria-labelledby="simpleicons-twitter-icon" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title id="simpleicons-twitter-icon">Twitter icon</title><path d="M23.954 4.569c-.885.389-1.83.654-2.825.775 1.014-.611 1.794-1.574 2.163-2.723-.951.555-2.005.959-3.127 1.184-.896-.959-2.173-1.559-3.591-1.559-2.717 0-4.92 2.203-4.92 4.917 0 .39.045.765.127 1.124C7.691 8.094 4.066 6.13 1.64 3.161c-.427.722-.666 1.561-.666 2.475 0 1.71.87 3.213 2.188 4.096-.807-.026-1.566-.248-2.228-.616v.061c0 2.385 1.693 4.374 3.946 4.827-.413.111-.849.171-1.296.171-.314 0-.615-.03-.916-.086.631 1.953 2.445 3.377 4.604 3.417-1.68 1.319-3.809 2.105-6.102 2.105-.39 0-.779-.023-1.17-.067 2.189 1.394 4.768 2.209 7.557 2.209 9.054 0 13.999-7.496 13.999-13.986 0-.209 0-.42-.015-.63.961-.689 1.8-1.56 2.46-2.548l-.047-.02z"></path></svg>
|
||||
Twitter
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://discourse.drone.io/" target="_blank">
|
||||
<svg aria-labelledby="simpleicons-discourse-icon" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title id="simpleicons-discourse-icon">Discourse icon</title><path d="M12.103 0C18.666 0 24 5.485 24 11.997c0 6.51-5.33 11.99-11.9 11.99L0 24V11.79C0 5.28 5.532 0 12.103 0zm.116 4.563c-2.593-.003-4.996 1.352-6.337 3.57-1.33 2.208-1.387 4.957-.148 7.22L4.4 19.61l4.794-1.074c2.745 1.225 5.965.676 8.136-1.39 2.17-2.054 2.86-5.228 1.737-7.997-1.135-2.778-3.84-4.59-6.84-4.585h-.008z"></path></svg>
|
||||
Discourse
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://gitter.im/drone/drone/" target="_blank">
|
||||
<svg aria-labelledby="simpleicons-slack-icon" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title id="simpleicons-slack-icon">Slack icon</title><path d="M9.879 10.995l1.035 3.085 3.205-1.074-1.035-3.074-3.205 1.08v-.017z"></path><path d="M18.824 14.055l-1.555.521.54 1.61c.218.65-.135 1.355-.786 1.574-.15.045-.285.067-.435.063-.511-.015-.976-.338-1.155-.849l-.54-1.607-3.21 1.073.539 1.608c.211.652-.135 1.358-.794 1.575-.15.048-.285.067-.435.064-.51-.015-.976-.34-1.156-.85l-.539-1.619-1.561.524c-.15.045-.285.061-.435.061-.511-.016-.976-.345-1.155-.855-.225-.66.135-1.364.78-1.575l1.56-.525L7.5 11.76l-1.551.525c-.141.048-.285.066-.428.064-.495-.016-.975-.338-1.141-.848-.209-.65.135-1.354.796-1.574l1.56-.52-.54-1.605c-.21-.654.136-1.359.796-1.575.659-.22 1.363.136 1.574.783l.539 1.608L12.3 7.544l-.54-1.605c-.209-.645.135-1.35.789-1.574.652-.211 1.359.135 1.575.791l.54 1.621 1.555-.51c.651-.219 1.356.135 1.575.779.218.654-.135 1.359-.784 1.575l-1.557.524 1.035 3.086 1.551-.516c.652-.211 1.358.135 1.575.795.22.66-.135 1.365-.779 1.574l-.011-.029zm4.171-5.356C20.52.456 16.946-1.471 8.699 1.005.456 3.479-1.471 7.051 1.005 15.301c2.475 8.245 6.046 10.17 14.296 7.694 8.245-2.475 10.17-6.046 7.694-14.296z"></path></svg>
|
||||
Chat
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
Before Width: | Height: | Size: 237 KiB |
|
@ -1,615 +0,0 @@
|
|||
html, body {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
font-family: -apple-system, system-ui, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
section {
|
||||
padding: 60px;
|
||||
}
|
||||
|
||||
footer {
|
||||
padding: 60px 30px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.center {
|
||||
max-width:900px;
|
||||
margin:0px auto;
|
||||
}
|
||||
|
||||
/*
|
||||
* Code
|
||||
*/
|
||||
|
||||
code {
|
||||
text-align:left;
|
||||
background: #222;
|
||||
color: #FFF;
|
||||
margin: 0px auto;
|
||||
font-family: 'Source Code Pro';
|
||||
font-size: 13px;
|
||||
line-height: 18px;
|
||||
border-radius: 5px;
|
||||
padding: 30px 0px;
|
||||
}
|
||||
|
||||
code div {
|
||||
white-space: pre;
|
||||
padding: 0px 30px;
|
||||
}
|
||||
|
||||
code span.group {
|
||||
background: #333;
|
||||
display: block;
|
||||
padding: 5px 0px;
|
||||
}
|
||||
|
||||
code span.c0 {
|
||||
color: #00E5FF;
|
||||
}
|
||||
|
||||
code span.c1 {
|
||||
color: #FF8A80;
|
||||
}
|
||||
|
||||
.code .center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.code p {
|
||||
max-width:500px;
|
||||
text-align:center;
|
||||
margin:30px auto;
|
||||
}
|
||||
|
||||
.code .grid {
|
||||
display: grid;
|
||||
grid-template-columns: 225px 450px 225px;
|
||||
grid-template-rows: auto auto auto;
|
||||
}
|
||||
|
||||
.code .grid code {
|
||||
grid-column: 2;
|
||||
grid-row-start: 1;
|
||||
grid-row-end: 4;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.info {
|
||||
background: #EEE;
|
||||
margin-right: 20px;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.info:first-of-type {
|
||||
grid-column: 1;
|
||||
grid-row: 1;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.info:nth-of-type(2) {
|
||||
grid-column: 3;
|
||||
grid-row: 2;
|
||||
margin-right: 0px;
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
.info:last-of-type {
|
||||
grid-column: 1;
|
||||
grid-row: 3;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Plugins
|
||||
*/
|
||||
|
||||
|
||||
.code.plugins .grid {
|
||||
margin-top: 80px;
|
||||
display: grid;
|
||||
grid-template-columns: 112.5px 112.5px 112.5px 112.5px 450px;
|
||||
grid-template-rows: auto auto auto auto;
|
||||
}
|
||||
|
||||
.code.plugins .grid code {
|
||||
grid-column: 5;
|
||||
grid-row-start: 1;
|
||||
grid-row-end: 5;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.code.plugins .logo {
|
||||
margin-right: 20px;
|
||||
padding: 15px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
|
||||
nav{
|
||||
text-align: right;
|
||||
height: 60px;
|
||||
background:#293a41;
|
||||
}
|
||||
|
||||
nav .center {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
nav ul {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
nav li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
nav li a {
|
||||
font-size: 15px;
|
||||
color: #FFF;
|
||||
text-decoration: none;
|
||||
margin-left: 15px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
nav .login {
|
||||
background:#00bfa6;
|
||||
color: #FFF;
|
||||
font-size: 13px;
|
||||
text-transform: uppercase;
|
||||
padding: 10px 20px;
|
||||
border-radius: 3px;
|
||||
-webkit-font-smoothing: unset;
|
||||
-moz-font-smoothing: unset;
|
||||
}
|
||||
|
||||
nav svg {
|
||||
fill: #FFF;
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Header Section
|
||||
*/
|
||||
|
||||
header {
|
||||
background-color: #293a41;
|
||||
color: #FFF;
|
||||
padding: 50px 20px;
|
||||
padding-bottom: 80px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
header .illustration {
|
||||
background-image: url("/static2/city-cloud.png");
|
||||
background-repeat: no-repeat;
|
||||
background-size: contain;
|
||||
float:right;
|
||||
height: 250px;
|
||||
padding: 20px;
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
header h1,
|
||||
header h2 {
|
||||
max-width: 500px;
|
||||
text-align: left;
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
header h1 {
|
||||
font-size: 28px;
|
||||
line-height: 32px;
|
||||
}
|
||||
|
||||
header h2 {
|
||||
margin-bottom: 50px;
|
||||
line-height: 20px;
|
||||
font-weight: normal;
|
||||
font-size: 16px;
|
||||
max-width: 400px;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
color: rgba(255,255,255,0.8);
|
||||
}
|
||||
|
||||
header a {
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
header a.button {
|
||||
background: #00bfa6;
|
||||
color: #FFF;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #00bfa6;
|
||||
padding: 10px 20px;
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
transition: all .15s ease;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
margin-right: 10px;
|
||||
|
||||
}
|
||||
|
||||
header a.button.button-outline {
|
||||
color: #00bfa6;
|
||||
background: none;
|
||||
border: 1px solid #00bfa6;
|
||||
}
|
||||
|
||||
header a.button:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
/*
|
||||
* Codeblock
|
||||
*/
|
||||
|
||||
div.logos {
|
||||
display: block;
|
||||
border-top: none;
|
||||
margin-top: 0px;
|
||||
text-align: left;
|
||||
white-space: unset;
|
||||
overflow: unset;
|
||||
}
|
||||
|
||||
.logos .logo {
|
||||
display: inline-block;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 50%;
|
||||
margin: 10px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.logos .logo img {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
/*
|
||||
* VCS Section
|
||||
*/
|
||||
|
||||
.vcs .center {
|
||||
text-align: center;
|
||||
padding: 60px 0px;
|
||||
}
|
||||
|
||||
.vcs strong {
|
||||
font-size: 1.17em;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
* Logo Section
|
||||
*/
|
||||
|
||||
.logos {
|
||||
border-top: 1px solid #EEE;
|
||||
text-align: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
margin-top: 100px;
|
||||
}
|
||||
|
||||
.logos img {
|
||||
margin: 0px 30px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quote Sections
|
||||
*/
|
||||
|
||||
.quote .center {
|
||||
display: grid;
|
||||
grid-template-columns: 110px auto;
|
||||
}
|
||||
|
||||
.quote blockquote {
|
||||
margin: 0px;
|
||||
padding: 15px;
|
||||
font-size: 18px;
|
||||
line-height: 26px;
|
||||
grid-column: 2;
|
||||
}
|
||||
|
||||
.quote img {
|
||||
grid-column: 1;
|
||||
padding-top: 5px;
|
||||
max-width: 75px;
|
||||
}
|
||||
|
||||
.quote cite {
|
||||
grid-column: 2;
|
||||
padding-top: 15px;
|
||||
padding-left: 15px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* 3-columns section
|
||||
*/
|
||||
|
||||
.columns-2 .center {
|
||||
display: grid;
|
||||
grid-template-columns: auto 400px;
|
||||
grid-gap: 30px;
|
||||
}
|
||||
|
||||
.columns-3 .center {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto auto;
|
||||
grid-gap: 30px;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
border: 1px solid #CCC;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/*
|
||||
* Cards
|
||||
*/
|
||||
|
||||
.center.header h2{
|
||||
font-size: 26px;
|
||||
font-weight: normal;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cards .center div {
|
||||
font-size: 14px;
|
||||
border: 1px solid #EEE;
|
||||
border-radius: 5px;
|
||||
padding: 15px 30px;
|
||||
box-shadow: 0 5px 15px rgba(50,50,93,.05), 0 5px 5px rgba(0,0,0,.02);
|
||||
}
|
||||
|
||||
.cards div h3 {
|
||||
font-size: 15px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Try Drone Today
|
||||
*/
|
||||
|
||||
.try-drone-panel {
|
||||
background:#293a41;
|
||||
color: #FFF;
|
||||
}
|
||||
|
||||
.try-drone-panel h3 {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.try-drone-panel a {
|
||||
color: #FFF;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
background: #00bfa6;
|
||||
padding: 10px 20px;
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
transition: all .15s ease;
|
||||
text-transform: uppercase;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.try-drone-panel a:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
.try-drone-panel small {
|
||||
font-style: italic;
|
||||
color: rgba(255,255,255,0.75);
|
||||
}
|
||||
|
||||
/*
|
||||
* Thanks to Packet
|
||||
*/
|
||||
|
||||
.thanks-packet {
|
||||
background-color: #eff3f5;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
padding-top: 40px;
|
||||
}
|
||||
|
||||
.thanks-packet .center > div:first-of-type {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.thanks-packet svg {
|
||||
max-width: 300px;
|
||||
margin-top: 45px;
|
||||
}
|
||||
|
||||
.thanks-packet .center > div:last-of-type {
|
||||
margin-top: 40px;
|
||||
}
|
||||
|
||||
.thanks-packet p {
|
||||
font-size: 13px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.thanks-packet em {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.thanks-packet a:visited,
|
||||
.thanks-packet a {
|
||||
color: #0564d7;
|
||||
}
|
||||
|
||||
.thanks-packet a.button {
|
||||
color: #00bfa6;
|
||||
text-decoration: none;
|
||||
border-radius: 3px;
|
||||
border: 1px solid #00bfa6;
|
||||
padding: 10px 20px;
|
||||
display: inline-block;
|
||||
margin-bottom: 10px;
|
||||
transition: all .15s ease;
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.thanks-packet a.button:hover {
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
|
||||
|
||||
|
||||
footer {
|
||||
padding: 0px;
|
||||
}
|
||||
footer > div {
|
||||
max-width: 900px;
|
||||
margin: 0px auto;
|
||||
display: flex;
|
||||
}
|
||||
footer section {
|
||||
margin-left: unset;
|
||||
}
|
||||
footer h3 {
|
||||
text-transform: uppercase;
|
||||
font-size: 13px;
|
||||
color: #455A64;
|
||||
}
|
||||
footer ul {
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
margin-top: 40px;
|
||||
list-style: none;
|
||||
}
|
||||
footer ul li {
|
||||
|
||||
}
|
||||
footer a {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
font-size: 14px;
|
||||
margin: 10px 0px;
|
||||
color: #455A64;
|
||||
text-decoration: none;
|
||||
}
|
||||
footer svg {
|
||||
fill: #455A64;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
footer .logo {
|
||||
flex: 1;
|
||||
}
|
||||
@media (max-width: 920px) {
|
||||
header {
|
||||
padding: 30px 30px;
|
||||
}
|
||||
|
||||
header .illustration {
|
||||
display: none;
|
||||
}
|
||||
nav {
|
||||
padding: 0px 30px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 720px) {
|
||||
footer > div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
footer .logo {
|
||||
flex: 1;
|
||||
}
|
||||
footer section {
|
||||
margin-left: 0px;
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
footer {
|
||||
padding-top: 30px;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
footer h3 {
|
||||
margin-top: 30px;
|
||||
}
|
||||
footer ul {
|
||||
margin-left: 30px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
nav a {
|
||||
display: none;
|
||||
}
|
||||
|
||||
nav a.login {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.thanks-packet.columns-2 {
|
||||
padding-top: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.thanks-packet.columns-2 > .center {
|
||||
grid-template-columns: none;
|
||||
display: grid;
|
||||
grid-template-rows: auto 400px;
|
||||
}
|
||||
|
||||
.thanks-packet .center > div:first-of-type {
|
||||
grid-row: 2;
|
||||
}
|
||||
.thanks-packet .center > div:last-of-type {
|
||||
grid-row: 1;
|
||||
padding: 0px 30px;
|
||||
padding-bottom:30px;
|
||||
}
|
||||
.thanks-packet .center > div:last-of-type > div {
|
||||
text-align: center;
|
||||
padding-top:20px;
|
||||
}
|
||||
|
||||
.thanks-packet svg {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.columns-3.cards .center {
|
||||
display: grid;
|
||||
grid-template-rows: auto auto auto;
|
||||
grid-template-columns: none !important;
|
||||
grid-gap: 30px;
|
||||
}
|
||||
}
|
|
@ -70,11 +70,13 @@ func HandleLogin(
|
|||
logger := logrus.WithField("login", account.Login)
|
||||
logger.Debugf("attempting authentication")
|
||||
|
||||
redirect := "/"
|
||||
user, err := users.FindLogin(ctx, account.Login)
|
||||
if err == sql.ErrNoRows {
|
||||
redirect = "/register"
|
||||
|
||||
user = &core.User{
|
||||
Login: account.Login,
|
||||
Email: account.Email,
|
||||
Avatar: account.Avatar,
|
||||
Admin: false,
|
||||
Machine: false,
|
||||
|
@ -140,7 +142,6 @@ func HandleLogin(
|
|||
}
|
||||
|
||||
user.Avatar = account.Avatar
|
||||
user.Email = account.Email
|
||||
user.Token = tok.Access
|
||||
user.Refresh = tok.Refresh
|
||||
user.LastLogin = time.Now().Unix()
|
||||
|
@ -149,7 +150,7 @@ func HandleLogin(
|
|||
}
|
||||
|
||||
// If the user account has never been synchronized we
|
||||
// execute the synchonrization logic.
|
||||
// execute the synchronization logic.
|
||||
if time.Unix(user.Synced, 0).Add(syncPeriod).Before(time.Now()) {
|
||||
user.Syncing = true
|
||||
}
|
||||
|
@ -162,17 +163,23 @@ func HandleLogin(
|
|||
logger.Errorf("cannot update user: %s", err)
|
||||
}
|
||||
|
||||
// launch the synchrnoization process in a go-routine,
|
||||
// launch the synchronization process in a go-routine,
|
||||
// since it is a long-running process and can take up
|
||||
// to a few minutes.
|
||||
if user.Syncing {
|
||||
go synchronize(ctx, syncer, user)
|
||||
}
|
||||
|
||||
// If the user account has not completed registration,
|
||||
// redirect to the registration form.
|
||||
if len(user.Email) == 0 && user.Created > 1619841600 {
|
||||
redirect = "/register"
|
||||
}
|
||||
|
||||
logger.Debugf("authentication successful")
|
||||
|
||||
session.Create(w, user)
|
||||
http.Redirect(w, r, "/", http.StatusSeeOther)
|
||||
http.Redirect(w, r, redirect, http.StatusSeeOther)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,15 +23,13 @@ import (
|
|||
|
||||
"github.com/drone/drone-ui/dist"
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/web/landingpage"
|
||||
)
|
||||
|
||||
func HandleIndex(host string, session core.Session, license core.LicenseService) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, r *http.Request) {
|
||||
user, _ := session.Get(r)
|
||||
if user == nil && host == "cloud.drone.io" && r.URL.Path == "/" {
|
||||
rw.Header().Set("Content-Type", "text/html; charset=UTF-8")
|
||||
rw.Write(landingpage.MustLookup("/index.html"))
|
||||
if user == nil && r.URL.Path == "/" {
|
||||
http.Redirect(rw, r, "/welcome", 303)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,8 @@ import (
|
|||
"net/http"
|
||||
|
||||
"github.com/drone/drone-ui/dist"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/web/landingpage"
|
||||
"github.com/drone/drone/handler/web/link"
|
||||
"github.com/drone/drone/logger"
|
||||
"github.com/drone/go-login/login"
|
||||
|
@ -128,15 +128,12 @@ func (s Server) Handler() http.Handler {
|
|||
r.Get("/logout", HandleLogout())
|
||||
r.Post("/logout", HandleLogout())
|
||||
|
||||
h2 := http.FileServer(landingpage.New())
|
||||
h := http.FileServer(dist.New())
|
||||
h = setupCache(h)
|
||||
r.Handle("/favicon.png", h)
|
||||
r.Handle("/js/*filepath", h)
|
||||
r.Handle("/css/*filepath", h)
|
||||
r.Handle("/img/*filepath", h)
|
||||
r.Handle("/images/*filepath", h)
|
||||
r.Handle("/static2/*filepath", h2)
|
||||
r.Handle("/manifest.json", h)
|
||||
r.Handle("/asset-manifest.json", h)
|
||||
r.Handle("/static/*filepath", h)
|
||||
r.NotFound(HandleIndex(s.Host, s.Session, s.Licenses))
|
||||
|
||||
return r
|
||||
|
|
|
@ -90,6 +90,11 @@ func (d *Datadog) do(ctx context.Context, unix int64) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
userList, _ := d.users.ListRange(ctx, core.UserParams{
|
||||
Sort: false,
|
||||
Page: 1,
|
||||
Size: 5,
|
||||
})
|
||||
tags := createTags(d.config)
|
||||
data := new(payload)
|
||||
data.Series = []series{
|
||||
|
@ -98,7 +103,7 @@ func (d *Datadog) do(ctx context.Context, unix int64) error {
|
|||
Points: [][]int64{[]int64{unix, users}},
|
||||
Type: "gauge",
|
||||
Host: d.system.Host,
|
||||
Tags: tags,
|
||||
Tags: append(tags, createInstallerTags(userList)...),
|
||||
},
|
||||
{
|
||||
Metric: "drone.repos",
|
||||
|
|
|
@ -18,6 +18,7 @@ import (
|
|||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/mock"
|
||||
"github.com/drone/drone/version"
|
||||
"github.com/golang/mock/gomock"
|
||||
|
@ -38,6 +39,7 @@ func TestDo(t *testing.T) {
|
|||
|
||||
users := mock.NewMockUserStore(controller)
|
||||
users.EXPECT().Count(gomock.Any()).Return(int64(10), nil)
|
||||
users.EXPECT().ListRange(gomock.Any(), gomock.Any()).Return([]*core.User{{Email: "jane@acme.com"}}, nil)
|
||||
|
||||
repos := mock.NewMockRepositoryStore(controller)
|
||||
repos.EXPECT().Count(gomock.Any()).Return(int64(20), nil)
|
||||
|
@ -73,7 +75,7 @@ var sample = `{
|
|||
"points": [[915148800, 10]],
|
||||
"type": "gauge",
|
||||
"host": "test.example.com",
|
||||
"tags": ["version:` + version.Version.String() + `","remote:github:cloud","scheduler:internal:agents","license:trial"]
|
||||
"tags": ["version:` + version.Version.String() + `","remote:github:cloud","scheduler:internal:agents","license:trial","installer:jane@acme.com"]
|
||||
},
|
||||
{
|
||||
"metric": "drone.repos",
|
||||
|
|
|
@ -17,6 +17,7 @@ package sink
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/version"
|
||||
)
|
||||
|
||||
|
@ -70,3 +71,19 @@ func createTags(config Config) []string {
|
|||
}
|
||||
return tags
|
||||
}
|
||||
|
||||
func createInstallerTags(users []*core.User) []string {
|
||||
var tags []string
|
||||
for _, user := range users {
|
||||
if user.Machine {
|
||||
continue
|
||||
}
|
||||
if len(user.Email) == 0 {
|
||||
continue
|
||||
}
|
||||
tag := fmt.Sprintf("installer:%s", user.Email)
|
||||
tags = append(tags, tag)
|
||||
break
|
||||
}
|
||||
return tags
|
||||
}
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
|
||||
package mock
|
||||
|
||||
//go:generate mockgen -package=mock -destination=mock_gen.go github.com/drone/drone/core Pubsub,Canceler,ConvertService,ValidateService,NetrcService,Renewer,HookParser,UserService,RepositoryService,CommitService,StatusService,HookService,FileService,Batcher,BuildStore,CronStore,LogStore,PermStore,SecretStore,GlobalSecretStore,StageStore,StepStore,RepositoryStore,UserStore,Scheduler,Session,OrganizationService,SecretService,RegistryService,ConfigService,Transferer,Triggerer,Syncer,LogStream,WebhookSender,LicenseService
|
||||
//go:generate mockgen -package=mock -destination=mock_gen.go github.com/drone/drone/core Pubsub,Canceler,ConvertService,ValidateService,NetrcService,Renewer,HookParser,UserService,RepositoryService,CommitService,StatusService,HookService,FileService,Batcher,BuildStore,CronStore,LogStore,PermStore,SecretStore,GlobalSecretStore,StageStore,StepStore,RepositoryStore,UserStore,Scheduler,Session,OrganizationService,SecretService,RegistryService,ConfigService,Transferer,Triggerer,Syncer,LogStream,WebhookSender,LicenseService,TemplateStore
|
||||
|
|
955
mock/mock_gen.go
955
mock/mock_gen.go
File diff suppressed because it is too large
Load diff
|
@ -6,35 +6,36 @@ package mockscm
|
|||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
scm "github.com/drone/go-scm/scm"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockContentService is a mock of ContentService interface
|
||||
// MockContentService is a mock of ContentService interface.
|
||||
type MockContentService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockContentServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockContentServiceMockRecorder is the mock recorder for MockContentService
|
||||
// MockContentServiceMockRecorder is the mock recorder for MockContentService.
|
||||
type MockContentServiceMockRecorder struct {
|
||||
mock *MockContentService
|
||||
}
|
||||
|
||||
// NewMockContentService creates a new mock instance
|
||||
// NewMockContentService creates a new mock instance.
|
||||
func NewMockContentService(ctrl *gomock.Controller) *MockContentService {
|
||||
mock := &MockContentService{ctrl: ctrl}
|
||||
mock.recorder = &MockContentServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockContentService) EXPECT() *MockContentServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Create mocks base method
|
||||
// Create mocks base method.
|
||||
func (m *MockContentService) Create(arg0 context.Context, arg1, arg2 string, arg3 *scm.ContentParams) (*scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Create", arg0, arg1, arg2, arg3)
|
||||
|
@ -43,14 +44,14 @@ func (m *MockContentService) Create(arg0 context.Context, arg1, arg2 string, arg
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Create indicates an expected call of Create
|
||||
// Create indicates an expected call of Create.
|
||||
func (mr *MockContentServiceMockRecorder) Create(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockContentService)(nil).Create), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// Delete mocks base method
|
||||
func (m *MockContentService) Delete(arg0 context.Context, arg1, arg2, arg3 string) (*scm.Response, error) {
|
||||
// Delete mocks base method.
|
||||
func (m *MockContentService) Delete(arg0 context.Context, arg1, arg2 string, arg3 *scm.ContentParams) (*scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Delete", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].(*scm.Response)
|
||||
|
@ -58,13 +59,13 @@ func (m *MockContentService) Delete(arg0 context.Context, arg1, arg2, arg3 strin
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Delete indicates an expected call of Delete
|
||||
// Delete indicates an expected call of Delete.
|
||||
func (mr *MockContentServiceMockRecorder) Delete(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockContentService)(nil).Delete), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// Find mocks base method
|
||||
// Find mocks base method.
|
||||
func (m *MockContentService) Find(arg0 context.Context, arg1, arg2, arg3 string) (*scm.Content, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Find", arg0, arg1, arg2, arg3)
|
||||
|
@ -74,13 +75,13 @@ func (m *MockContentService) Find(arg0 context.Context, arg1, arg2, arg3 string)
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// Find indicates an expected call of Find
|
||||
// Find indicates an expected call of Find.
|
||||
func (mr *MockContentServiceMockRecorder) Find(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockContentService)(nil).Find), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// List mocks base method
|
||||
// List mocks base method.
|
||||
func (m *MockContentService) List(arg0 context.Context, arg1, arg2, arg3 string, arg4 scm.ListOptions) ([]*scm.ContentInfo, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "List", arg0, arg1, arg2, arg3, arg4)
|
||||
|
@ -90,13 +91,13 @@ func (m *MockContentService) List(arg0 context.Context, arg1, arg2, arg3 string,
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// List indicates an expected call of List
|
||||
// List indicates an expected call of List.
|
||||
func (mr *MockContentServiceMockRecorder) List(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockContentService)(nil).List), arg0, arg1, arg2, arg3, arg4)
|
||||
}
|
||||
|
||||
// Update mocks base method
|
||||
// Update mocks base method.
|
||||
func (m *MockContentService) Update(arg0 context.Context, arg1, arg2 string, arg3 *scm.ContentParams) (*scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Update", arg0, arg1, arg2, arg3)
|
||||
|
@ -105,36 +106,36 @@ func (m *MockContentService) Update(arg0 context.Context, arg1, arg2 string, arg
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Update indicates an expected call of Update
|
||||
// Update indicates an expected call of Update.
|
||||
func (mr *MockContentServiceMockRecorder) Update(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockContentService)(nil).Update), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// MockGitService is a mock of GitService interface
|
||||
// MockGitService is a mock of GitService interface.
|
||||
type MockGitService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockGitServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockGitServiceMockRecorder is the mock recorder for MockGitService
|
||||
// MockGitServiceMockRecorder is the mock recorder for MockGitService.
|
||||
type MockGitServiceMockRecorder struct {
|
||||
mock *MockGitService
|
||||
}
|
||||
|
||||
// NewMockGitService creates a new mock instance
|
||||
// NewMockGitService creates a new mock instance.
|
||||
func NewMockGitService(ctrl *gomock.Controller) *MockGitService {
|
||||
mock := &MockGitService{ctrl: ctrl}
|
||||
mock.recorder = &MockGitServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockGitService) EXPECT() *MockGitServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CompareChanges mocks base method
|
||||
// CompareChanges mocks base method.
|
||||
func (m *MockGitService) CompareChanges(arg0 context.Context, arg1, arg2, arg3 string, arg4 scm.ListOptions) ([]*scm.Change, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CompareChanges", arg0, arg1, arg2, arg3, arg4)
|
||||
|
@ -144,13 +145,28 @@ func (m *MockGitService) CompareChanges(arg0 context.Context, arg1, arg2, arg3 s
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// CompareChanges indicates an expected call of CompareChanges
|
||||
// CompareChanges indicates an expected call of CompareChanges.
|
||||
func (mr *MockGitServiceMockRecorder) CompareChanges(arg0, arg1, arg2, arg3, arg4 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CompareChanges", reflect.TypeOf((*MockGitService)(nil).CompareChanges), arg0, arg1, arg2, arg3, arg4)
|
||||
}
|
||||
|
||||
// FindBranch mocks base method
|
||||
// CreateBranch mocks base method.
|
||||
func (m *MockGitService) CreateBranch(arg0 context.Context, arg1 string, arg2 *scm.CreateBranch) (*scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateBranch", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(*scm.Response)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// CreateBranch indicates an expected call of CreateBranch.
|
||||
func (mr *MockGitServiceMockRecorder) CreateBranch(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateBranch", reflect.TypeOf((*MockGitService)(nil).CreateBranch), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// FindBranch mocks base method.
|
||||
func (m *MockGitService) FindBranch(arg0 context.Context, arg1, arg2 string) (*scm.Reference, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindBranch", arg0, arg1, arg2)
|
||||
|
@ -160,13 +176,13 @@ func (m *MockGitService) FindBranch(arg0 context.Context, arg1, arg2 string) (*s
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// FindBranch indicates an expected call of FindBranch
|
||||
// FindBranch indicates an expected call of FindBranch.
|
||||
func (mr *MockGitServiceMockRecorder) FindBranch(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindBranch", reflect.TypeOf((*MockGitService)(nil).FindBranch), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// FindCommit mocks base method
|
||||
// FindCommit mocks base method.
|
||||
func (m *MockGitService) FindCommit(arg0 context.Context, arg1, arg2 string) (*scm.Commit, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindCommit", arg0, arg1, arg2)
|
||||
|
@ -176,13 +192,13 @@ func (m *MockGitService) FindCommit(arg0 context.Context, arg1, arg2 string) (*s
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// FindCommit indicates an expected call of FindCommit
|
||||
// FindCommit indicates an expected call of FindCommit.
|
||||
func (mr *MockGitServiceMockRecorder) FindCommit(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindCommit", reflect.TypeOf((*MockGitService)(nil).FindCommit), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// FindTag mocks base method
|
||||
// FindTag mocks base method.
|
||||
func (m *MockGitService) FindTag(arg0 context.Context, arg1, arg2 string) (*scm.Reference, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindTag", arg0, arg1, arg2)
|
||||
|
@ -192,13 +208,13 @@ func (m *MockGitService) FindTag(arg0 context.Context, arg1, arg2 string) (*scm.
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// FindTag indicates an expected call of FindTag
|
||||
// FindTag indicates an expected call of FindTag.
|
||||
func (mr *MockGitServiceMockRecorder) FindTag(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindTag", reflect.TypeOf((*MockGitService)(nil).FindTag), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ListBranches mocks base method
|
||||
// ListBranches mocks base method.
|
||||
func (m *MockGitService) ListBranches(arg0 context.Context, arg1 string, arg2 scm.ListOptions) ([]*scm.Reference, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListBranches", arg0, arg1, arg2)
|
||||
|
@ -208,13 +224,13 @@ func (m *MockGitService) ListBranches(arg0 context.Context, arg1 string, arg2 sc
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// ListBranches indicates an expected call of ListBranches
|
||||
// ListBranches indicates an expected call of ListBranches.
|
||||
func (mr *MockGitServiceMockRecorder) ListBranches(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListBranches", reflect.TypeOf((*MockGitService)(nil).ListBranches), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ListChanges mocks base method
|
||||
// ListChanges mocks base method.
|
||||
func (m *MockGitService) ListChanges(arg0 context.Context, arg1, arg2 string, arg3 scm.ListOptions) ([]*scm.Change, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListChanges", arg0, arg1, arg2, arg3)
|
||||
|
@ -224,13 +240,13 @@ func (m *MockGitService) ListChanges(arg0 context.Context, arg1, arg2 string, ar
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// ListChanges indicates an expected call of ListChanges
|
||||
// ListChanges indicates an expected call of ListChanges.
|
||||
func (mr *MockGitServiceMockRecorder) ListChanges(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChanges", reflect.TypeOf((*MockGitService)(nil).ListChanges), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// ListCommits mocks base method
|
||||
// ListCommits mocks base method.
|
||||
func (m *MockGitService) ListCommits(arg0 context.Context, arg1 string, arg2 scm.CommitListOptions) ([]*scm.Commit, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListCommits", arg0, arg1, arg2)
|
||||
|
@ -240,13 +256,13 @@ func (m *MockGitService) ListCommits(arg0 context.Context, arg1 string, arg2 scm
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// ListCommits indicates an expected call of ListCommits
|
||||
// ListCommits indicates an expected call of ListCommits.
|
||||
func (mr *MockGitServiceMockRecorder) ListCommits(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCommits", reflect.TypeOf((*MockGitService)(nil).ListCommits), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ListTags mocks base method
|
||||
// ListTags mocks base method.
|
||||
func (m *MockGitService) ListTags(arg0 context.Context, arg1 string, arg2 scm.ListOptions) ([]*scm.Reference, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListTags", arg0, arg1, arg2)
|
||||
|
@ -256,36 +272,36 @@ func (m *MockGitService) ListTags(arg0 context.Context, arg1 string, arg2 scm.Li
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// ListTags indicates an expected call of ListTags
|
||||
// ListTags indicates an expected call of ListTags.
|
||||
func (mr *MockGitServiceMockRecorder) ListTags(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListTags", reflect.TypeOf((*MockGitService)(nil).ListTags), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// MockOrganizationService is a mock of OrganizationService interface
|
||||
// MockOrganizationService is a mock of OrganizationService interface.
|
||||
type MockOrganizationService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockOrganizationServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockOrganizationServiceMockRecorder is the mock recorder for MockOrganizationService
|
||||
// MockOrganizationServiceMockRecorder is the mock recorder for MockOrganizationService.
|
||||
type MockOrganizationServiceMockRecorder struct {
|
||||
mock *MockOrganizationService
|
||||
}
|
||||
|
||||
// NewMockOrganizationService creates a new mock instance
|
||||
// NewMockOrganizationService creates a new mock instance.
|
||||
func NewMockOrganizationService(ctrl *gomock.Controller) *MockOrganizationService {
|
||||
mock := &MockOrganizationService{ctrl: ctrl}
|
||||
mock.recorder = &MockOrganizationServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockOrganizationService) EXPECT() *MockOrganizationServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Find mocks base method
|
||||
// Find mocks base method.
|
||||
func (m *MockOrganizationService) Find(arg0 context.Context, arg1 string) (*scm.Organization, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Find", arg0, arg1)
|
||||
|
@ -295,13 +311,13 @@ func (m *MockOrganizationService) Find(arg0 context.Context, arg1 string) (*scm.
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// Find indicates an expected call of Find
|
||||
// Find indicates an expected call of Find.
|
||||
func (mr *MockOrganizationServiceMockRecorder) Find(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockOrganizationService)(nil).Find), arg0, arg1)
|
||||
}
|
||||
|
||||
// FindMembership mocks base method
|
||||
// FindMembership mocks base method.
|
||||
func (m *MockOrganizationService) FindMembership(arg0 context.Context, arg1, arg2 string) (*scm.Membership, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindMembership", arg0, arg1, arg2)
|
||||
|
@ -311,13 +327,13 @@ func (m *MockOrganizationService) FindMembership(arg0 context.Context, arg1, arg
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// FindMembership indicates an expected call of FindMembership
|
||||
// FindMembership indicates an expected call of FindMembership.
|
||||
func (mr *MockOrganizationServiceMockRecorder) FindMembership(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindMembership", reflect.TypeOf((*MockOrganizationService)(nil).FindMembership), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// List mocks base method
|
||||
// List mocks base method.
|
||||
func (m *MockOrganizationService) List(arg0 context.Context, arg1 scm.ListOptions) ([]*scm.Organization, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "List", arg0, arg1)
|
||||
|
@ -327,36 +343,36 @@ func (m *MockOrganizationService) List(arg0 context.Context, arg1 scm.ListOption
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// List indicates an expected call of List
|
||||
// List indicates an expected call of List.
|
||||
func (mr *MockOrganizationServiceMockRecorder) List(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockOrganizationService)(nil).List), arg0, arg1)
|
||||
}
|
||||
|
||||
// MockPullRequestService is a mock of PullRequestService interface
|
||||
// MockPullRequestService is a mock of PullRequestService interface.
|
||||
type MockPullRequestService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockPullRequestServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockPullRequestServiceMockRecorder is the mock recorder for MockPullRequestService
|
||||
// MockPullRequestServiceMockRecorder is the mock recorder for MockPullRequestService.
|
||||
type MockPullRequestServiceMockRecorder struct {
|
||||
mock *MockPullRequestService
|
||||
}
|
||||
|
||||
// NewMockPullRequestService creates a new mock instance
|
||||
// NewMockPullRequestService creates a new mock instance.
|
||||
func NewMockPullRequestService(ctrl *gomock.Controller) *MockPullRequestService {
|
||||
mock := &MockPullRequestService{ctrl: ctrl}
|
||||
mock.recorder = &MockPullRequestServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockPullRequestService) EXPECT() *MockPullRequestServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Close mocks base method
|
||||
// Close mocks base method.
|
||||
func (m *MockPullRequestService) Close(arg0 context.Context, arg1 string, arg2 int) (*scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Close", arg0, arg1, arg2)
|
||||
|
@ -365,13 +381,13 @@ func (m *MockPullRequestService) Close(arg0 context.Context, arg1 string, arg2 i
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Close indicates an expected call of Close
|
||||
// Close indicates an expected call of Close.
|
||||
func (mr *MockPullRequestServiceMockRecorder) Close(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockPullRequestService)(nil).Close), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// Create mocks base method
|
||||
// Create mocks base method.
|
||||
func (m *MockPullRequestService) Create(arg0 context.Context, arg1 string, arg2 *scm.PullRequestInput) (*scm.PullRequest, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Create", arg0, arg1, arg2)
|
||||
|
@ -381,13 +397,13 @@ func (m *MockPullRequestService) Create(arg0 context.Context, arg1 string, arg2
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// Create indicates an expected call of Create
|
||||
// Create indicates an expected call of Create.
|
||||
func (mr *MockPullRequestServiceMockRecorder) Create(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*MockPullRequestService)(nil).Create), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// CreateComment mocks base method
|
||||
// CreateComment mocks base method.
|
||||
func (m *MockPullRequestService) CreateComment(arg0 context.Context, arg1 string, arg2 int, arg3 *scm.CommentInput) (*scm.Comment, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateComment", arg0, arg1, arg2, arg3)
|
||||
|
@ -397,13 +413,13 @@ func (m *MockPullRequestService) CreateComment(arg0 context.Context, arg1 string
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// CreateComment indicates an expected call of CreateComment
|
||||
// CreateComment indicates an expected call of CreateComment.
|
||||
func (mr *MockPullRequestServiceMockRecorder) CreateComment(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateComment", reflect.TypeOf((*MockPullRequestService)(nil).CreateComment), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// DeleteComment mocks base method
|
||||
// DeleteComment mocks base method.
|
||||
func (m *MockPullRequestService) DeleteComment(arg0 context.Context, arg1 string, arg2, arg3 int) (*scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteComment", arg0, arg1, arg2, arg3)
|
||||
|
@ -412,13 +428,13 @@ func (m *MockPullRequestService) DeleteComment(arg0 context.Context, arg1 string
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DeleteComment indicates an expected call of DeleteComment
|
||||
// DeleteComment indicates an expected call of DeleteComment.
|
||||
func (mr *MockPullRequestServiceMockRecorder) DeleteComment(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteComment", reflect.TypeOf((*MockPullRequestService)(nil).DeleteComment), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// Find mocks base method
|
||||
// Find mocks base method.
|
||||
func (m *MockPullRequestService) Find(arg0 context.Context, arg1 string, arg2 int) (*scm.PullRequest, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Find", arg0, arg1, arg2)
|
||||
|
@ -428,13 +444,13 @@ func (m *MockPullRequestService) Find(arg0 context.Context, arg1 string, arg2 in
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// Find indicates an expected call of Find
|
||||
// Find indicates an expected call of Find.
|
||||
func (mr *MockPullRequestServiceMockRecorder) Find(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockPullRequestService)(nil).Find), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// FindComment mocks base method
|
||||
// FindComment mocks base method.
|
||||
func (m *MockPullRequestService) FindComment(arg0 context.Context, arg1 string, arg2, arg3 int) (*scm.Comment, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindComment", arg0, arg1, arg2, arg3)
|
||||
|
@ -444,13 +460,13 @@ func (m *MockPullRequestService) FindComment(arg0 context.Context, arg1 string,
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// FindComment indicates an expected call of FindComment
|
||||
// FindComment indicates an expected call of FindComment.
|
||||
func (mr *MockPullRequestServiceMockRecorder) FindComment(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindComment", reflect.TypeOf((*MockPullRequestService)(nil).FindComment), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// List mocks base method
|
||||
// List mocks base method.
|
||||
func (m *MockPullRequestService) List(arg0 context.Context, arg1 string, arg2 scm.PullRequestListOptions) ([]*scm.PullRequest, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "List", arg0, arg1, arg2)
|
||||
|
@ -460,13 +476,13 @@ func (m *MockPullRequestService) List(arg0 context.Context, arg1 string, arg2 sc
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// List indicates an expected call of List
|
||||
// List indicates an expected call of List.
|
||||
func (mr *MockPullRequestServiceMockRecorder) List(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockPullRequestService)(nil).List), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ListChanges mocks base method
|
||||
// ListChanges mocks base method.
|
||||
func (m *MockPullRequestService) ListChanges(arg0 context.Context, arg1 string, arg2 int, arg3 scm.ListOptions) ([]*scm.Change, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListChanges", arg0, arg1, arg2, arg3)
|
||||
|
@ -476,13 +492,13 @@ func (m *MockPullRequestService) ListChanges(arg0 context.Context, arg1 string,
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// ListChanges indicates an expected call of ListChanges
|
||||
// ListChanges indicates an expected call of ListChanges.
|
||||
func (mr *MockPullRequestServiceMockRecorder) ListChanges(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListChanges", reflect.TypeOf((*MockPullRequestService)(nil).ListChanges), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// ListComments mocks base method
|
||||
// ListComments mocks base method.
|
||||
func (m *MockPullRequestService) ListComments(arg0 context.Context, arg1 string, arg2 int, arg3 scm.ListOptions) ([]*scm.Comment, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListComments", arg0, arg1, arg2, arg3)
|
||||
|
@ -492,13 +508,29 @@ func (m *MockPullRequestService) ListComments(arg0 context.Context, arg1 string,
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// ListComments indicates an expected call of ListComments
|
||||
// ListComments indicates an expected call of ListComments.
|
||||
func (mr *MockPullRequestServiceMockRecorder) ListComments(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListComments", reflect.TypeOf((*MockPullRequestService)(nil).ListComments), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// Merge mocks base method
|
||||
// ListCommits mocks base method.
|
||||
func (m *MockPullRequestService) ListCommits(arg0 context.Context, arg1 string, arg2 int, arg3 scm.ListOptions) ([]*scm.Commit, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListCommits", arg0, arg1, arg2, arg3)
|
||||
ret0, _ := ret[0].([]*scm.Commit)
|
||||
ret1, _ := ret[1].(*scm.Response)
|
||||
ret2, _ := ret[2].(error)
|
||||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// ListCommits indicates an expected call of ListCommits.
|
||||
func (mr *MockPullRequestServiceMockRecorder) ListCommits(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListCommits", reflect.TypeOf((*MockPullRequestService)(nil).ListCommits), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// Merge mocks base method.
|
||||
func (m *MockPullRequestService) Merge(arg0 context.Context, arg1 string, arg2 int) (*scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Merge", arg0, arg1, arg2)
|
||||
|
@ -507,36 +539,36 @@ func (m *MockPullRequestService) Merge(arg0 context.Context, arg1 string, arg2 i
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Merge indicates an expected call of Merge
|
||||
// Merge indicates an expected call of Merge.
|
||||
func (mr *MockPullRequestServiceMockRecorder) Merge(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Merge", reflect.TypeOf((*MockPullRequestService)(nil).Merge), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// MockRepositoryService is a mock of RepositoryService interface
|
||||
// MockRepositoryService is a mock of RepositoryService interface.
|
||||
type MockRepositoryService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockRepositoryServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockRepositoryServiceMockRecorder is the mock recorder for MockRepositoryService
|
||||
// MockRepositoryServiceMockRecorder is the mock recorder for MockRepositoryService.
|
||||
type MockRepositoryServiceMockRecorder struct {
|
||||
mock *MockRepositoryService
|
||||
}
|
||||
|
||||
// NewMockRepositoryService creates a new mock instance
|
||||
// NewMockRepositoryService creates a new mock instance.
|
||||
func NewMockRepositoryService(ctrl *gomock.Controller) *MockRepositoryService {
|
||||
mock := &MockRepositoryService{ctrl: ctrl}
|
||||
mock.recorder = &MockRepositoryServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockRepositoryService) EXPECT() *MockRepositoryServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// CreateHook mocks base method
|
||||
// CreateHook mocks base method.
|
||||
func (m *MockRepositoryService) CreateHook(arg0 context.Context, arg1 string, arg2 *scm.HookInput) (*scm.Hook, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateHook", arg0, arg1, arg2)
|
||||
|
@ -546,13 +578,13 @@ func (m *MockRepositoryService) CreateHook(arg0 context.Context, arg1 string, ar
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// CreateHook indicates an expected call of CreateHook
|
||||
// CreateHook indicates an expected call of CreateHook.
|
||||
func (mr *MockRepositoryServiceMockRecorder) CreateHook(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateHook", reflect.TypeOf((*MockRepositoryService)(nil).CreateHook), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// CreateStatus mocks base method
|
||||
// CreateStatus mocks base method.
|
||||
func (m *MockRepositoryService) CreateStatus(arg0 context.Context, arg1, arg2 string, arg3 *scm.StatusInput) (*scm.Status, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "CreateStatus", arg0, arg1, arg2, arg3)
|
||||
|
@ -562,13 +594,13 @@ func (m *MockRepositoryService) CreateStatus(arg0 context.Context, arg1, arg2 st
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// CreateStatus indicates an expected call of CreateStatus
|
||||
// CreateStatus indicates an expected call of CreateStatus.
|
||||
func (mr *MockRepositoryServiceMockRecorder) CreateStatus(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateStatus", reflect.TypeOf((*MockRepositoryService)(nil).CreateStatus), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// DeleteHook mocks base method
|
||||
// DeleteHook mocks base method.
|
||||
func (m *MockRepositoryService) DeleteHook(arg0 context.Context, arg1, arg2 string) (*scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DeleteHook", arg0, arg1, arg2)
|
||||
|
@ -577,13 +609,13 @@ func (m *MockRepositoryService) DeleteHook(arg0 context.Context, arg1, arg2 stri
|
|||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DeleteHook indicates an expected call of DeleteHook
|
||||
// DeleteHook indicates an expected call of DeleteHook.
|
||||
func (mr *MockRepositoryServiceMockRecorder) DeleteHook(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteHook", reflect.TypeOf((*MockRepositoryService)(nil).DeleteHook), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// Find mocks base method
|
||||
// Find mocks base method.
|
||||
func (m *MockRepositoryService) Find(arg0 context.Context, arg1 string) (*scm.Repository, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Find", arg0, arg1)
|
||||
|
@ -593,13 +625,13 @@ func (m *MockRepositoryService) Find(arg0 context.Context, arg1 string) (*scm.Re
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// Find indicates an expected call of Find
|
||||
// Find indicates an expected call of Find.
|
||||
func (mr *MockRepositoryServiceMockRecorder) Find(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockRepositoryService)(nil).Find), arg0, arg1)
|
||||
}
|
||||
|
||||
// FindHook mocks base method
|
||||
// FindHook mocks base method.
|
||||
func (m *MockRepositoryService) FindHook(arg0 context.Context, arg1, arg2 string) (*scm.Hook, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindHook", arg0, arg1, arg2)
|
||||
|
@ -609,13 +641,13 @@ func (m *MockRepositoryService) FindHook(arg0 context.Context, arg1, arg2 string
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// FindHook indicates an expected call of FindHook
|
||||
// FindHook indicates an expected call of FindHook.
|
||||
func (mr *MockRepositoryServiceMockRecorder) FindHook(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindHook", reflect.TypeOf((*MockRepositoryService)(nil).FindHook), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// FindPerms mocks base method
|
||||
// FindPerms mocks base method.
|
||||
func (m *MockRepositoryService) FindPerms(arg0 context.Context, arg1 string) (*scm.Perm, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindPerms", arg0, arg1)
|
||||
|
@ -625,13 +657,13 @@ func (m *MockRepositoryService) FindPerms(arg0 context.Context, arg1 string) (*s
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// FindPerms indicates an expected call of FindPerms
|
||||
// FindPerms indicates an expected call of FindPerms.
|
||||
func (mr *MockRepositoryServiceMockRecorder) FindPerms(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindPerms", reflect.TypeOf((*MockRepositoryService)(nil).FindPerms), arg0, arg1)
|
||||
}
|
||||
|
||||
// List mocks base method
|
||||
// List mocks base method.
|
||||
func (m *MockRepositoryService) List(arg0 context.Context, arg1 scm.ListOptions) ([]*scm.Repository, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "List", arg0, arg1)
|
||||
|
@ -641,13 +673,13 @@ func (m *MockRepositoryService) List(arg0 context.Context, arg1 scm.ListOptions)
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// List indicates an expected call of List
|
||||
// List indicates an expected call of List.
|
||||
func (mr *MockRepositoryServiceMockRecorder) List(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "List", reflect.TypeOf((*MockRepositoryService)(nil).List), arg0, arg1)
|
||||
}
|
||||
|
||||
// ListHooks mocks base method
|
||||
// ListHooks mocks base method.
|
||||
func (m *MockRepositoryService) ListHooks(arg0 context.Context, arg1 string, arg2 scm.ListOptions) ([]*scm.Hook, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListHooks", arg0, arg1, arg2)
|
||||
|
@ -657,13 +689,13 @@ func (m *MockRepositoryService) ListHooks(arg0 context.Context, arg1 string, arg
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// ListHooks indicates an expected call of ListHooks
|
||||
// ListHooks indicates an expected call of ListHooks.
|
||||
func (mr *MockRepositoryServiceMockRecorder) ListHooks(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListHooks", reflect.TypeOf((*MockRepositoryService)(nil).ListHooks), arg0, arg1, arg2)
|
||||
}
|
||||
|
||||
// ListStatus mocks base method
|
||||
// ListStatus mocks base method.
|
||||
func (m *MockRepositoryService) ListStatus(arg0 context.Context, arg1, arg2 string, arg3 scm.ListOptions) ([]*scm.Status, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListStatus", arg0, arg1, arg2, arg3)
|
||||
|
@ -673,13 +705,13 @@ func (m *MockRepositoryService) ListStatus(arg0 context.Context, arg1, arg2 stri
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// ListStatus indicates an expected call of ListStatus
|
||||
// ListStatus indicates an expected call of ListStatus.
|
||||
func (mr *MockRepositoryServiceMockRecorder) ListStatus(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListStatus", reflect.TypeOf((*MockRepositoryService)(nil).ListStatus), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// UpdateHook mocks base method
|
||||
// UpdateHook mocks base method.
|
||||
func (m *MockRepositoryService) UpdateHook(arg0 context.Context, arg1, arg2 string, arg3 *scm.HookInput) (*scm.Hook, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateHook", arg0, arg1, arg2, arg3)
|
||||
|
@ -689,36 +721,36 @@ func (m *MockRepositoryService) UpdateHook(arg0 context.Context, arg1, arg2 stri
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// UpdateHook indicates an expected call of UpdateHook
|
||||
// UpdateHook indicates an expected call of UpdateHook.
|
||||
func (mr *MockRepositoryServiceMockRecorder) UpdateHook(arg0, arg1, arg2, arg3 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateHook", reflect.TypeOf((*MockRepositoryService)(nil).UpdateHook), arg0, arg1, arg2, arg3)
|
||||
}
|
||||
|
||||
// MockUserService is a mock of UserService interface
|
||||
// MockUserService is a mock of UserService interface.
|
||||
type MockUserService struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockUserServiceMockRecorder
|
||||
}
|
||||
|
||||
// MockUserServiceMockRecorder is the mock recorder for MockUserService
|
||||
// MockUserServiceMockRecorder is the mock recorder for MockUserService.
|
||||
type MockUserServiceMockRecorder struct {
|
||||
mock *MockUserService
|
||||
}
|
||||
|
||||
// NewMockUserService creates a new mock instance
|
||||
// NewMockUserService creates a new mock instance.
|
||||
func NewMockUserService(ctrl *gomock.Controller) *MockUserService {
|
||||
mock := &MockUserService{ctrl: ctrl}
|
||||
mock.recorder = &MockUserServiceMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockUserService) EXPECT() *MockUserServiceMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// Find mocks base method
|
||||
// Find mocks base method.
|
||||
func (m *MockUserService) Find(arg0 context.Context) (*scm.User, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Find", arg0)
|
||||
|
@ -728,13 +760,13 @@ func (m *MockUserService) Find(arg0 context.Context) (*scm.User, *scm.Response,
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// Find indicates an expected call of Find
|
||||
// Find indicates an expected call of Find.
|
||||
func (mr *MockUserServiceMockRecorder) Find(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Find", reflect.TypeOf((*MockUserService)(nil).Find), arg0)
|
||||
}
|
||||
|
||||
// FindEmail mocks base method
|
||||
// FindEmail mocks base method.
|
||||
func (m *MockUserService) FindEmail(arg0 context.Context) (string, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindEmail", arg0)
|
||||
|
@ -744,13 +776,13 @@ func (m *MockUserService) FindEmail(arg0 context.Context) (string, *scm.Response
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// FindEmail indicates an expected call of FindEmail
|
||||
// FindEmail indicates an expected call of FindEmail.
|
||||
func (mr *MockUserServiceMockRecorder) FindEmail(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindEmail", reflect.TypeOf((*MockUserService)(nil).FindEmail), arg0)
|
||||
}
|
||||
|
||||
// FindLogin mocks base method
|
||||
// FindLogin mocks base method.
|
||||
func (m *MockUserService) FindLogin(arg0 context.Context, arg1 string) (*scm.User, *scm.Response, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "FindLogin", arg0, arg1)
|
||||
|
@ -760,7 +792,7 @@ func (m *MockUserService) FindLogin(arg0 context.Context, arg1 string) (*scm.Use
|
|||
return ret0, ret1, ret2
|
||||
}
|
||||
|
||||
// FindLogin indicates an expected call of FindLogin
|
||||
// FindLogin indicates an expected call of FindLogin.
|
||||
func (mr *MockUserServiceMockRecorder) FindLogin(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindLogin", reflect.TypeOf((*MockUserService)(nil).FindLogin), arg0, arg1)
|
||||
|
|
|
@ -44,7 +44,7 @@ type (
|
|||
System *core.System `json:"system"`
|
||||
}
|
||||
|
||||
// BuildManager encapsulets complex build operations and provides
|
||||
// BuildManager encapsulates complex build operations and provides
|
||||
// a simplified interface for build runners.
|
||||
BuildManager interface {
|
||||
// Request requests the next available build stage for execution.
|
||||
|
@ -60,13 +60,13 @@ type (
|
|||
Details(ctx context.Context, stage int64) (*Context, error)
|
||||
|
||||
// Before signals the build step is about to start.
|
||||
Before(ctxt context.Context, step *core.Step) error
|
||||
Before(ctx context.Context, step *core.Step) error
|
||||
|
||||
// After signals the build step is complete.
|
||||
After(ctx context.Context, step *core.Step) error
|
||||
|
||||
// Before signals the build stage is about to start.
|
||||
BeforeAll(ctxt context.Context, stage *core.Stage) error
|
||||
BeforeAll(ctx context.Context, stage *core.Stage) error
|
||||
|
||||
// After signals the build stage is complete.
|
||||
AfterAll(ctx context.Context, stage *core.Stage) error
|
||||
|
@ -84,7 +84,7 @@ type (
|
|||
UploadBytes(ctx context.Context, step int64, b []byte) error
|
||||
}
|
||||
|
||||
// Request provildes filters when requesting a pending
|
||||
// Request provides filters when requesting a pending
|
||||
// build from the queue. This allows an agent, for example,
|
||||
// to request a build that matches its architecture and kernel.
|
||||
Request struct {
|
||||
|
|
|
@ -58,7 +58,7 @@ func (Server) Details(ctx context.Context, stage int64) (*manager.Context, error
|
|||
}
|
||||
|
||||
// Before signals the build step is about to start.
|
||||
func (Server) Before(ctxt context.Context, step *core.Step) error {
|
||||
func (Server) Before(ctx context.Context, step *core.Step) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
|
@ -68,7 +68,7 @@ func (Server) After(ctx context.Context, step *core.Step) error {
|
|||
}
|
||||
|
||||
// Before signals the build stage is about to start.
|
||||
func (Server) BeforeAll(ctxt context.Context, stage *core.Stage) error {
|
||||
func (Server) BeforeAll(ctx context.Context, stage *core.Stage) error {
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ func HandlePing() http.HandlerFunc {
|
|||
}
|
||||
|
||||
// HandleRequest returns an http.HandlerFunc that processes an
|
||||
// http.Request to reqeust a stage from the queue for execution.
|
||||
// http.Request to request a stage from the queue for execution.
|
||||
//
|
||||
// POST /rpc/v2/stage
|
||||
func HandleRequest(m manager.BuildManager) http.HandlerFunc {
|
||||
|
@ -135,7 +135,7 @@ func HandleInfo(m manager.BuildManager) http.HandlerFunc {
|
|||
writeJSON(w, &details{
|
||||
Context: res,
|
||||
Netrc: netrc,
|
||||
Repo: &repositroy{
|
||||
Repo: &repository{
|
||||
Repository: res.Repo,
|
||||
Secret: res.Repo.Secret,
|
||||
},
|
||||
|
|
|
@ -16,12 +16,12 @@ import (
|
|||
type details struct {
|
||||
*manager.Context
|
||||
Netrc *core.Netrc `json:"netrc"`
|
||||
Repo *repositroy `json:"repository"`
|
||||
Repo *repository `json:"repository"`
|
||||
}
|
||||
|
||||
// repository wraps a repository object to include the secret
|
||||
// when the repository is marshaled to json.
|
||||
type repositroy struct {
|
||||
type repository struct {
|
||||
*core.Repository
|
||||
Secret string `json:"secret"`
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ type Config struct {
|
|||
}
|
||||
}
|
||||
|
||||
// heper function reads and unmarshales the docker-machine
|
||||
// helper function reads and unmarshalls the docker-machine
|
||||
// configuration from a reader.
|
||||
func parseReader(r io.Reader) (*Config, error) {
|
||||
out := new(Config)
|
||||
|
|
|
@ -37,7 +37,7 @@ func Load(home, match string) ([]*Config, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// If no match logic is defined, the matchine is
|
||||
// If no match logic is defined, the machine is
|
||||
// automatically used as a build machine.
|
||||
if match == "" {
|
||||
machines = append(machines, conf)
|
||||
|
|
|
@ -539,7 +539,7 @@ func (r *Runner) start(ctx context.Context) error {
|
|||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
return nil
|
||||
default:
|
||||
// This error is ignored on purpose. The system
|
||||
// should not exit the runner on error. The run
|
||||
|
|
|
@ -71,7 +71,7 @@ func TestGlobalErr(t *testing.T) {
|
|||
false, time.Minute)
|
||||
_, err := service.Find(noContext, args)
|
||||
if err == nil {
|
||||
t.Errorf("Expect http.Reponse error")
|
||||
t.Errorf("Expect http.Response error")
|
||||
} else if err.Error() != "Not Found" {
|
||||
t.Errorf("Expect Not Found error")
|
||||
}
|
||||
|
|
|
@ -7,13 +7,11 @@
|
|||
package converter
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
|
||||
"github.com/google/go-jsonnet"
|
||||
"github.com/drone/drone/plugin/converter/jsonnet"
|
||||
)
|
||||
|
||||
// TODO(bradrydzewski) handle jsonnet imports
|
||||
|
@ -42,32 +40,12 @@ func (p *jsonnetPlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*co
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// create the jsonnet vm
|
||||
vm := jsonnet.MakeVM()
|
||||
vm.MaxStack = 500
|
||||
vm.StringOutput = false
|
||||
vm.ErrorFormatter.SetMaxStackTraceSize(20)
|
||||
file, err := jsonnet.Parse(req, nil, nil)
|
||||
|
||||
// convert the jsonnet file to yaml
|
||||
buf := new(bytes.Buffer)
|
||||
docs, err := vm.EvaluateSnippetStream(req.Repo.Config, req.Config.Data)
|
||||
if err != nil {
|
||||
doc, err2 := vm.EvaluateSnippet(req.Repo.Config, req.Config.Data)
|
||||
if err2 != nil {
|
||||
return nil, err
|
||||
}
|
||||
docs = append(docs, doc)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// the jsonnet vm returns a stream of yaml documents
|
||||
// that need to be combined into a single yaml file.
|
||||
for _, doc := range docs {
|
||||
buf.WriteString("---")
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(doc)
|
||||
}
|
||||
|
||||
return &core.Config{
|
||||
Data: buf.String(),
|
||||
Data: file,
|
||||
}, nil
|
||||
}
|
||||
|
|
118
plugin/converter/jsonnet/jsonnet.go
Normal file
118
plugin/converter/jsonnet/jsonnet.go
Normal file
|
@ -0,0 +1,118 @@
|
|||
package jsonnet
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
|
||||
"github.com/google/go-jsonnet"
|
||||
)
|
||||
|
||||
const repo = "repo."
|
||||
const build = "build."
|
||||
const param = "param."
|
||||
|
||||
func Parse(req *core.ConvertArgs, template *core.Template, templateData map[string]interface{}) (string, error) {
|
||||
vm := jsonnet.MakeVM()
|
||||
vm.MaxStack = 500
|
||||
vm.StringOutput = false
|
||||
vm.ErrorFormatter.SetMaxStackTraceSize(20)
|
||||
|
||||
//map build/repo parameters
|
||||
if req.Build != nil {
|
||||
mapBuild(req.Build, vm)
|
||||
}
|
||||
if req.Repo != nil {
|
||||
mapRepo(req.Repo, vm)
|
||||
}
|
||||
|
||||
var jsonnetFile string
|
||||
var jsonnetFileName string
|
||||
if template != nil {
|
||||
jsonnetFile = template.Data
|
||||
jsonnetFileName = template.Name
|
||||
} else {
|
||||
jsonnetFile = req.Config.Data
|
||||
jsonnetFileName = req.Repo.Config
|
||||
}
|
||||
// map external inputs
|
||||
if len(templateData) != 0 {
|
||||
for k, v := range templateData {
|
||||
key := fmt.Sprintf("input." + k)
|
||||
val := fmt.Sprint(v)
|
||||
vm.ExtVar(key, val)
|
||||
}
|
||||
}
|
||||
|
||||
// convert the jsonnet file to yaml
|
||||
buf := new(bytes.Buffer)
|
||||
docs, err := vm.EvaluateSnippetStream(jsonnetFileName, jsonnetFile)
|
||||
if err != nil {
|
||||
doc, err2 := vm.EvaluateSnippet(jsonnetFileName, jsonnetFile)
|
||||
if err2 != nil {
|
||||
return "", err
|
||||
}
|
||||
docs = append(docs, doc)
|
||||
}
|
||||
|
||||
// the jsonnet vm returns a stream of yaml documents
|
||||
// that need to be combined into a single yaml file.
|
||||
for _, doc := range docs {
|
||||
buf.WriteString("---")
|
||||
buf.WriteString("\n")
|
||||
buf.WriteString(doc)
|
||||
}
|
||||
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func mapBuild(v *core.Build, vm *jsonnet.VM) {
|
||||
vm.ExtVar(build+"event", v.Event)
|
||||
vm.ExtVar(build+"action", v.Action)
|
||||
vm.ExtVar(build+"environment", v.Deploy)
|
||||
vm.ExtVar(build+"link", v.Link)
|
||||
vm.ExtVar(build+"branch", v.Target)
|
||||
vm.ExtVar(build+"source", v.Source)
|
||||
vm.ExtVar(build+"before", v.Before)
|
||||
vm.ExtVar(build+"after", v.After)
|
||||
vm.ExtVar(build+"target", v.Target)
|
||||
vm.ExtVar(build+"ref", v.Ref)
|
||||
vm.ExtVar(build+"commit", v.After)
|
||||
vm.ExtVar(build+"ref", v.Ref)
|
||||
vm.ExtVar(build+"title", v.Title)
|
||||
vm.ExtVar(build+"message", v.Message)
|
||||
vm.ExtVar(build+"source_repo", v.Fork)
|
||||
vm.ExtVar(build+"author_login", v.Author)
|
||||
vm.ExtVar(build+"author_name", v.AuthorName)
|
||||
vm.ExtVar(build+"author_email", v.AuthorEmail)
|
||||
vm.ExtVar(build+"author_avatar", v.AuthorAvatar)
|
||||
vm.ExtVar(build+"sender", v.Sender)
|
||||
fromMap(v.Params, vm)
|
||||
}
|
||||
|
||||
func mapRepo(v *core.Repository, vm *jsonnet.VM) {
|
||||
vm.ExtVar(repo+"uid", v.UID)
|
||||
vm.ExtVar(repo+"name", v.Name)
|
||||
vm.ExtVar(repo+"namespace", v.Namespace)
|
||||
vm.ExtVar(repo+"slug", v.Slug)
|
||||
vm.ExtVar(repo+"git_http_url", v.HTTPURL)
|
||||
vm.ExtVar(repo+"git_ssh_url", v.SSHURL)
|
||||
vm.ExtVar(repo+"link", v.Link)
|
||||
vm.ExtVar(repo+"branch", v.Branch)
|
||||
vm.ExtVar(repo+"config", v.Config)
|
||||
vm.ExtVar(repo+"private", strconv.FormatBool(v.Private))
|
||||
vm.ExtVar(repo+"visibility", v.Visibility)
|
||||
vm.ExtVar(repo+"active", strconv.FormatBool(v.Active))
|
||||
vm.ExtVar(repo+"trusted", strconv.FormatBool(v.Trusted))
|
||||
vm.ExtVar(repo+"protected", strconv.FormatBool(v.Protected))
|
||||
vm.ExtVar(repo+"ignore_forks", strconv.FormatBool(v.IgnoreForks))
|
||||
vm.ExtVar(repo+"ignore_pull_requests", strconv.FormatBool(v.IgnorePulls))
|
||||
}
|
||||
|
||||
func fromMap(m map[string]string, vm *jsonnet.VM) {
|
||||
for k, v := range m {
|
||||
vm.ExtVar(build+param+k, v)
|
||||
}
|
||||
}
|
94
plugin/converter/jsonnet/jsonnet_test.go
Normal file
94
plugin/converter/jsonnet/jsonnet_test.go
Normal file
|
@ -0,0 +1,94 @@
|
|||
package jsonnet
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
)
|
||||
|
||||
func TestParse(t *testing.T) {
|
||||
before, err := ioutil.ReadFile("../testdata/input.jsonnet")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
after, err := ioutil.ReadFile("../testdata/input.jsonnet.golden")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
After: "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
},
|
||||
Repo: &core.Repository{
|
||||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.yml",
|
||||
},
|
||||
Config: &core.Config{},
|
||||
}
|
||||
|
||||
template := &core.Template{
|
||||
Name: "my_template.jsonnet",
|
||||
Data: string(before),
|
||||
}
|
||||
|
||||
templateData := map[string]interface{}{
|
||||
"stepName": "my_step",
|
||||
"image": "my_image",
|
||||
"commands": "my_command",
|
||||
}
|
||||
|
||||
req.Config.Data = string(before)
|
||||
|
||||
parsedFile, err := Parse(req, template, templateData)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if want, got := parsedFile, string(after); want != got {
|
||||
t.Errorf("Want %q got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseJsonnetNotTemplateFile(t *testing.T) {
|
||||
before, err := ioutil.ReadFile("../testdata/single.jsonnet")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
after, err := ioutil.ReadFile("../testdata/input.jsonnet.golden")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
After: "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
},
|
||||
Repo: &core.Repository{
|
||||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.jsonnet",
|
||||
},
|
||||
Config: &core.Config{},
|
||||
}
|
||||
|
||||
req.Repo.Config = "plugin.jsonnet"
|
||||
req.Config.Data = string(before)
|
||||
|
||||
parsedFile, err := Parse(req, nil, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if want, got := parsedFile, string(after); want != got {
|
||||
t.Errorf("Want %q got %q", want, got)
|
||||
}
|
||||
}
|
|
@ -34,16 +34,17 @@ const keyf = "%d|%s|%s|%s|%s|%s"
|
|||
// This micro-optimization is intended for multi-pipeline
|
||||
// projects that would otherwise covert the file for each
|
||||
// pipeline execution.
|
||||
func Memoize(base core.ConvertService) core.ConvertService {
|
||||
func Memoize(base core.ConvertService, size int) core.ConvertService {
|
||||
// simple cache prevents the same yaml file from being
|
||||
// requested multiple times in a short period.
|
||||
cache, _ := lru.New(10)
|
||||
return &memoize{base: base, cache: cache}
|
||||
return &memoize{base: base, cache: cache, size: size}
|
||||
}
|
||||
|
||||
type memoize struct {
|
||||
base core.ConvertService
|
||||
cache *lru.Cache
|
||||
size int
|
||||
}
|
||||
|
||||
func (c *memoize) Convert(ctx context.Context, req *core.ConvertArgs) (*core.Config, error) {
|
||||
|
@ -53,6 +54,11 @@ func (c *memoize) Convert(ctx context.Context, req *core.ConvertArgs) (*core.Con
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// the client can optionally disable cacheing.
|
||||
if c.size == 0 {
|
||||
return c.base.Convert(ctx, req)
|
||||
}
|
||||
|
||||
// generate the key used to cache the converted file.
|
||||
key := fmt.Sprintf(keyf,
|
||||
req.Repo.ID,
|
||||
|
|
|
@ -24,6 +24,6 @@ import (
|
|||
// This micro-optimization is intended for multi-pipeline
|
||||
// projects that would otherwise covert the file for each
|
||||
// pipeline execution.
|
||||
func Memoize(base core.ConvertService) core.ConvertService {
|
||||
func Memoize(base core.ConvertService, size int) core.ConvertService {
|
||||
return new(noop)
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ func TestMemoize(t *testing.T) {
|
|||
base := mock.NewMockConvertService(controller)
|
||||
base.EXPECT().Convert(gomock.Any(), gomock.Any()).Return(args.Config, nil)
|
||||
|
||||
service := Memoize(base).(*memoize)
|
||||
service := Memoize(base, 10).(*memoize)
|
||||
_, err := service.Convert(noContext, args)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -69,7 +69,7 @@ func TestMemoize_Tag(t *testing.T) {
|
|||
base := mock.NewMockConvertService(controller)
|
||||
base.EXPECT().Convert(gomock.Any(), gomock.Any()).Return(args.Config, nil)
|
||||
|
||||
service := Memoize(base).(*memoize)
|
||||
service := Memoize(base, 10).(*memoize)
|
||||
res, err := service.Convert(noContext, args)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -93,7 +93,7 @@ func TestMemoize_Empty(t *testing.T) {
|
|||
base := mock.NewMockConvertService(controller)
|
||||
base.EXPECT().Convert(gomock.Any(), gomock.Any()).Return(args.Config, nil)
|
||||
|
||||
service := Memoize(base).(*memoize)
|
||||
service := Memoize(base, 10).(*memoize)
|
||||
res, err := service.Convert(noContext, args)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -120,7 +120,7 @@ func TestMemoize_Nil(t *testing.T) {
|
|||
base := mock.NewMockConvertService(controller)
|
||||
base.EXPECT().Convert(gomock.Any(), gomock.Any()).Return(args.Config, nil)
|
||||
|
||||
service := Memoize(base).(*memoize)
|
||||
service := Memoize(base, 10).(*memoize)
|
||||
res, err := service.Convert(noContext, args)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
@ -147,7 +147,7 @@ func TestMemoize_Error(t *testing.T) {
|
|||
base := mock.NewMockConvertService(controller)
|
||||
base.EXPECT().Convert(gomock.Any(), gomock.Any()).Return(nil, want)
|
||||
|
||||
service := Memoize(base).(*memoize)
|
||||
service := Memoize(base, 10).(*memoize)
|
||||
_, err := service.Convert(noContext, args)
|
||||
if err == nil {
|
||||
t.Errorf("Expect error from base returned to caller")
|
||||
|
|
61
plugin/converter/starlark.go
Normal file
61
plugin/converter/starlark.go
Normal file
|
@ -0,0 +1,61 @@
|
|||
// Copyright 2019 Drone IO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package converter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/plugin/converter/starlark"
|
||||
)
|
||||
|
||||
// Starlark returns a conversion service that converts the
|
||||
// starlark file to a yaml file.
|
||||
func Starlark(enabled bool) core.ConvertService {
|
||||
return &starlarkPlugin{
|
||||
enabled: enabled,
|
||||
}
|
||||
}
|
||||
|
||||
type starlarkPlugin struct {
|
||||
enabled bool
|
||||
}
|
||||
|
||||
func (p *starlarkPlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*core.Config, error) {
|
||||
if p.enabled == false {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// if the file extension is not jsonnet we can
|
||||
// skip this plugin by returning zero values.
|
||||
switch {
|
||||
case strings.HasSuffix(req.Repo.Config, ".script"):
|
||||
case strings.HasSuffix(req.Repo.Config, ".star"):
|
||||
case strings.HasSuffix(req.Repo.Config, ".starlark"):
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
file, err := starlark.Parse(req, nil, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &core.Config{
|
||||
Data: file,
|
||||
}, nil
|
||||
}
|
|
@ -38,18 +38,29 @@ import (
|
|||
// TODO(bradrydzewski) add build parent
|
||||
// TODO(bradrydzewski) add build timestamp
|
||||
|
||||
func createArgs(repo *core.Repository, build *core.Build) []starlark.Value {
|
||||
func createArgs(repo *core.Repository, build *core.Build, input map[string]interface{}) []starlark.Value {
|
||||
return []starlark.Value{
|
||||
starlarkstruct.FromStringDict(
|
||||
starlark.String("context"),
|
||||
starlark.StringDict{
|
||||
"repo": starlarkstruct.FromStringDict(starlark.String("repo"), fromRepo(repo)),
|
||||
"build": starlarkstruct.FromStringDict(starlark.String("build"), fromBuild(build)),
|
||||
"input": starlarkstruct.FromStringDict(starlark.String("input"), fromInput(input)),
|
||||
},
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func fromInput(input map[string]interface{}) starlark.StringDict {
|
||||
out := map[string]starlark.Value{}
|
||||
for k, v := range input {
|
||||
if s, ok := v.(string); ok {
|
||||
out[k] = starlark.String(s)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func fromBuild(v *core.Build) starlark.StringDict {
|
||||
return starlark.StringDict{
|
||||
"event": starlark.String(v.Event),
|
||||
|
@ -72,6 +83,7 @@ func fromBuild(v *core.Build) starlark.StringDict {
|
|||
"author_email": starlark.String(v.AuthorEmail),
|
||||
"author_avatar": starlark.String(v.AuthorAvatar),
|
||||
"sender": starlark.String(v.Sender),
|
||||
"debug": starlark.Bool(v.Debug),
|
||||
"params": fromMap(v.Params),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,11 +16,10 @@ package starlark
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/handler/api/errors"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.starlark.net/starlark"
|
||||
)
|
||||
|
@ -55,33 +54,7 @@ var (
|
|||
ErrCannotLoad = errors.New("starlark: cannot load external scripts")
|
||||
)
|
||||
|
||||
// New returns a conversion service that converts the
|
||||
// starlark file to a yaml file.
|
||||
func New(enabled bool) core.ConvertService {
|
||||
return &starlarkPlugin{
|
||||
enabled: enabled,
|
||||
}
|
||||
}
|
||||
|
||||
type starlarkPlugin struct {
|
||||
enabled bool
|
||||
}
|
||||
|
||||
func (p *starlarkPlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*core.Config, error) {
|
||||
if p.enabled == false {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// if the file extension is not jsonnet we can
|
||||
// skip this plugin by returning zero values.
|
||||
switch {
|
||||
case strings.HasSuffix(req.Repo.Config, ".script"):
|
||||
case strings.HasSuffix(req.Repo.Config, ".star"):
|
||||
case strings.HasSuffix(req.Repo.Config, ".starlark"):
|
||||
default:
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func Parse(req *core.ConvertArgs, template *core.Template, templateData map[string]interface{}) (string, error) {
|
||||
thread := &starlark.Thread{
|
||||
Name: "drone",
|
||||
Load: noLoad,
|
||||
|
@ -92,9 +65,19 @@ func (p *starlarkPlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*c
|
|||
}).Traceln(msg)
|
||||
},
|
||||
}
|
||||
globals, err := starlark.ExecFile(thread, req.Repo.Config, []byte(req.Config.Data), nil)
|
||||
var starlarkFile string
|
||||
var starlarkFileName string
|
||||
if template != nil {
|
||||
starlarkFile = template.Data
|
||||
starlarkFileName = template.Name
|
||||
} else {
|
||||
starlarkFile = req.Config.Data
|
||||
starlarkFileName = req.Repo.Config
|
||||
}
|
||||
|
||||
globals, err := starlark.ExecFile(thread, starlarkFileName, starlarkFile, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
// find the main method in the starlark script and
|
||||
|
@ -102,16 +85,16 @@ func (p *starlarkPlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*c
|
|||
// is invalid.
|
||||
mainVal, ok := globals["main"]
|
||||
if !ok {
|
||||
return nil, ErrMainMissing
|
||||
return "", ErrMainMissing
|
||||
}
|
||||
main, ok := mainVal.(starlark.Callable)
|
||||
if !ok {
|
||||
return nil, ErrMainInvalid
|
||||
return "", ErrMainInvalid
|
||||
}
|
||||
|
||||
// create the input args and invoke the main method
|
||||
// using the input args.
|
||||
args := createArgs(req.Repo, req.Build)
|
||||
args := createArgs(req.Repo, req.Build, templateData)
|
||||
|
||||
// set the maximum number of operations in the script. this
|
||||
// mitigates long running scripts.
|
||||
|
@ -120,7 +103,7 @@ func (p *starlarkPlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*c
|
|||
// execute the main method in the script.
|
||||
mainVal, err = starlark.Call(thread, main, args, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
@ -131,27 +114,24 @@ func (p *starlarkPlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*c
|
|||
buf.WriteString(separator)
|
||||
buf.WriteString(newline)
|
||||
if err := write(buf, item); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
buf.WriteString(newline)
|
||||
}
|
||||
case *starlark.Dict:
|
||||
if err := write(buf, v); err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
default:
|
||||
return nil, ErrMainReturn
|
||||
return "", ErrMainReturn
|
||||
}
|
||||
|
||||
// this is a temporary workaround until we
|
||||
// implement a LimitWriter.
|
||||
if b := buf.Bytes(); len(b) > limit {
|
||||
return nil, ErrMaximumSize
|
||||
return "", ErrMaximumSize
|
||||
}
|
||||
|
||||
return &core.Config{
|
||||
Data: buf.String(),
|
||||
}, nil
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func noLoad(_ *starlark.Thread, _ string) (starlark.StringDict, error) {
|
||||
|
|
|
@ -15,17 +15,24 @@
|
|||
package starlark
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
)
|
||||
|
||||
var noContext = context.Background()
|
||||
func TestParseStarlark(t *testing.T) {
|
||||
before, err := ioutil.ReadFile("../testdata/starlark.input.star")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
plugin := New(true)
|
||||
after, err := ioutil.ReadFile("../testdata/starlark.input.star.golden")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
|
@ -37,54 +44,38 @@ func TestConvert(t *testing.T) {
|
|||
},
|
||||
Config: &core.Config{},
|
||||
}
|
||||
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config != nil {
|
||||
t.Error("Want nil config when configuration is not starlark file")
|
||||
return
|
||||
template := &core.Template{
|
||||
Name: "my_template.star",
|
||||
Data: string(before),
|
||||
}
|
||||
|
||||
before, err := ioutil.ReadFile("testdata/single.star")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
after, err := ioutil.ReadFile("testdata/single.star.golden")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
templateData := map[string]interface{}{
|
||||
"stepName": "my_step",
|
||||
"image": "my_image",
|
||||
"commands": "my_command",
|
||||
}
|
||||
|
||||
req.Repo.Config = "single.star"
|
||||
req.Config.Data = string(before)
|
||||
config, err = plugin.Convert(noContext, req)
|
||||
|
||||
parsedFile, err := Parse(req, template, templateData)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config == nil {
|
||||
t.Error("Want non-nil configuration")
|
||||
return
|
||||
}
|
||||
|
||||
if want, got := config.Data, string(after); want != got {
|
||||
if want, got := parsedFile, string(after); want != got {
|
||||
t.Errorf("Want %q got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
// this test verifies the starlark file can generate a multi-document
|
||||
// yaml file that defines multiple pipelines.
|
||||
func TestConvert_Multi(t *testing.T) {
|
||||
before, err := ioutil.ReadFile("testdata/multi.star")
|
||||
func TestParseStarlarkNotTemplateFile(t *testing.T) {
|
||||
before, err := ioutil.ReadFile("../testdata/single.star")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
after, err := ioutil.ReadFile("testdata/multi.star.golden")
|
||||
|
||||
after, err := ioutil.ReadFile("../testdata/single.star.golden")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
|
@ -98,63 +89,19 @@ func TestConvert_Multi(t *testing.T) {
|
|||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.star",
|
||||
},
|
||||
Config: &core.Config{
|
||||
Data: string(before),
|
||||
},
|
||||
Config: &core.Config{},
|
||||
}
|
||||
|
||||
plugin := New(true)
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
req.Repo.Config = "plugin.starlark.star"
|
||||
req.Config.Data = string(before)
|
||||
|
||||
parsedFile, err := Parse(req, nil, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
config, err = plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config == nil {
|
||||
t.Error("Want non-nil configuration")
|
||||
return
|
||||
}
|
||||
|
||||
if want, got := config.Data, string(after); want != got {
|
||||
if want, got := parsedFile, string(after); want != got {
|
||||
t.Errorf("Want %q got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
// this test verifies the plugin is skipped when it has
|
||||
// not been explicitly enabled.
|
||||
func TestConvert_Skip(t *testing.T) {
|
||||
plugin := New(false)
|
||||
config, err := plugin.Convert(noContext, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config != nil {
|
||||
t.Errorf("Expect nil config returned when plugin disabled")
|
||||
}
|
||||
}
|
||||
|
||||
// this test verifies the plugin is skipped when the config
|
||||
// file extension is not a starlark extension.
|
||||
func TestConvert_SkipYaml(t *testing.T) {
|
||||
req := &core.ConvertArgs{
|
||||
Repo: &core.Repository{
|
||||
Config: ".drone.yaml",
|
||||
},
|
||||
}
|
||||
|
||||
plugin := New(true)
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config != nil {
|
||||
t.Errorf("Expect nil config returned for non-starlark files")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package landingpage
|
||||
// +build oss
|
||||
|
||||
//go:generate togo http -package landingpage -output dist_gen.go
|
||||
package converter
|
||||
|
||||
import "github.com/drone/drone/core"
|
||||
|
||||
func Starlark(enabled bool) core.ConvertService {
|
||||
return new(noop)
|
||||
}
|
157
plugin/converter/starlark_test.go
Normal file
157
plugin/converter/starlark_test.go
Normal file
|
@ -0,0 +1,157 @@
|
|||
// Copyright 2019 Drone IO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package converter
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
)
|
||||
|
||||
func TestStarlarkConvert(t *testing.T) {
|
||||
plugin := Starlark(true)
|
||||
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
After: "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
},
|
||||
Repo: &core.Repository{
|
||||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.yml",
|
||||
},
|
||||
Config: &core.Config{},
|
||||
}
|
||||
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config != nil {
|
||||
t.Error("Want nil config when configuration is not starlark file")
|
||||
return
|
||||
}
|
||||
|
||||
before, err := ioutil.ReadFile("testdata/single.star")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
after, err := ioutil.ReadFile("testdata/single.star.golden")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
req.Repo.Config = "single.star"
|
||||
req.Config.Data = string(before)
|
||||
config, err = plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config == nil {
|
||||
t.Error("Want non-nil configuration")
|
||||
return
|
||||
}
|
||||
|
||||
if want, got := config.Data, string(after); want != got {
|
||||
t.Errorf("Want %q got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
// this test verifies the starlark file can generate a multi-document
|
||||
// yaml file that defines multiple pipelines.
|
||||
func TestConvert_Multi(t *testing.T) {
|
||||
before, err := ioutil.ReadFile("testdata/multi.star")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
after, err := ioutil.ReadFile("testdata/multi.star.golden")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
After: "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
},
|
||||
Repo: &core.Repository{
|
||||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.star",
|
||||
},
|
||||
Config: &core.Config{
|
||||
Data: string(before),
|
||||
},
|
||||
}
|
||||
|
||||
plugin := Starlark(true)
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
config, err = plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config == nil {
|
||||
t.Error("Want non-nil configuration")
|
||||
return
|
||||
}
|
||||
|
||||
if want, got := config.Data, string(after); want != got {
|
||||
t.Errorf("Want %q got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
// this test verifies the plugin is skipped when it has
|
||||
// not been explicitly enabled.
|
||||
func TestConvert_Skip(t *testing.T) {
|
||||
plugin := Starlark(false)
|
||||
config, err := plugin.Convert(noContext, nil)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config != nil {
|
||||
t.Errorf("Expect nil config returned when plugin disabled")
|
||||
}
|
||||
}
|
||||
|
||||
// this test verifies the plugin is skipped when the config
|
||||
// file extension is not a starlark extension.
|
||||
func TestConvert_SkipYaml(t *testing.T) {
|
||||
req := &core.ConvertArgs{
|
||||
Repo: &core.Repository{
|
||||
Config: ".drone.yaml",
|
||||
},
|
||||
}
|
||||
|
||||
plugin := Starlark(true)
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config != nil {
|
||||
t.Errorf("Expect nil config returned for non-starlark files")
|
||||
}
|
||||
}
|
98
plugin/converter/template.go
Normal file
98
plugin/converter/template.go
Normal file
|
@ -0,0 +1,98 @@
|
|||
// Copyright 2019 Drone IO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build !oss
|
||||
|
||||
package converter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/plugin/converter/jsonnet"
|
||||
"github.com/drone/drone/plugin/converter/starlark"
|
||||
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
// templateFileRE regex to verifying kind is template.
|
||||
templateFileRE = regexp.MustCompile("^kind:\\s+template+\\n")
|
||||
ErrTemplateNotFound = errors.New("template converter: template name given not found")
|
||||
ErrTemplateSyntaxErrors = errors.New("template converter: there is a problem with the yaml file provided")
|
||||
)
|
||||
|
||||
func Template(templateStore core.TemplateStore) core.ConvertService {
|
||||
return &templatePlugin{
|
||||
templateStore: templateStore,
|
||||
}
|
||||
}
|
||||
|
||||
type templatePlugin struct {
|
||||
templateStore core.TemplateStore
|
||||
}
|
||||
|
||||
func (p *templatePlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*core.Config, error) {
|
||||
// check type is yaml
|
||||
if strings.HasSuffix(req.Repo.Config, ".yml") == false {
|
||||
return nil, nil
|
||||
}
|
||||
// check kind is template
|
||||
if templateFileRE.MatchString(req.Config.Data) == false {
|
||||
return nil, nil
|
||||
}
|
||||
// map to templateArgs
|
||||
var templateArgs core.TemplateArgs
|
||||
err := yaml.Unmarshal([]byte(req.Config.Data), &templateArgs)
|
||||
if err != nil {
|
||||
return nil, ErrTemplateSyntaxErrors
|
||||
}
|
||||
// get template from db
|
||||
template, err := p.templateStore.FindName(ctx, templateArgs.Load, req.Repo.Namespace)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, ErrTemplateNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Check if file is of type Starlark
|
||||
if strings.HasSuffix(templateArgs.Load, ".script") ||
|
||||
strings.HasSuffix(templateArgs.Load, ".star") ||
|
||||
strings.HasSuffix(templateArgs.Load, ".starlark") {
|
||||
|
||||
file, err := starlark.Parse(req, template, templateArgs.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &core.Config{
|
||||
Data: file,
|
||||
}, nil
|
||||
}
|
||||
// Check if the file is of type Jsonnet
|
||||
if strings.HasSuffix(templateArgs.Load, ".jsonnet") {
|
||||
file, err := jsonnet.Parse(req, template, templateArgs.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &core.Config{
|
||||
Data: file,
|
||||
}, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
37
plugin/converter/template_oss.go
Normal file
37
plugin/converter/template_oss.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
// Copyright 2019 Drone IO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// +build oss
|
||||
|
||||
package converter
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
)
|
||||
|
||||
func Template(templateStore core.TemplateStore) core.ConvertService {
|
||||
return &templatePlugin{
|
||||
templateStore: templateStore,
|
||||
}
|
||||
}
|
||||
|
||||
type templatePlugin struct {
|
||||
templateStore core.TemplateStore
|
||||
}
|
||||
|
||||
func (p *templatePlugin) Convert(ctx context.Context, req *core.ConvertArgs) (*core.Config, error) {
|
||||
return nil, nil
|
||||
}
|
239
plugin/converter/template_test.go
Normal file
239
plugin/converter/template_test.go
Normal file
|
@ -0,0 +1,239 @@
|
|||
// Copyright 2019 Drone IO, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package converter
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"github.com/drone/drone/core"
|
||||
"github.com/drone/drone/mock"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
func TestTemplatePluginConvertStarlark(t *testing.T) {
|
||||
templateArgs, err := ioutil.ReadFile("testdata/starlark.template.yml")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
After: "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
},
|
||||
Repo: &core.Repository{
|
||||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.yml",
|
||||
Namespace: "octocat",
|
||||
},
|
||||
Config: &core.Config{
|
||||
Data: string(templateArgs),
|
||||
},
|
||||
}
|
||||
|
||||
beforeInput, err := ioutil.ReadFile("testdata/starlark.input.star")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
after, err := ioutil.ReadFile("testdata/starlark.input.star.golden")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
template := &core.Template{
|
||||
Name: "plugin.starlark",
|
||||
Data: string(beforeInput),
|
||||
Namespace: "octocat",
|
||||
}
|
||||
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
templates := mock.NewMockTemplateStore(controller)
|
||||
templates.EXPECT().FindName(gomock.Any(), template.Name, req.Repo.Namespace).Return(template, nil)
|
||||
|
||||
plugin := Template(templates)
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
t.Error("Want non-nil configuration")
|
||||
return
|
||||
}
|
||||
|
||||
if want, got := config.Data, string(after); want != got {
|
||||
t.Errorf("Want %q got %q", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplatePluginConvertNotYamlFile(t *testing.T) {
|
||||
|
||||
plugin := Template(nil)
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
After: "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
},
|
||||
Repo: &core.Repository{
|
||||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.star",
|
||||
},
|
||||
Config: &core.Config{},
|
||||
}
|
||||
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config != nil {
|
||||
t.Errorf("Expect nil config returned for non-starlark files")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplatePluginConvertDroneFileTypePipeline(t *testing.T) {
|
||||
args, err := ioutil.ReadFile("testdata/drone.yml")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
plugin := Template(nil)
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
After: "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
},
|
||||
Repo: &core.Repository{
|
||||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.yml",
|
||||
},
|
||||
Config: &core.Config{Data: string(args)},
|
||||
}
|
||||
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if config != nil {
|
||||
t.Errorf("Expect nil config returned for non-starlark files")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplatePluginConvertTemplateNotFound(t *testing.T) {
|
||||
templateArgs, err := ioutil.ReadFile("testdata/starlark.template.yml")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
After: "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
},
|
||||
Repo: &core.Repository{
|
||||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.yml",
|
||||
Namespace: "octocat",
|
||||
},
|
||||
Config: &core.Config{Data: string(templateArgs)},
|
||||
}
|
||||
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
template := &core.Template{
|
||||
Name: "plugin.starlark",
|
||||
Data: "",
|
||||
}
|
||||
|
||||
templates := mock.NewMockTemplateStore(controller)
|
||||
templates.EXPECT().FindName(gomock.Any(), template.Name, req.Repo.Namespace).Return(nil, nil)
|
||||
|
||||
plugin := Template(templates)
|
||||
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if config != nil {
|
||||
t.Errorf("template converter: template name given not found")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTemplatePluginConvertJsonnet(t *testing.T) {
|
||||
templateArgs, err := ioutil.ReadFile("testdata/jsonnet.template.yml")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
req := &core.ConvertArgs{
|
||||
Build: &core.Build{
|
||||
After: "3d21ec53a331a6f037a91c368710b99387d012c1",
|
||||
},
|
||||
Repo: &core.Repository{
|
||||
Slug: "octocat/hello-world",
|
||||
Config: ".drone.yml",
|
||||
Namespace: "octocat",
|
||||
},
|
||||
Config: &core.Config{
|
||||
Data: string(templateArgs),
|
||||
},
|
||||
}
|
||||
|
||||
beforeInput, err := ioutil.ReadFile("testdata/input.jsonnet")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
after, err := ioutil.ReadFile("testdata/input.jsonnet.golden")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
template := &core.Template{
|
||||
Name: "plugin.jsonnet",
|
||||
Data: string(beforeInput),
|
||||
Namespace: "octocat",
|
||||
}
|
||||
|
||||
controller := gomock.NewController(t)
|
||||
defer controller.Finish()
|
||||
|
||||
templates := mock.NewMockTemplateStore(controller)
|
||||
templates.EXPECT().FindName(gomock.Any(), template.Name, req.Repo.Namespace).Return(template, nil)
|
||||
|
||||
plugin := Template(templates)
|
||||
config, err := plugin.Convert(noContext, req)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if config == nil {
|
||||
t.Error("Want non-nil configuration")
|
||||
return
|
||||
}
|
||||
|
||||
if want, got := config.Data, string(after); want != got {
|
||||
t.Errorf("Want %q got %q", want, got)
|
||||
}
|
||||
}
|
6
plugin/converter/testdata/drone.yml
vendored
Normal file
6
plugin/converter/testdata/drone.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
kind: pipeline
|
||||
load: plugin.starlark
|
||||
data:
|
||||
stepName: my_step
|
||||
image: my_image
|
||||
commands: my_command
|
18
plugin/converter/testdata/input.jsonnet
vendored
Normal file
18
plugin/converter/testdata/input.jsonnet
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
local stepName = std.extVar("input.stepName");
|
||||
local image = std.extVar("input.image");
|
||||
local commands = std.extVar("input.commands");
|
||||
|
||||
{
|
||||
"kind": "pipeline",
|
||||
"type": "docker",
|
||||
"name": "default",
|
||||
"steps": [
|
||||
{
|
||||
"name": stepName,
|
||||
"image": image,
|
||||
"commands": [
|
||||
commands
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
15
plugin/converter/testdata/input.jsonnet.golden
vendored
Normal file
15
plugin/converter/testdata/input.jsonnet.golden
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
---
|
||||
{
|
||||
"kind": "pipeline",
|
||||
"name": "default",
|
||||
"steps": [
|
||||
{
|
||||
"commands": [
|
||||
"my_command"
|
||||
],
|
||||
"image": "my_image",
|
||||
"name": "my_step"
|
||||
}
|
||||
],
|
||||
"type": "docker"
|
||||
}
|
6
plugin/converter/testdata/jsonnet.template.yml
vendored
Normal file
6
plugin/converter/testdata/jsonnet.template.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
kind: template
|
||||
load: plugin.jsonnet
|
||||
data:
|
||||
stepName: my_step
|
||||
image: my_image
|
||||
commands: my_command
|
14
plugin/converter/testdata/single.jsonnet
vendored
Normal file
14
plugin/converter/testdata/single.jsonnet
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"kind": "pipeline",
|
||||
"name": "default",
|
||||
"steps": [
|
||||
{
|
||||
"commands": [
|
||||
"my_command"
|
||||
],
|
||||
"image": "my_image",
|
||||
"name": "my_step"
|
||||
}
|
||||
],
|
||||
"type": "docker"
|
||||
}
|
14
plugin/converter/testdata/starlark.input.star
vendored
Normal file
14
plugin/converter/testdata/starlark.input.star
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
def main(ctx):
|
||||
return {
|
||||
"kind": "pipeline",
|
||||
"name": "build",
|
||||
"steps": [
|
||||
{
|
||||
"name": ctx.input.stepName,
|
||||
"image": ctx.input.image,
|
||||
"commands": [
|
||||
ctx.input.commands
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
1
plugin/converter/testdata/starlark.input.star.golden
vendored
Normal file
1
plugin/converter/testdata/starlark.input.star.golden
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"kind": "pipeline", "name": "build", "steps": [{"name": "my_step", "image": "my_image", "commands": ["my_command"]}]}
|
6
plugin/converter/testdata/starlark.template.yml
vendored
Normal file
6
plugin/converter/testdata/starlark.template.yml
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
kind: template
|
||||
load: plugin.starlark
|
||||
data:
|
||||
stepName: my_step
|
||||
image: my_image
|
||||
commands: my_command
|
|
@ -28,7 +28,7 @@ import (
|
|||
)
|
||||
|
||||
// Encrypted returns a new encrypted registry credentials
|
||||
// provider that sournces credentials from the encrypted strings
|
||||
// provider that sources credentials from the encrypted strings
|
||||
// in the yaml file.
|
||||
func Encrypted() core.RegistryService {
|
||||
return new(encrypted)
|
||||
|
|
|
@ -67,7 +67,7 @@ func TestEndpointSource_Err(t *testing.T) {
|
|||
service := EndpointSource("https://company.com/auths", "GMEuUHQfmrMRsseWxi9YlIeBtn9lm6im", false)
|
||||
_, err := service.List(noContext, &core.RegistryArgs{Repo: &core.Repository{}, Build: &core.Build{}})
|
||||
if err == nil {
|
||||
t.Errorf("Expect http.Reponse error")
|
||||
t.Errorf("Expect http.Response error")
|
||||
} else if err.Error() != "Not Found" {
|
||||
t.Errorf("Expect Not Found error")
|
||||
}
|
||||
|
|
|
@ -147,7 +147,7 @@ func (q *queue) signal(ctx context.Context) error {
|
|||
continue
|
||||
}
|
||||
|
||||
// if the system defines concurrencly limits
|
||||
// if the system defines concurrency limits
|
||||
// per repository we need to make sure those limits
|
||||
// are not exceeded before proceeding.
|
||||
if shouldThrottle(item, items, item.LimitRepo) == true {
|
||||
|
@ -266,7 +266,8 @@ func withinLimits(stage *core.Stage, siblings []*core.Stage) bool {
|
|||
if sibling.Name != stage.Name {
|
||||
continue
|
||||
}
|
||||
if sibling.ID < stage.ID {
|
||||
if sibling.ID < stage.ID ||
|
||||
sibling.Status == core.StatusRunning {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
@ -274,7 +275,7 @@ func withinLimits(stage *core.Stage, siblings []*core.Stage) bool {
|
|||
}
|
||||
|
||||
func shouldThrottle(stage *core.Stage, siblings []*core.Stage, limit int) bool {
|
||||
// if no throttle limit is defined (defualt) then
|
||||
// if no throttle limit is defined (default) then
|
||||
// return false to indicate no throttling is needed.
|
||||
if limit == 0 {
|
||||
return false
|
||||
|
|
|
@ -115,42 +115,6 @@ func TestQueuePush(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestWithinLimits(t *testing.T) {
|
||||
tests := []struct {
|
||||
ID int64
|
||||
RepoID int64
|
||||
Name string
|
||||
Limit int
|
||||
Want bool
|
||||
}{
|
||||
{Want: true, ID: 1, RepoID: 1, Name: "foo"},
|
||||
{Want: true, ID: 2, RepoID: 2, Name: "bar", Limit: 1},
|
||||
{Want: true, ID: 3, RepoID: 1, Name: "bar", Limit: 1},
|
||||
{Want: false, ID: 4, RepoID: 1, Name: "bar", Limit: 1},
|
||||
{Want: false, ID: 5, RepoID: 1, Name: "bar", Limit: 1},
|
||||
{Want: true, ID: 6, RepoID: 1, Name: "baz", Limit: 2},
|
||||
{Want: true, ID: 7, RepoID: 1, Name: "baz", Limit: 2},
|
||||
{Want: false, ID: 8, RepoID: 1, Name: "baz", Limit: 2},
|
||||
{Want: false, ID: 9, RepoID: 1, Name: "baz", Limit: 2},
|
||||
{Want: true, ID: 10, RepoID: 1, Name: "baz", Limit: 0},
|
||||
}
|
||||
var stages []*core.Stage
|
||||
for _, test := range tests {
|
||||
stages = append(stages, &core.Stage{
|
||||
ID: test.ID,
|
||||
RepoID: test.RepoID,
|
||||
Name: test.Name,
|
||||
Limit: test.Limit,
|
||||
})
|
||||
}
|
||||
for i, test := range tests {
|
||||
stage := stages[i]
|
||||
if got, want := withinLimits(stage, stages), test.Want; got != want {
|
||||
t.Errorf("Unexpectd results at index %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestMatchResource(t *testing.T) {
|
||||
tests := []struct {
|
||||
kinda, typea, kindb, typeb string
|
||||
|
@ -184,7 +148,7 @@ func TestMatchResource(t *testing.T) {
|
|||
for i, test := range tests {
|
||||
got, want := matchResource(test.kinda, test.typea, test.kindb, test.typeb), test.want
|
||||
if got != want {
|
||||
t.Errorf("Unexpectd results at index %d", i)
|
||||
t.Errorf("Unexpected results at index %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -229,7 +193,166 @@ func TestShouldThrottle(t *testing.T) {
|
|||
for i, test := range tests {
|
||||
stage := stages[i]
|
||||
if got, want := shouldThrottle(stage, stages, stage.LimitRepo), test.Want; got != want {
|
||||
t.Errorf("Unexpectd results at index %d", i)
|
||||
t.Errorf("Unexpected results at index %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithinLimits(t *testing.T) {
|
||||
tests := []struct {
|
||||
result bool
|
||||
stage *core.Stage
|
||||
stages []*core.Stage
|
||||
}{
|
||||
// multiple stages executing for same repository and with same
|
||||
// name, but no concurrency limits exist. expect true.
|
||||
{
|
||||
result: true,
|
||||
stage: &core.Stage{
|
||||
ID: 3, RepoID: 1, Name: "build", Limit: 0,
|
||||
},
|
||||
stages: []*core.Stage{
|
||||
{ID: 1, RepoID: 1, Name: "build", Status: "running"},
|
||||
{ID: 2, RepoID: 1, Name: "build", Status: "running"},
|
||||
{ID: 3, RepoID: 1, Name: "build", Status: "pending"},
|
||||
},
|
||||
},
|
||||
|
||||
// stage with concurrency 1, no existing stages
|
||||
// exist for same repository id. expect true.
|
||||
{
|
||||
result: true,
|
||||
stage: &core.Stage{
|
||||
ID: 3, RepoID: 2, Name: "build", Limit: 0,
|
||||
},
|
||||
stages: []*core.Stage{
|
||||
{ID: 1, RepoID: 1, Name: "build", Status: "running"},
|
||||
{ID: 2, RepoID: 1, Name: "build", Status: "running"},
|
||||
{ID: 3, RepoID: 2, Name: "build", Status: "pending"},
|
||||
},
|
||||
},
|
||||
|
||||
// stage with concurrency 1, no existing stages
|
||||
// exist for same stage name. expect true.
|
||||
{
|
||||
result: true,
|
||||
stage: &core.Stage{
|
||||
ID: 3, RepoID: 1, Name: "build", Limit: 0,
|
||||
},
|
||||
stages: []*core.Stage{
|
||||
{ID: 1, RepoID: 1, Name: "test", Status: "running"},
|
||||
{ID: 2, RepoID: 1, Name: "test", Status: "running"},
|
||||
{ID: 3, RepoID: 1, Name: "build", Status: "pending"},
|
||||
},
|
||||
},
|
||||
|
||||
// single stage with concurrency 1, no existing stages
|
||||
// exist. expect true.
|
||||
{
|
||||
result: true,
|
||||
stage: &core.Stage{
|
||||
ID: 1, RepoID: 1, Name: "build", Limit: 1,
|
||||
},
|
||||
stages: []*core.Stage{
|
||||
{ID: 1, RepoID: 1, Name: "build", Status: "pending"},
|
||||
},
|
||||
},
|
||||
|
||||
// stage with concurrency 1, other named stages
|
||||
// exist in the queue, but they come after this stage.
|
||||
// expect true.
|
||||
{
|
||||
result: true,
|
||||
stage: &core.Stage{
|
||||
ID: 1, RepoID: 1, Name: "build", Limit: 1,
|
||||
},
|
||||
stages: []*core.Stage{
|
||||
{ID: 1, RepoID: 1, Name: "build", Status: "pending"},
|
||||
{ID: 2, RepoID: 1, Name: "build", Status: "pending"},
|
||||
},
|
||||
},
|
||||
|
||||
// stage with concurrency 1, however, stage with same
|
||||
// repository and name is already executing. expect false.
|
||||
{
|
||||
result: false,
|
||||
stage: &core.Stage{
|
||||
ID: 2, RepoID: 1, Name: "build", Limit: 1,
|
||||
},
|
||||
stages: []*core.Stage{
|
||||
{ID: 1, RepoID: 1, Name: "build", Status: "running"},
|
||||
{ID: 2, RepoID: 1, Name: "build", Status: "pending"},
|
||||
},
|
||||
},
|
||||
|
||||
// stage with concurrency 2. one existing stage in the
|
||||
// queue before this stage. expect true.
|
||||
{
|
||||
result: true,
|
||||
stage: &core.Stage{
|
||||
ID: 2, RepoID: 1, Name: "build", Limit: 2,
|
||||
},
|
||||
stages: []*core.Stage{
|
||||
{ID: 1, RepoID: 1, Name: "build", Status: "running"},
|
||||
{ID: 2, RepoID: 1, Name: "build", Status: "pending"},
|
||||
{ID: 3, RepoID: 1, Name: "build", Status: "pending"},
|
||||
},
|
||||
},
|
||||
|
||||
// stage with concurrency 1. stages start out of order, and the
|
||||
// second named stage starts before its predecessor. Its predecessor
|
||||
// should not execute. expect false.
|
||||
{
|
||||
result: false,
|
||||
stage: &core.Stage{
|
||||
ID: 1, RepoID: 1, Name: "build", Limit: 1,
|
||||
},
|
||||
stages: []*core.Stage{
|
||||
{ID: 1, RepoID: 1, Name: "build", Status: "pending"},
|
||||
{ID: 2, RepoID: 1, Name: "build", Status: "running"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i, test := range tests {
|
||||
if got, want := withinLimits(test.stage, test.stages), test.result; got != want {
|
||||
t.Errorf("Unexpected results at index %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestWithinLimits_Old(t *testing.T) {
|
||||
tests := []struct {
|
||||
ID int64
|
||||
RepoID int64
|
||||
Name string
|
||||
Limit int
|
||||
Want bool
|
||||
}{
|
||||
{Want: true, ID: 1, RepoID: 1, Name: "foo"},
|
||||
{Want: true, ID: 2, RepoID: 2, Name: "bar", Limit: 1},
|
||||
{Want: true, ID: 3, RepoID: 1, Name: "bar", Limit: 1},
|
||||
{Want: false, ID: 4, RepoID: 1, Name: "bar", Limit: 1},
|
||||
{Want: false, ID: 5, RepoID: 1, Name: "bar", Limit: 1},
|
||||
{Want: true, ID: 6, RepoID: 1, Name: "baz", Limit: 2},
|
||||
{Want: true, ID: 7, RepoID: 1, Name: "baz", Limit: 2},
|
||||
{Want: false, ID: 8, RepoID: 1, Name: "baz", Limit: 2},
|
||||
{Want: false, ID: 9, RepoID: 1, Name: "baz", Limit: 2},
|
||||
{Want: true, ID: 10, RepoID: 1, Name: "baz", Limit: 0},
|
||||
}
|
||||
var stages []*core.Stage
|
||||
for _, test := range tests {
|
||||
stages = append(stages, &core.Stage{
|
||||
ID: test.ID,
|
||||
RepoID: test.RepoID,
|
||||
Name: test.Name,
|
||||
Limit: test.Limit,
|
||||
})
|
||||
}
|
||||
for i, test := range tests {
|
||||
stage := stages[i]
|
||||
if got, want := withinLimits(stage, stages), test.Want; got != want {
|
||||
t.Errorf("Unexpected results at index %d", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
0
scripts/build.sh
Normal file → Executable file
0
scripts/build.sh
Normal file → Executable file
|
@ -20,6 +20,7 @@ import (
|
|||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"golang.org/x/crypto/acme/autocert"
|
||||
"golang.org/x/sync/errgroup"
|
||||
|
@ -36,6 +37,8 @@ type Server struct {
|
|||
Handler http.Handler
|
||||
}
|
||||
|
||||
const timeoutGracefulShutdown = 5 * time.Second
|
||||
|
||||
// ListenAndServe initializes a server to respond to HTTP network requests.
|
||||
func (s Server) ListenAndServe(ctx context.Context) error {
|
||||
if s.Acme {
|
||||
|
@ -43,7 +46,11 @@ func (s Server) ListenAndServe(ctx context.Context) error {
|
|||
} else if s.Key != "" {
|
||||
return s.listenAndServeTLS(ctx)
|
||||
}
|
||||
return s.listenAndServe(ctx)
|
||||
err := s.listenAndServe(ctx)
|
||||
if err == http.ErrServerClosed {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (s Server) listenAndServe(ctx context.Context) error {
|
||||
|
@ -53,10 +60,12 @@ func (s Server) listenAndServe(ctx context.Context) error {
|
|||
Handler: s.Handler,
|
||||
}
|
||||
g.Go(func() error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return s1.Shutdown(ctx)
|
||||
}
|
||||
<-ctx.Done()
|
||||
|
||||
ctxShutdown, cancelFunc := context.WithTimeout(context.Background(), timeoutGracefulShutdown)
|
||||
defer cancelFunc()
|
||||
|
||||
return s1.Shutdown(ctxShutdown)
|
||||
})
|
||||
g.Go(s1.ListenAndServe)
|
||||
return g.Wait()
|
||||
|
@ -80,12 +89,20 @@ func (s Server) listenAndServeTLS(ctx context.Context) error {
|
|||
)
|
||||
})
|
||||
g.Go(func() error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
s1.Shutdown(ctx)
|
||||
s2.Shutdown(ctx)
|
||||
return nil
|
||||
}
|
||||
<-ctx.Done()
|
||||
|
||||
var gShutdown errgroup.Group
|
||||
ctxShutdown, cancelFunc := context.WithTimeout(context.Background(), timeoutGracefulShutdown)
|
||||
defer cancelFunc()
|
||||
|
||||
gShutdown.Go(func() error {
|
||||
return s1.Shutdown(ctxShutdown)
|
||||
})
|
||||
gShutdown.Go(func() error {
|
||||
return s2.Shutdown(ctxShutdown)
|
||||
})
|
||||
|
||||
return gShutdown.Wait()
|
||||
})
|
||||
return g.Wait()
|
||||
}
|
||||
|
@ -118,12 +135,20 @@ func (s Server) listenAndServeAcme(ctx context.Context) error {
|
|||
return s2.ListenAndServeTLS("", "")
|
||||
})
|
||||
g.Go(func() error {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
s1.Shutdown(ctx)
|
||||
s2.Shutdown(ctx)
|
||||
return nil
|
||||
}
|
||||
<-ctx.Done()
|
||||
|
||||
var gShutdown errgroup.Group
|
||||
ctxShutdown, cancelFunc := context.WithTimeout(context.Background(), timeoutGracefulShutdown)
|
||||
defer cancelFunc()
|
||||
|
||||
gShutdown.Go(func() error {
|
||||
return s1.Shutdown(ctxShutdown)
|
||||
})
|
||||
gShutdown.Go(func() error {
|
||||
return s2.Shutdown(ctxShutdown)
|
||||
})
|
||||
|
||||
return gShutdown.Wait()
|
||||
})
|
||||
return g.Wait()
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ func (r *Reaper) Start(ctx context.Context, dur time.Duration) error {
|
|||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
return nil
|
||||
case <-ticker.C:
|
||||
r.reap(ctx)
|
||||
}
|
||||
|
|
|
@ -79,6 +79,7 @@ func (s *service) FindRef(ctx context.Context, user *core.User, repo, ref string
|
|||
|
||||
switch s.client.Driver {
|
||||
case scm.DriverBitbucket:
|
||||
case scm.DriverStash:
|
||||
ref = scm.TrimRef(ref)
|
||||
branch, _, err := s.client.Git.FindBranch(ctx, repo, ref) // wont work for a Tag
|
||||
if err != nil {
|
||||
|
|
|
@ -49,7 +49,7 @@ type service struct {
|
|||
func (s *service) Find(ctx context.Context, user *core.User, repo, commit, ref, path string) (*core.File, error) {
|
||||
// TODO(gogs) ability to fetch a yaml by pull request ref.
|
||||
// it is not currently possible to fetch the yaml
|
||||
// configuation file from a pull request sha. This
|
||||
// configuration file from a pull request sha. This
|
||||
// workaround defaults to master.
|
||||
if s.client.Driver == scm.DriverGogs &&
|
||||
strings.HasPrefix(ref, "refs/pull") {
|
||||
|
|
2
service/hook/parser/testdata/gitea_push.json
vendored
2
service/hook/parser/testdata/gitea_push.json
vendored
|
@ -38,4 +38,4 @@
|
|||
"Email": "noreply@gogs.io",
|
||||
"Avatar": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
service/hook/parser/testdata/gitea_tag.json
vendored
2
service/hook/parser/testdata/gitea_tag.json
vendored
|
@ -23,4 +23,4 @@
|
|||
"Email": "noreply@gogs.io",
|
||||
"Avatar": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,4 +40,4 @@
|
|||
"Email": "noreply@gogs.io",
|
||||
"Avatar": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
service/hook/parser/testdata/gogs_push.json
vendored
2
service/hook/parser/testdata/gogs_push.json
vendored
|
@ -38,4 +38,4 @@
|
|||
"Email": "noreply@gogs.io",
|
||||
"Avatar": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
2
service/hook/parser/testdata/gogs_tag.json
vendored
2
service/hook/parser/testdata/gogs_tag.json
vendored
|
@ -23,4 +23,4 @@
|
|||
"Email": "noreply@gogs.io",
|
||||
"Avatar": "https://secure.gravatar.com/avatar/8c58a0be77ee441bb8f8595b7f1b4e87"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ import (
|
|||
"github.com/drone/go-scm/scm"
|
||||
)
|
||||
|
||||
// merge is a helper function that mergest a subset of
|
||||
// merge is a helper function that merges a subset of
|
||||
// values from the source to the destination repository.
|
||||
func merge(dst, src *core.Repository) {
|
||||
dst.Namespace = src.Namespace
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue