mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-12-30 04:10:32 +00:00
Change pipeline config path resolution (#299)
# Config resolution - pipeline-config setting empty / not specified (default): `.woodpecker/` => `.woodpecker.yml` => `.drone.yml` - pipeline-config setting defined by user: try that file / folder and no fallback (if a user sets some special value that is normally done for some reason) # Changes - pipeline-config setting will be empty by default - remove fallback setting for config loading (simplifies config) --- closes #133 --- * adjust config fetching mechanism * default path empty * remove fallback flag from ui and db
This commit is contained in:
parent
d4ab506507
commit
289f0c9ad6
23 changed files with 331 additions and 183 deletions
|
@ -89,12 +89,6 @@ var flags = []cli.Flag{
|
|||
Name: "open",
|
||||
Usage: "enable open user registration",
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "DRONE_REPO_CONFIG,WOODPECKER_REPO_CONFIG",
|
||||
Name: "repo-config",
|
||||
Usage: "file path for the drone config",
|
||||
Value: ".drone.yml",
|
||||
},
|
||||
cli.StringFlag{
|
||||
EnvVar: "DRONE_DOCS,WOODPECKER_DOCS",
|
||||
Name: "docs",
|
||||
|
|
|
@ -20,11 +20,9 @@ When you activate your repository Woodpecker automatically add webhooks to your
|
|||
|
||||
Webhooks are used to trigger pipeline executions. When you push code to your repository, open a pull request, or create a tag, your version control system will automatically send a webhook to Woodpecker which will in turn trigger pipeline execution.
|
||||
|
||||
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure you pipeline you should place a `.woodpecker.yml` file in the root of your repository. The .woodpecker.yml file is used to define your pipeline steps. It is a superset of the widely used docker-compose file format.
|
||||
To configure your pipeline you should place a `.woodpecker.yml` file in the root of your repository. The .woodpecker.yml file is used to define your pipeline steps. It is a superset of the widely used docker-compose file format.
|
||||
|
||||
Example pipeline configuration:
|
||||
|
||||
|
|
|
@ -6,9 +6,7 @@ As the owner of a project in Woodpecker you can change some project related sett
|
|||
|
||||
## Pipeline path
|
||||
|
||||
The path to the pipeline file or folder. By default it point `.woodpecker.yml`. To use a [multi pipeline](/docs/usage/multi-pipeline) you have to change it to a folder path ending with `/` like `.woodpecker/`.
|
||||
|
||||
If you enable the fallback check, Woodpecker will first try to load the configuration from the defined path and if it fails to find that file it will try to use `.drone.yml`.
|
||||
The path to the pipeline config file or folder. By default it is left empty which will use the following configuration resolution `.woodpecker/*.yml` -> `.woodpecker.yml` -> `.drone.yml`. If you set a custom path Woodpecker tries to load your configuration or fails if no configuration could be found at the specified location. To use a [multi pipeline](/docs/usage/multi-pipeline) you have to change it to a folder path ending with a `/` like `.woodpecker/`.
|
||||
|
||||
## Repository hooks
|
||||
|
||||
|
|
|
@ -4,11 +4,14 @@ Some versions need some changes to the server configuration or the pipeline conf
|
|||
|
||||
## 0.15.0
|
||||
|
||||
- Default pipeline path changed to `.woodpecker/`
|
||||
- Default value for custom pipeline path is now empty / un-set which results in following resolution:
|
||||
|
||||
`.woodpecker/*.yml` -> `.woodpecker.yml` -> `.drone.yml`
|
||||
|
||||
Only projects created after updating will have an empty value by default. Existing projects will stick to the current pipeline path which is `.drone.yml` in most cases.
|
||||
|
||||
Read more about it at the [Project Settings](/docs/usage/project-settings#pipeline-path)
|
||||
|
||||
**Solution:** Set configuration location via [project settings](/docs/usage/project-settings#pipeline-path).
|
||||
|
||||
There is still a default fallback mechanism in following order: `.woodpecker/*.yml` -> `.woodpecker.yml` -> `.drone.yml`
|
||||
- ...
|
||||
|
||||
## 0.14.0
|
||||
|
|
|
@ -55,7 +55,6 @@ type Repo struct {
|
|||
Config string `json:"config_file" meddler:"repo_config_path"`
|
||||
Hash string `json:"-" meddler:"repo_hash"`
|
||||
Perm *Perm `json:"-" meddler:"-"`
|
||||
Fallback bool `json:"fallback" meddler:"repo_fallback"`
|
||||
}
|
||||
|
||||
func (r *Repo) ResetVisibility() {
|
||||
|
@ -106,5 +105,4 @@ type RepoPatch struct {
|
|||
AllowDeploy *bool `json:"allow_deploy,omitempty"`
|
||||
AllowTag *bool `json:"allow_tag,omitempty"`
|
||||
BuildCounter *int `json:"build_counter,omitempty"`
|
||||
Fallback *bool `json:"fallback,omitempty"`
|
||||
}
|
||||
|
|
|
@ -429,7 +429,7 @@ func PostBuild(c *gin.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// fetch the .drone.yml file from the database
|
||||
// fetch the pipeline config from database
|
||||
configs, err := Config.Storage.Config.ConfigsForBuild(build.ID)
|
||||
if err != nil {
|
||||
logrus.Errorf("failure to get build config for %s. %s", repo.FullName, err)
|
||||
|
|
|
@ -30,28 +30,43 @@ func (cf *configFetcher) Fetch() (files []*remote.FileMeta, err error) {
|
|||
for i := 0; i < 5; i++ {
|
||||
select {
|
||||
case <-time.After(time.Second * time.Duration(i)):
|
||||
|
||||
// either a file
|
||||
if !strings.HasSuffix(cf.repo.Config, "/") {
|
||||
file, err = cf.remote_.File(cf.user, cf.repo, cf.build, cf.repo.Config)
|
||||
if err == nil {
|
||||
return []*remote.FileMeta{{
|
||||
Name: cf.repo.Config,
|
||||
Data: file,
|
||||
}}, nil
|
||||
if len(cf.repo.Config) > 0 {
|
||||
// either a file
|
||||
if !strings.HasSuffix(cf.repo.Config, "/") {
|
||||
file, err = cf.remote_.File(cf.user, cf.repo, cf.build, cf.repo.Config)
|
||||
if err == nil {
|
||||
return []*remote.FileMeta{{
|
||||
Name: cf.repo.Config,
|
||||
Data: file,
|
||||
}}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// or a folder
|
||||
if strings.HasSuffix(cf.repo.Config, "/") {
|
||||
files, err = cf.remote_.Dir(cf.user, cf.repo, cf.build, strings.TrimSuffix(cf.repo.Config, "/"))
|
||||
// or a folder
|
||||
if strings.HasSuffix(cf.repo.Config, "/") {
|
||||
files, err = cf.remote_.Dir(cf.user, cf.repo, cf.build, strings.TrimSuffix(cf.repo.Config, "/"))
|
||||
if err == nil {
|
||||
return filterPipelineFiles(files), nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// no user defined config so try .woodpecker/*.yml -> .woodpecker.yml -> .drone.yml
|
||||
|
||||
// test .woodpecker/ folder
|
||||
// if folder is not supported we will get a "Not implemented" error and continue
|
||||
files, err = cf.remote_.Dir(cf.user, cf.repo, cf.build, ".woodpecker")
|
||||
if err == nil {
|
||||
return filterPipelineFiles(files), nil
|
||||
}
|
||||
}
|
||||
|
||||
// or fallback
|
||||
if cf.repo.Fallback {
|
||||
file, err = cf.remote_.File(cf.user, cf.repo, cf.build, ".woodpecker.yml")
|
||||
if err == nil {
|
||||
return []*remote.FileMeta{{
|
||||
Name: ".woodpecker.yml",
|
||||
Data: file,
|
||||
}}, nil
|
||||
}
|
||||
|
||||
file, err = cf.remote_.File(cf.user, cf.repo, cf.build, ".drone.yml")
|
||||
if err == nil {
|
||||
return []*remote.FileMeta{{
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
package server_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
@ -15,61 +16,19 @@ func TestFetch(t *testing.T) {
|
|||
t.Parallel()
|
||||
|
||||
testTable := []struct {
|
||||
name string
|
||||
repoConfig string
|
||||
repoFallback bool
|
||||
fileMocks []struct {
|
||||
file []byte
|
||||
err error
|
||||
}
|
||||
dirMock struct {
|
||||
files []*remote.FileMeta
|
||||
err error
|
||||
}
|
||||
name string
|
||||
repoConfig string
|
||||
files []string
|
||||
expectedFileNames []string
|
||||
expectedError bool
|
||||
}{
|
||||
{
|
||||
name: "Single .woodpecker.yml file",
|
||||
repoConfig: ".woodpecker.yml",
|
||||
repoFallback: false,
|
||||
fileMocks: []struct {
|
||||
file []byte
|
||||
err error
|
||||
}{
|
||||
{
|
||||
file: []byte{},
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".woodpecker.yml",
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Folder .woodpecker/",
|
||||
repoConfig: ".woodpecker/",
|
||||
repoFallback: false,
|
||||
dirMock: struct {
|
||||
files []*remote.FileMeta
|
||||
err error
|
||||
}{
|
||||
files: []*remote.FileMeta{
|
||||
{
|
||||
Name: ".woodpecker/text.txt",
|
||||
Data: []byte{},
|
||||
},
|
||||
{
|
||||
Name: ".woodpecker/release.yml",
|
||||
Data: []byte{},
|
||||
},
|
||||
{
|
||||
Name: ".woodpecker/image.png",
|
||||
Data: []byte{},
|
||||
},
|
||||
},
|
||||
err: nil,
|
||||
name: "Default config - .woodpecker/",
|
||||
repoConfig: "",
|
||||
files: []string{
|
||||
".woodpecker/text.txt",
|
||||
".woodpecker/release.yml",
|
||||
".woodpecker/image.png",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".woodpecker/release.yml",
|
||||
|
@ -77,23 +36,21 @@ func TestFetch(t *testing.T) {
|
|||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Requesting woodpecker-file but using fallback",
|
||||
repoConfig: ".woodpecker.yml",
|
||||
repoFallback: true,
|
||||
fileMocks: []struct {
|
||||
file []byte
|
||||
err error
|
||||
}{
|
||||
// first call requesting regular woodpecker.yml
|
||||
{
|
||||
file: nil,
|
||||
err: errors.New("File not found"),
|
||||
},
|
||||
// fallback file call
|
||||
{
|
||||
file: []byte{},
|
||||
err: nil,
|
||||
},
|
||||
name: "Default config - .woodpecker.yml",
|
||||
repoConfig: "",
|
||||
files: []string{
|
||||
".woodpecker.yml",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".woodpecker.yml",
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Default config - .drone.yml",
|
||||
repoConfig: "",
|
||||
files: []string{
|
||||
".drone.yml",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".drone.yml",
|
||||
|
@ -101,49 +58,99 @@ func TestFetch(t *testing.T) {
|
|||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Requesting folder but using fallback",
|
||||
repoConfig: ".woodpecker/",
|
||||
repoFallback: true,
|
||||
fileMocks: []struct {
|
||||
file []byte
|
||||
err error
|
||||
}{
|
||||
{
|
||||
file: []byte{},
|
||||
err: nil,
|
||||
},
|
||||
},
|
||||
dirMock: struct {
|
||||
files []*remote.FileMeta
|
||||
err error
|
||||
}{
|
||||
files: []*remote.FileMeta{},
|
||||
err: errors.New("Dir not found"),
|
||||
name: "Default config - Empty repo",
|
||||
repoConfig: "",
|
||||
files: []string{},
|
||||
expectedFileNames: []string{},
|
||||
expectedError: true,
|
||||
},
|
||||
{
|
||||
name: "Default config - Additional sub-folders",
|
||||
repoConfig: "",
|
||||
files: []string{
|
||||
".woodpecker/test.yml",
|
||||
".woodpecker/sub-folder/config.yml",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".drone.yml",
|
||||
".woodpecker/test.yml",
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Not found and disabled fallback",
|
||||
repoConfig: ".woodpecker.yml",
|
||||
repoFallback: false,
|
||||
fileMocks: []struct {
|
||||
file []byte
|
||||
err error
|
||||
}{
|
||||
// first call requesting regular woodpecker.yml
|
||||
{
|
||||
file: nil,
|
||||
err: errors.New("File not found"),
|
||||
},
|
||||
// fallback file call
|
||||
{
|
||||
file: []byte{},
|
||||
err: errors.New("File not found"),
|
||||
},
|
||||
name: "Default config - Additional none .yml files",
|
||||
repoConfig: "",
|
||||
files: []string{
|
||||
".woodpecker/notes.txt",
|
||||
".woodpecker/image.png",
|
||||
".woodpecker/test.yml",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".woodpecker/test.yml",
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Special config - folder (ignoring default files)",
|
||||
repoConfig: ".my-ci-folder/",
|
||||
files: []string{
|
||||
".woodpecker/test.yml",
|
||||
".woodpecker.yml",
|
||||
".drone.yml",
|
||||
".my-ci-folder/test.yml",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".my-ci-folder/test.yml",
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Special config - folder",
|
||||
repoConfig: ".my-ci-folder/",
|
||||
files: []string{
|
||||
".my-ci-folder/test.yml",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".my-ci-folder/test.yml",
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Special config - subfolder",
|
||||
repoConfig: ".my-ci-folder/my-config/",
|
||||
files: []string{
|
||||
".my-ci-folder/my-config/test.yml",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".my-ci-folder/my-config/test.yml",
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Special config - file",
|
||||
repoConfig: ".config.yml",
|
||||
files: []string{
|
||||
".config.yml",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".config.yml",
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Special config - file inside subfolder",
|
||||
repoConfig: ".my-ci-folder/sub-folder/config.yml",
|
||||
files: []string{
|
||||
".my-ci-folder/sub-folder/config.yml",
|
||||
},
|
||||
expectedFileNames: []string{
|
||||
".my-ci-folder/sub-folder/config.yml",
|
||||
},
|
||||
expectedError: false,
|
||||
},
|
||||
{
|
||||
name: "Special config - empty repo",
|
||||
repoConfig: ".config.yml",
|
||||
files: []string{},
|
||||
expectedFileNames: []string{},
|
||||
expectedError: true,
|
||||
},
|
||||
|
@ -151,13 +158,26 @@ func TestFetch(t *testing.T) {
|
|||
|
||||
for _, tt := range testTable {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
repo := &model.Repo{Owner: "laszlocph", Name: "drone-multipipeline", Config: tt.repoConfig, Fallback: tt.repoFallback}
|
||||
repo := &model.Repo{Owner: "laszlocph", Name: "drone-multipipeline", Config: tt.repoConfig}
|
||||
|
||||
r := new(mocks.Remote)
|
||||
for _, fileMock := range tt.fileMocks {
|
||||
r.On("File", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(fileMock.file, fileMock.err).Once()
|
||||
dirs := map[string][]*remote.FileMeta{}
|
||||
for _, file := range tt.files {
|
||||
r.On("File", mock.Anything, mock.Anything, mock.Anything, file).Return([]byte{}, nil)
|
||||
path := filepath.Dir(file)
|
||||
dirs[path] = append(dirs[path], &remote.FileMeta{
|
||||
Name: file,
|
||||
Data: []byte{},
|
||||
})
|
||||
}
|
||||
r.On("Dir", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tt.dirMock.files, tt.dirMock.err)
|
||||
|
||||
for path, files := range dirs {
|
||||
r.On("Dir", mock.Anything, mock.Anything, mock.Anything, path).Return(files, nil)
|
||||
}
|
||||
|
||||
// if the previous mocks do not match return not found errors
|
||||
r.On("File", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("File not found"))
|
||||
r.On("Dir", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, fmt.Errorf("Directory not found"))
|
||||
|
||||
configFetcher := server.NewConfigFetcher(
|
||||
r,
|
||||
|
@ -182,7 +202,11 @@ func TestFetch(t *testing.T) {
|
|||
}
|
||||
|
||||
if matchingFiles != len(tt.expectedFileNames) {
|
||||
t.Fatal("expected some other pipeline files", tt.expectedFileNames, files)
|
||||
receivedFileNames := []string{}
|
||||
for _, file := range files {
|
||||
receivedFileNames = append(receivedFileNames, file.Name)
|
||||
}
|
||||
t.Fatal("expected some other pipeline files", tt.expectedFileNames, receivedFileNames)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -52,9 +52,6 @@ func PostRepo(c *gin.Context) {
|
|||
repo.Visibility = model.VisibilityPrivate
|
||||
}
|
||||
}
|
||||
if repo.Config == "" {
|
||||
repo.Config = Config.Server.RepoConfig
|
||||
}
|
||||
if repo.Timeout == 0 {
|
||||
repo.Timeout = 60 // 1 hour default build time
|
||||
}
|
||||
|
@ -149,9 +146,6 @@ func PatchRepo(c *gin.Context) {
|
|||
if in.BuildCounter != nil {
|
||||
repo.Counter = *in.BuildCounter
|
||||
}
|
||||
if in.Fallback != nil {
|
||||
repo.Fallback = *in.Fallback
|
||||
}
|
||||
|
||||
err := store.UpdateRepo(c, repo)
|
||||
if err != nil {
|
||||
|
|
|
@ -200,6 +200,10 @@ var migrations = []struct {
|
|||
name: "update-builds-set-changed_files",
|
||||
stmt: updateBuildsSetChangedfiles,
|
||||
},
|
||||
{
|
||||
name: "alter-table-drop-repo-fallback",
|
||||
stmt: alterTableDropRepoFallback,
|
||||
},
|
||||
}
|
||||
|
||||
// Migrate performs the database migration. If the migration fails
|
||||
|
@ -745,3 +749,11 @@ ALTER TABLE builds ADD COLUMN changed_files TEXT
|
|||
var updateBuildsSetChangedfiles = `
|
||||
UPDATE builds SET changed_files='[]'
|
||||
`
|
||||
|
||||
//
|
||||
// 026_drop_repo_fallback_column.sql
|
||||
//
|
||||
|
||||
var alterTableDropRepoFallback = `
|
||||
ALTER TABLE repos DROP COLUMN repo_fallback
|
||||
`
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- name: alter-table-drop-repo-fallback
|
||||
ALTER TABLE repos DROP COLUMN repo_fallback
|
|
@ -200,6 +200,10 @@ var migrations = []struct {
|
|||
name: "update-builds-set-changed_files",
|
||||
stmt: updateBuildsSetChangedfiles,
|
||||
},
|
||||
{
|
||||
name: "alter-table-drop-repo-fallback",
|
||||
stmt: alterTableDropRepoFallback,
|
||||
},
|
||||
}
|
||||
|
||||
// Migrate performs the database migration. If the migration fails
|
||||
|
@ -747,3 +751,11 @@ ALTER TABLE builds ADD COLUMN changed_files TEXT;
|
|||
var updateBuildsSetChangedfiles = `
|
||||
UPDATE builds SET changed_files='[]'
|
||||
`
|
||||
|
||||
//
|
||||
// 026_drop_repo_fallback_column.sql
|
||||
//
|
||||
|
||||
var alterTableDropRepoFallback = `
|
||||
ALTER TABLE repos DROP COLUMN repo_fallback
|
||||
`
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
-- name: alter-table-drop-repo-fallback
|
||||
ALTER TABLE repos DROP COLUMN repo_fallback
|
|
@ -204,6 +204,10 @@ var migrations = []struct {
|
|||
name: "update-builds-set-changed_files",
|
||||
stmt: updateBuildsSetChangedfiles,
|
||||
},
|
||||
{
|
||||
name: "alter-table-drop-repo-fallback",
|
||||
stmt: alterTableDropRepoFallback,
|
||||
},
|
||||
}
|
||||
|
||||
// Migrate performs the database migration. If the migration fails
|
||||
|
@ -746,3 +750,65 @@ ALTER TABLE builds ADD COLUMN changed_files TEXT
|
|||
var updateBuildsSetChangedfiles = `
|
||||
UPDATE builds SET changed_files='[]'
|
||||
`
|
||||
|
||||
//
|
||||
// 026_drop_repo_fallback_column.sql
|
||||
//
|
||||
|
||||
var alterTableDropRepoFallback = `
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
CREATE TABLE repos_new (
|
||||
repo_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
repo_user_id INTEGER,
|
||||
repo_owner TEXT,
|
||||
repo_name TEXT,
|
||||
repo_full_name TEXT,
|
||||
repo_avatar TEXT,
|
||||
repo_link TEXT,
|
||||
repo_clone TEXT,
|
||||
repo_branch TEXT,
|
||||
repo_timeout INTEGER,
|
||||
repo_private BOOLEAN,
|
||||
repo_trusted BOOLEAN,
|
||||
repo_active BOOLEAN,
|
||||
repo_allow_pr BOOLEAN,
|
||||
repo_allow_push BOOLEAN,
|
||||
repo_allow_deploys BOOLEAN,
|
||||
repo_allow_tags BOOLEAN,
|
||||
repo_hash TEXT,
|
||||
repo_scm TEXT,
|
||||
repo_config_path TEXT,
|
||||
repo_gated BOOLEAN,
|
||||
repo_visibility TEXT,
|
||||
repo_counter INTEGER,
|
||||
UNIQUE(repo_full_name)
|
||||
);
|
||||
|
||||
INSERT INTO repos_new SELECT repo_id
|
||||
,repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter FROM repos;
|
||||
DROP TABLE repos;
|
||||
ALTER TABLE repos_new RENAME TO repos;
|
||||
COMMIT;
|
||||
`
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
-- name: alter-table-drop-repo-fallback
|
||||
BEGIN TRANSACTION;
|
||||
|
||||
CREATE TABLE repos_new (
|
||||
repo_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
repo_user_id INTEGER,
|
||||
repo_owner TEXT,
|
||||
repo_name TEXT,
|
||||
repo_full_name TEXT,
|
||||
repo_avatar TEXT,
|
||||
repo_link TEXT,
|
||||
repo_clone TEXT,
|
||||
repo_branch TEXT,
|
||||
repo_timeout INTEGER,
|
||||
repo_private BOOLEAN,
|
||||
repo_trusted BOOLEAN,
|
||||
repo_active BOOLEAN,
|
||||
repo_allow_pr BOOLEAN,
|
||||
repo_allow_push BOOLEAN,
|
||||
repo_allow_deploys BOOLEAN,
|
||||
repo_allow_tags BOOLEAN,
|
||||
repo_hash TEXT,
|
||||
repo_scm TEXT,
|
||||
repo_config_path TEXT,
|
||||
repo_gated BOOLEAN,
|
||||
repo_visibility TEXT,
|
||||
repo_counter INTEGER,
|
||||
UNIQUE(repo_full_name)
|
||||
);
|
||||
|
||||
INSERT INTO repos_new SELECT repo_id
|
||||
,repo_user_id
|
||||
,repo_owner
|
||||
,repo_name
|
||||
,repo_full_name
|
||||
,repo_avatar
|
||||
,repo_link
|
||||
,repo_clone
|
||||
,repo_branch
|
||||
,repo_timeout
|
||||
,repo_private
|
||||
,repo_trusted
|
||||
,repo_active
|
||||
,repo_allow_pr
|
||||
,repo_allow_push
|
||||
,repo_allow_deploys
|
||||
,repo_allow_tags
|
||||
,repo_hash
|
||||
,repo_scm
|
||||
,repo_config_path
|
||||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter FROM repos;
|
||||
DROP TABLE repos;
|
||||
ALTER TABLE repos_new RENAME TO repos;
|
||||
COMMIT;
|
|
@ -93,7 +93,6 @@ func (db *datastore) RepoBatch(repos []*model.Repo) error {
|
|||
repo.IsGated,
|
||||
repo.Visibility,
|
||||
repo.Counter,
|
||||
repo.Fallback,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
@ -30,7 +30,6 @@ SELECT
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
|
@ -61,8 +60,7 @@ INSERT IGNORE INTO repos (
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
-- name: repo-delete
|
||||
|
||||
|
|
|
@ -448,7 +448,6 @@ SELECT
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
|
@ -479,8 +478,7 @@ INSERT IGNORE INTO repos (
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
`
|
||||
|
||||
var repoDelete = `
|
||||
|
|
|
@ -30,7 +30,6 @@ SELECT
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = $1
|
||||
|
@ -61,8 +60,7 @@ INSERT INTO repos (
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23)
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22)
|
||||
ON CONFLICT (repo_full_name) DO NOTHING
|
||||
|
||||
-- name: repo-delete
|
||||
|
|
|
@ -451,7 +451,6 @@ SELECT
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = $1
|
||||
|
@ -482,8 +481,7 @@ INSERT INTO repos (
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23)
|
||||
) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22)
|
||||
ON CONFLICT (repo_full_name) DO NOTHING
|
||||
`
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ SELECT
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
|
@ -61,8 +60,7 @@ INSERT OR IGNORE INTO repos (
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
|
||||
-- name: repo-delete
|
||||
|
||||
|
|
|
@ -448,7 +448,6 @@ SELECT
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
FROM repos
|
||||
INNER JOIN perms ON perms.perm_repo_id = repos.repo_id
|
||||
WHERE perms.perm_user_id = ?
|
||||
|
@ -479,8 +478,7 @@ INSERT OR IGNORE INTO repos (
|
|||
,repo_gated
|
||||
,repo_visibility
|
||||
,repo_counter
|
||||
,repo_fallback
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)
|
||||
`
|
||||
|
||||
var repoDelete = `
|
||||
|
|
|
@ -41,7 +41,6 @@ export default class Settings extends Component {
|
|||
this.handleVisibilityChange = this.handleVisibilityChange.bind(this);
|
||||
this.handleTimeoutChange = this.handleTimeoutChange.bind(this);
|
||||
this.handlePathChange = this.handlePathChange.bind(this);
|
||||
this.handleFallbackChange = this.handleFallbackChange.bind(this);
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
}
|
||||
|
||||
|
@ -74,14 +73,6 @@ export default class Settings extends Component {
|
|||
value={repo.config_file}
|
||||
onBlur={this.handlePathChange}
|
||||
/>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={repo.fallback}
|
||||
onChange={this.handleFallbackChange}
|
||||
/>
|
||||
<span>Fallback to .drone.yml if path not exists</span>
|
||||
</label>
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
|
@ -231,10 +222,6 @@ export default class Settings extends Component {
|
|||
this.handleChange("config_file", e.target.value);
|
||||
}
|
||||
|
||||
handleFallbackChange(e) {
|
||||
this.handleChange("fallback", e.target.checked);
|
||||
}
|
||||
|
||||
handleChange(prop, value) {
|
||||
const { dispatch, drone, repo } = this.props;
|
||||
let data = {};
|
||||
|
|
Loading…
Reference in a new issue