mirror of
https://github.com/woodpecker-ci/woodpecker.git
synced 2024-06-02 13:39:55 +00:00
Merge branch 'main' into wp-go-opts
This commit is contained in:
commit
e4c65fe065
|
@ -4,6 +4,7 @@ tasks:
|
|||
WOODPECKER_OPEN: true
|
||||
WOODPECKER_ADMIN: woodpecker
|
||||
WOODPECKER_HOST: http://host.docker.internal:8000
|
||||
WOODPECKER_EXPERT_WEBHOOK_HOST: http://host.docker.internal:8000
|
||||
WOODPECKER_AGENT_SECRET: '1234'
|
||||
WOODPECKER_GITEA: true
|
||||
WOODPECKER_DEV_WWW_PROXY: http://localhost:8010
|
||||
|
@ -20,9 +21,9 @@ tasks:
|
|||
grep "WOODPECKER_GITEA_URL=" .env \
|
||||
&& sed "s,^WOODPECKER_GITEA_URL=.*,WOODPECKER_GITEA_URL=$(gp url 3000)," .env \
|
||||
|| echo WOODPECKER_GITEA_URL=$(gp url 3000) >> .env
|
||||
grep "WOODPECKER_DEV_OAUTH_HOST=" .env \
|
||||
&& sed "s,^WOODPECKER_DEV_OAUTH_HOST=.*,WOODPECKER_DEV_OAUTH_HOST=$(gp url 8000)," .env \
|
||||
|| echo WOODPECKER_DEV_OAUTH_HOST=$(gp url 8000) >> .env
|
||||
grep "WOODPECKER_HOST=" .env \
|
||||
&& sed "s,^WOODPECKER_HOST=.*,WOODPECKER_HOST=$(gp url 8000)," .env \
|
||||
|| echo WOODPECKER_HOST=$(gp url 8000) >> .env
|
||||
gp sync-await gitea
|
||||
gp sync-done woodpecker-server
|
||||
go run go.woodpecker-ci.org/woodpecker/v2/cmd/server
|
||||
|
|
|
@ -38,12 +38,7 @@ var flags = append([]cli.Flag{
|
|||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_HOST"},
|
||||
Name: "server-host",
|
||||
Usage: "server fully qualified url (<scheme>://<host>[/<prefixpath>])",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_WEBHOOK_HOST"},
|
||||
Name: "server-webhook-host",
|
||||
Usage: "server fully qualified url for forge's Webhooks (<scheme>://<host>[/<prefixpath>])",
|
||||
Usage: "server fully qualified url. Format: <scheme>://<host>[/<prefixpath>]",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_SERVER_ADDR"},
|
||||
|
@ -330,6 +325,11 @@ var flags = append([]cli.Flag{
|
|||
Usage: "skip ssl verification",
|
||||
EnvVars: []string{"WOODPECKER_FORGE_SKIP_VERIFY", "WOODPECKER_GITHUB_SKIP_VERIFY", "WOODPECKER_GITLAB_SKIP_VERIFY", "WOODPECKER_GITEA_SKIP_VERIFY", "WOODPECKER_BITBUCKET_SKIP_VERIFY"},
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_EXPERT_FORGE_OAUTH_HOST", "WOODPECKER_DEV_GITEA_OAUTH_URL"}, // TODO: remove WOODPECKER_DEV_GITEA_OAUTH_URL in next major release
|
||||
Name: "forge-oauth-host",
|
||||
Usage: "!!!for experts!!! fully qualified public forge url. Use it if your forge url WOODPECKER_FORGE_URL or WOODPECKER_GITEA_URL, ... isn't a public url. Format: <scheme>://<host>[/<prefixpath>]",
|
||||
},
|
||||
//
|
||||
// Addon
|
||||
//
|
||||
|
@ -366,11 +366,6 @@ var flags = append([]cli.Flag{
|
|||
Name: "gitea",
|
||||
Usage: "gitea driver is enabled",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_DEV_GITEA_OAUTH_URL"},
|
||||
Name: "gitea-oauth-server",
|
||||
Usage: "user-facing gitea server url for oauth",
|
||||
},
|
||||
//
|
||||
// Bitbucket
|
||||
//
|
||||
|
@ -416,10 +411,19 @@ var flags = append([]cli.Flag{
|
|||
Usage: "serve the website by using a proxy (used for development)",
|
||||
Hidden: true,
|
||||
},
|
||||
//
|
||||
// expert flags
|
||||
//
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_EXPERT_WEBHOOK_HOST", "WOODPECKER_WEBHOOK_HOST"}, // TODO: remove WOODPECKER_WEBHOOK_HOST in next major release
|
||||
Name: "server-webhook-host",
|
||||
Usage: "!!!for experts!!! fully qualified woodpecker server url called by forge's webhooks. Format: <scheme>://<host>[/<prefixpath>]",
|
||||
},
|
||||
// TODO: remove in next major release
|
||||
&cli.StringFlag{
|
||||
EnvVars: []string{"WOODPECKER_DEV_OAUTH_HOST"},
|
||||
Name: "server-dev-oauth-host",
|
||||
Usage: "server fully qualified url (<scheme>://<host>[/<prefixpath>]) used for oauth redirect (used for development)",
|
||||
Name: "server-dev-oauth-host-deprecated",
|
||||
Usage: "DEPRECATED: use WOODPECKER_EXPERT_FORGE_OAUTH_HOST instead\nfully qualified url used for oauth redirects. Format: <scheme>://<host>[/<prefixpath>]",
|
||||
Value: "",
|
||||
Hidden: true,
|
||||
},
|
||||
|
|
|
@ -317,8 +317,8 @@ func setupEvilGlobals(c *cli.Context, s store.Store) error {
|
|||
} else {
|
||||
server.Config.Server.WebhookHost = serverHost
|
||||
}
|
||||
if c.IsSet("server-dev-oauth-host") {
|
||||
server.Config.Server.OAuthHost = c.String("server-dev-oauth-host")
|
||||
if c.IsSet("server-dev-oauth-host-deprecated") {
|
||||
server.Config.Server.OAuthHost = c.String("server-dev-oauth-host-deprecated")
|
||||
} else {
|
||||
server.Config.Server.OAuthHost = serverHost
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ Sometimes there are multiple terms that can be used to describe something. This
|
|||
- Environment variables `*_LINK` should be called `*_URL`. In the code use `URL()` instead of `Link()`
|
||||
- Use the term **pipelines** instead of the previous **builds**
|
||||
- Use the term **steps** instead of the previous **jobs**
|
||||
- Use the prefix `WOODPECKER_EXPERT_` for advanced environment variables that are normally not required to be set by users
|
||||
|
||||
<!-- References -->
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ Some versions need some changes to the server configuration or the pipeline conf
|
|||
- Deprecated alternative names for secrets, use `environment` with `from_secret`
|
||||
- Deprecated slice definition for env vars
|
||||
- Deprecated `environment` filter, use `when.evaluate`
|
||||
- Use `WOODPECKER_EXPERT_FORGE_OAUTH_HOST` instead of `WOODPECKER_DEV_GITEA_OAUTH_URL` or `WOODPECKER_DEV_OAUTH_HOST`
|
||||
- Deprecated `WOODPECKER_WEBHOOK_HOST` in favor of `WOODPECKER_EXPERT_WEBHOOK_HOST`
|
||||
|
||||
## 2.0.0
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@ type Opts struct {
|
|||
Password string // Git machine account password.
|
||||
ClientID string // OAuth 2.0 client id
|
||||
ClientSecret string // OAuth 2.0 client secret
|
||||
OAuthHost string // OAuth 2.0 host
|
||||
}
|
||||
|
||||
type client struct {
|
||||
|
@ -50,6 +51,7 @@ type client struct {
|
|||
urlAPI string
|
||||
clientID string
|
||||
clientSecret string
|
||||
oauthHost string
|
||||
username string
|
||||
password string
|
||||
}
|
||||
|
@ -62,6 +64,7 @@ func New(opts Opts) (forge.Forge, error) {
|
|||
urlAPI: fmt.Sprintf("%s/rest", opts.URL),
|
||||
clientID: opts.ClientID,
|
||||
clientSecret: opts.ClientSecret,
|
||||
oauthHost: opts.OAuthHost,
|
||||
username: opts.Username,
|
||||
password: opts.Password,
|
||||
}
|
||||
|
@ -608,11 +611,16 @@ func (c *client) Org(_ context.Context, _ *model.User, owner string) (*model.Org
|
|||
}
|
||||
|
||||
func (c *client) newOAuth2Config() *oauth2.Config {
|
||||
publicOAuthURL := c.oauthHost
|
||||
if publicOAuthURL == "" {
|
||||
publicOAuthURL = c.urlAPI
|
||||
}
|
||||
|
||||
return &oauth2.Config{
|
||||
ClientID: c.clientID,
|
||||
ClientSecret: c.clientSecret,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: fmt.Sprintf("%s/oauth2/latest/authorize", c.urlAPI),
|
||||
AuthURL: fmt.Sprintf("%s/oauth2/latest/authorize", publicOAuthURL),
|
||||
TokenURL: fmt.Sprintf("%s/oauth2/latest/token", c.urlAPI),
|
||||
},
|
||||
Scopes: []string{string(bb.PermissionRepoRead), string(bb.PermissionRepoWrite), string(bb.PermissionRepoAdmin)},
|
||||
|
|
|
@ -50,9 +50,9 @@ const (
|
|||
|
||||
type Gitea struct {
|
||||
url string
|
||||
oauth2URL string
|
||||
ClientID string
|
||||
ClientSecret string
|
||||
OAuthHost string
|
||||
SkipVerify bool
|
||||
pageSize int
|
||||
}
|
||||
|
@ -60,24 +60,20 @@ type Gitea struct {
|
|||
// Opts defines configuration options.
|
||||
type Opts struct {
|
||||
URL string // Gitea server url.
|
||||
OAuth2URL string // User-facing Gitea server url for OAuth2.
|
||||
Client string // OAuth2 Client ID
|
||||
Secret string // OAuth2 Client Secret
|
||||
OAuthHost string // OAuth2 Host
|
||||
SkipVerify bool // Skip ssl verification.
|
||||
}
|
||||
|
||||
// New returns a Forge implementation that integrates with Gitea,
|
||||
// an open source Git service written in Go. See https://gitea.io/
|
||||
func New(opts Opts) (forge.Forge, error) {
|
||||
if opts.OAuth2URL == "" {
|
||||
opts.OAuth2URL = opts.URL
|
||||
}
|
||||
|
||||
return &Gitea{
|
||||
url: opts.URL,
|
||||
oauth2URL: opts.OAuth2URL,
|
||||
ClientID: opts.Client,
|
||||
ClientSecret: opts.Secret,
|
||||
OAuthHost: opts.OAuthHost,
|
||||
SkipVerify: opts.SkipVerify,
|
||||
}, nil
|
||||
}
|
||||
|
@ -93,12 +89,16 @@ func (c *Gitea) URL() string {
|
|||
}
|
||||
|
||||
func (c *Gitea) oauth2Config(ctx context.Context) (*oauth2.Config, context.Context) {
|
||||
publicOAuthURL := c.OAuthHost
|
||||
if publicOAuthURL == "" {
|
||||
publicOAuthURL = c.url
|
||||
}
|
||||
return &oauth2.Config{
|
||||
ClientID: c.ClientID,
|
||||
ClientSecret: c.ClientSecret,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: fmt.Sprintf(authorizeTokenURL, c.oauth2URL),
|
||||
TokenURL: fmt.Sprintf(accessTokenURL, c.oauth2URL),
|
||||
AuthURL: fmt.Sprintf(authorizeTokenURL, publicOAuthURL),
|
||||
TokenURL: fmt.Sprintf(accessTokenURL, c.url),
|
||||
},
|
||||
RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.OAuthHost),
|
||||
},
|
||||
|
|
|
@ -52,6 +52,7 @@ type Opts struct {
|
|||
SkipVerify bool // Skip ssl verification.
|
||||
MergeRef bool // Clone pull requests using the merge ref.
|
||||
OnlyPublic bool // Only obtain OAuth tokens with access to public repos.
|
||||
OAuthHost string // Public url for oauth if different from url.
|
||||
}
|
||||
|
||||
// New returns a Forge implementation that integrates with a GitHub Cloud or
|
||||
|
@ -62,6 +63,7 @@ func New(opts Opts) (forge.Forge, error) {
|
|||
url: defaultURL,
|
||||
Client: opts.Client,
|
||||
Secret: opts.Secret,
|
||||
oAuthHost: opts.OAuthHost,
|
||||
SkipVerify: opts.SkipVerify,
|
||||
MergeRef: opts.MergeRef,
|
||||
OnlyPublic: opts.OnlyPublic,
|
||||
|
@ -82,6 +84,7 @@ type client struct {
|
|||
SkipVerify bool
|
||||
MergeRef bool
|
||||
OnlyPublic bool
|
||||
oAuthHost string
|
||||
}
|
||||
|
||||
// Name returns the string name of this driver.
|
||||
|
@ -415,12 +418,17 @@ func (c *client) newConfig() *oauth2.Config {
|
|||
scopes = append(scopes, "repo")
|
||||
}
|
||||
|
||||
publicOAuthURL := c.oAuthHost
|
||||
if publicOAuthURL == "" {
|
||||
publicOAuthURL = c.url
|
||||
}
|
||||
|
||||
return &oauth2.Config{
|
||||
ClientID: c.Client,
|
||||
ClientSecret: c.Secret,
|
||||
Scopes: scopes,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: fmt.Sprintf("%s/login/oauth/authorize", c.url),
|
||||
AuthURL: fmt.Sprintf("%s/login/oauth/authorize", publicOAuthURL),
|
||||
TokenURL: fmt.Sprintf("%s/login/oauth/access_token", c.url),
|
||||
},
|
||||
RedirectURL: fmt.Sprintf("%s/authorize", server.Config.Server.OAuthHost),
|
||||
|
|
|
@ -51,6 +51,7 @@ type Opts struct {
|
|||
ClientID string // Oauth2 client id.
|
||||
ClientSecret string // Oauth2 client secret.
|
||||
SkipVerify bool // Skip ssl verification.
|
||||
OAuthHost string // Public url for oauth if different from url.
|
||||
}
|
||||
|
||||
// Gitlab implements "Forge" interface.
|
||||
|
@ -61,6 +62,7 @@ type GitLab struct {
|
|||
SkipVerify bool
|
||||
HideArchives bool
|
||||
Search bool
|
||||
oAuthHost string
|
||||
}
|
||||
|
||||
// New returns a Forge implementation that integrates with Gitlab, an open
|
||||
|
@ -70,6 +72,7 @@ func New(opts Opts) (forge.Forge, error) {
|
|||
url: opts.URL,
|
||||
ClientID: opts.ClientID,
|
||||
ClientSecret: opts.ClientSecret,
|
||||
oAuthHost: opts.OAuthHost,
|
||||
SkipVerify: opts.SkipVerify,
|
||||
HideArchives: true,
|
||||
}, nil
|
||||
|
@ -86,11 +89,16 @@ func (g *GitLab) URL() string {
|
|||
}
|
||||
|
||||
func (g *GitLab) oauth2Config(ctx context.Context) (*oauth2.Config, context.Context) {
|
||||
publicOAuthURL := g.oAuthHost
|
||||
if publicOAuthURL == "" {
|
||||
publicOAuthURL = g.url
|
||||
}
|
||||
|
||||
return &oauth2.Config{
|
||||
ClientID: g.ClientID,
|
||||
ClientSecret: g.ClientSecret,
|
||||
Endpoint: oauth2.Endpoint{
|
||||
AuthURL: fmt.Sprintf("%s/oauth/authorize", g.url),
|
||||
AuthURL: fmt.Sprintf("%s/oauth/authorize", publicOAuthURL),
|
||||
TokenURL: fmt.Sprintf("%s/oauth/token", g.url),
|
||||
},
|
||||
Scopes: []string{defaultScope},
|
||||
|
|
|
@ -46,22 +46,17 @@ func setupBitbucket(forge *model.Forge) (forge.Forge, error) {
|
|||
}
|
||||
|
||||
func setupGitea(forge *model.Forge) (forge.Forge, error) {
|
||||
server, err := url.Parse(forge.URL)
|
||||
serverURL, err := url.Parse(forge.URL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oauthURL, ok := forge.AdditionalOptions["oauth-server"].(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("missing oauth-server")
|
||||
}
|
||||
|
||||
opts := gitea.Opts{
|
||||
URL: strings.TrimRight(server.String(), "/"),
|
||||
URL: strings.TrimRight(serverURL.String(), "/"),
|
||||
Client: forge.Client,
|
||||
Secret: forge.ClientSecret,
|
||||
SkipVerify: forge.SkipVerify,
|
||||
OAuth2URL: oauthURL,
|
||||
OAuthHost: forge.OAuthHost,
|
||||
}
|
||||
if len(opts.URL) == 0 {
|
||||
return nil, fmt.Errorf("WOODPECKER_GITEA_URL must be set")
|
||||
|
@ -76,6 +71,7 @@ func setupGitLab(forge *model.Forge) (forge.Forge, error) {
|
|||
ClientID: forge.Client,
|
||||
ClientSecret: forge.ClientSecret,
|
||||
SkipVerify: forge.SkipVerify,
|
||||
OAuthHost: forge.OAuthHost,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -97,6 +93,7 @@ func setupGitHub(forge *model.Forge) (forge.Forge, error) {
|
|||
SkipVerify: forge.SkipVerify,
|
||||
MergeRef: mergeRef,
|
||||
OnlyPublic: publicOnly,
|
||||
OAuthHost: forge.OAuthHost,
|
||||
}
|
||||
log.Trace().Msgf("Forge (github) opts: %#v", opts)
|
||||
return github.New(opts)
|
||||
|
@ -118,6 +115,7 @@ func setupBitbucketDatacenter(forge *model.Forge) (forge.Forge, error) {
|
|||
ClientSecret: forge.ClientSecret,
|
||||
Username: gitUsername,
|
||||
Password: gitPassword,
|
||||
OAuthHost: forge.OAuthHost,
|
||||
}
|
||||
log.Trace().Msgf("Forge (bitbucketdatacenter) opts: %#v", opts)
|
||||
return bitbucketdatacenter.New(opts)
|
||||
|
|
|
@ -32,5 +32,6 @@ type Forge struct {
|
|||
Client string `xorm:"VARCHAR(250)"`
|
||||
ClientSecret string `xorm:"VARCHAR(250)"`
|
||||
SkipVerify bool `xorm:"bool"`
|
||||
OAuthHost string `xorm:"VARCHAR(250) 'oauth_host'"` // public url for oauth if different from url
|
||||
AdditionalOptions map[string]any `xorm:"json"`
|
||||
}
|
||||
|
|
|
@ -118,6 +118,7 @@ func setupForgeService(c *cli.Context, _store store.Store) error {
|
|||
_forge.ClientSecret = c.String("forge-oauth-secret")
|
||||
_forge.URL = c.String("forge-url")
|
||||
_forge.SkipVerify = c.Bool("forge-skip-verify")
|
||||
_forge.OAuthHost = c.String("forge-oauth-host")
|
||||
|
||||
switch {
|
||||
case c.String("addon-forge") != "":
|
||||
|
@ -137,7 +138,6 @@ func setupForgeService(c *cli.Context, _store store.Store) error {
|
|||
}
|
||||
case c.Bool("gitea"):
|
||||
_forge.Type = model.ForgeTypeGitea
|
||||
_forge.AdditionalOptions["oauth-server"] = c.String("gitea-oauth-server")
|
||||
if _forge.URL == "" {
|
||||
_forge.URL = "https://try.gitea.com"
|
||||
}
|
||||
|
|
|
@ -222,7 +222,7 @@
|
|||
}
|
||||
},
|
||||
"not_allowed": "Zugriff auf dieses Repository nicht erlaubt",
|
||||
"open_in_forge": "Repository im Versionskontrollsystem öffnen",
|
||||
"open_in_forge": "Repository in der Forge öffnen",
|
||||
"pipeline": {
|
||||
"actions": {
|
||||
"cancel": "Abbrechen",
|
||||
|
@ -535,5 +535,31 @@
|
|||
"cli_login_success": "Anmelden im CLI erfolgreich",
|
||||
"cli_login_failed": "Anmelden im CLI fehlgeschlagen",
|
||||
"cli_login_denied": "Anmelden im CLI abgelehnt",
|
||||
"return_to_cli": "Du kannst diesen Tab jetzt schließen und zur CLI zurückkehren."
|
||||
"return_to_cli": "Du kannst diesen Tab jetzt schließen und zur CLI zurückkehren.",
|
||||
"secrets": {
|
||||
"secrets": "Geheimnisse",
|
||||
"desc": "Geheimnisse können zur Laufzeit als Umgebungsvariablen an einzelne Pipelineschritte übergeben werden.",
|
||||
"none": "Es gibt noch keine Geheimnisse.",
|
||||
"add": "Geheimnis hinzufügen",
|
||||
"save": "Geheimnis speichern",
|
||||
"show": "Geheimnisse anzeigen",
|
||||
"name": "Name",
|
||||
"value": "Wert",
|
||||
"delete_confirm": "Möchtest du dieses Geheimnis wirklich löschen?",
|
||||
"deleted": "Geheimnis gelöscht",
|
||||
"created": "Geheimnis erstellt",
|
||||
"saved": "Geheimnis gespeichert",
|
||||
"images": {
|
||||
"images": "Verfügbar für folgende Images",
|
||||
"desc": "Liste der Images, für die dieses Geheimnis verfügbar ist; leer lassen, um alle Images zuzulassen"
|
||||
},
|
||||
"events": {
|
||||
"events": "Verfügbar bei folgenden Ereignissen",
|
||||
"pr_warning": "Bitte sei vorsichtig mit dieser Option, da eine böswillige Person über einen Pull-Request deine Geheimnisse erhalten könnte."
|
||||
},
|
||||
"plugins_only": "Nur für Plugins verfügbar",
|
||||
"edit": "Geheimnis bearbeiten",
|
||||
"delete": "Geheimnis löschen"
|
||||
},
|
||||
"settings": "Einstellungen"
|
||||
}
|
||||
|
|
|
@ -72,9 +72,8 @@
|
|||
"success": "Repository enabled",
|
||||
"list_reloaded": "Repository list reloaded"
|
||||
},
|
||||
"open_in_forge": "Open Repository in Version Control System",
|
||||
"open_in_forge": "Open repository in forge",
|
||||
"settings": {
|
||||
"settings": "Settings",
|
||||
"not_allowed": "You are not allowed to access this repository's settings",
|
||||
"general": {
|
||||
"general": "General",
|
||||
|
@ -131,31 +130,6 @@
|
|||
"desc": "Enable to cancel pending and running pipelines of the same event and context before starting the newly triggered one."
|
||||
}
|
||||
},
|
||||
"secrets": {
|
||||
"secrets": "Secrets",
|
||||
"desc": "Secrets can be passed to individual pipeline steps at runtime as environmental variables.",
|
||||
"none": "There are no secrets yet.",
|
||||
"add": "Add secret",
|
||||
"save": "Save secret",
|
||||
"show": "Show secrets",
|
||||
"name": "Name",
|
||||
"value": "Value",
|
||||
"delete_confirm": "Do you really want to delete this secret?",
|
||||
"deleted": "Secret deleted",
|
||||
"created": "Secret created",
|
||||
"saved": "Secret saved",
|
||||
"images": {
|
||||
"images": "Available for following images",
|
||||
"desc": "List of images where this secret is available, leave empty to allow all images"
|
||||
},
|
||||
"events": {
|
||||
"events": "Available at following events",
|
||||
"pr_warning": "Please be careful with this option as a bad actor can submit a malicious pull request that exposes your secrets."
|
||||
},
|
||||
"plugins_only": "Only available for plugins",
|
||||
"edit": "Edit secret",
|
||||
"delete": "Delete secret"
|
||||
},
|
||||
"registries": {
|
||||
"registries": "Registries",
|
||||
"credentials": "Registry credentials",
|
||||
|
@ -298,58 +272,18 @@
|
|||
},
|
||||
"org": {
|
||||
"settings": {
|
||||
"settings": "Settings",
|
||||
"not_allowed": "You are not allowed to access this organization's settings",
|
||||
"secrets": {
|
||||
"secrets": "Secrets",
|
||||
"desc": "Organization secrets can be passed to all organization's repository individual pipeline steps at runtime as environmental variables.",
|
||||
"none": "There are no organization secrets yet.",
|
||||
"add": "Add secret",
|
||||
"save": "Save secret",
|
||||
"show": "Show secrets",
|
||||
"name": "Name",
|
||||
"value": "Value",
|
||||
"deleted": "Organization secret deleted",
|
||||
"created": "Organization secret created",
|
||||
"saved": "Organization secret saved",
|
||||
"images": {
|
||||
"images": "Available for following images",
|
||||
"desc": "List of images where this secret is available, leave empty to allow all images"
|
||||
},
|
||||
"plugins_only": "Only available for plugins",
|
||||
"events": {
|
||||
"events": "Available at following events",
|
||||
"pr_warning": "Please be careful with this option as a bad actor can submit a malicious pull request that exposes your secrets."
|
||||
}
|
||||
"desc": "Organization secrets can be passed to all organization's repository individual pipeline steps at runtime as environmental variables."
|
||||
}
|
||||
}
|
||||
},
|
||||
"admin": {
|
||||
"settings": {
|
||||
"settings": "Settings",
|
||||
"not_allowed": "You are not allowed to access server settings",
|
||||
"secrets": {
|
||||
"secrets": "Secrets",
|
||||
"desc": "Global secrets can be passed to all repositories individual pipeline steps at runtime as environmental variables.",
|
||||
"warning": "These secrets will be available for all server users.",
|
||||
"none": "There are no global secrets yet.",
|
||||
"add": "Add secret",
|
||||
"save": "Save secret",
|
||||
"show": "Show secrets",
|
||||
"name": "Name",
|
||||
"value": "Value",
|
||||
"deleted": "Global secret deleted",
|
||||
"created": "Global secret created",
|
||||
"saved": "Global secret saved",
|
||||
"images": {
|
||||
"images": "Available for following images",
|
||||
"desc": "List of images where this secret is available, leave empty to allow all images"
|
||||
},
|
||||
"plugins_only": "Only available for plugins",
|
||||
"events": {
|
||||
"events": "Available at following events",
|
||||
"pr_warning": "Please be careful with this option as a bad actor can submit a malicious pull request that exposes your secrets."
|
||||
}
|
||||
"warning": "These secrets will be available for all server users."
|
||||
},
|
||||
"agents": {
|
||||
"agents": "Agents",
|
||||
|
@ -472,26 +406,7 @@
|
|||
}
|
||||
},
|
||||
"secrets": {
|
||||
"secrets": "Secrets",
|
||||
"desc": "User secrets can be passed to all user's repository individual pipeline steps at runtime as environmental variables.",
|
||||
"none": "There are no user secrets yet.",
|
||||
"add": "Add secret",
|
||||
"save": "Save secret",
|
||||
"show": "Show secrets",
|
||||
"name": "Name",
|
||||
"value": "Value",
|
||||
"deleted": "User secret deleted",
|
||||
"created": "User secret created",
|
||||
"saved": "User secret saved",
|
||||
"images": {
|
||||
"images": "Available for following images",
|
||||
"desc": "List of images where this secret is available, leave empty to allow all images"
|
||||
},
|
||||
"plugins_only": "Only available for plugins",
|
||||
"events": {
|
||||
"events": "Available at following events",
|
||||
"pr_warning": "Please be careful with this option as a bad actor can submit a malicious pull request that exposes your secrets."
|
||||
}
|
||||
"desc": "User secrets can be passed to all user's repository individual pipeline steps at runtime as environmental variables."
|
||||
},
|
||||
"cli_and_api": {
|
||||
"cli_and_api": "CLI & API",
|
||||
|
@ -508,6 +423,31 @@
|
|||
"internal_error": "Some internal error occurred",
|
||||
"access_denied": "You are not allowed to login"
|
||||
},
|
||||
"secrets": {
|
||||
"secrets": "Secrets",
|
||||
"desc": "Secrets can be passed to individual pipeline steps at runtime as environmental variables.",
|
||||
"none": "There are no secrets yet.",
|
||||
"add": "Add secret",
|
||||
"save": "Save secret",
|
||||
"show": "Show secrets",
|
||||
"name": "Name",
|
||||
"value": "Value",
|
||||
"delete_confirm": "Do you really want to delete this secret?",
|
||||
"deleted": "Secret deleted",
|
||||
"created": "Secret created",
|
||||
"saved": "Secret saved",
|
||||
"images": {
|
||||
"images": "Available for following images",
|
||||
"desc": "List of images where this secret is available, leave empty to allow all images"
|
||||
},
|
||||
"events": {
|
||||
"events": "Available at following events",
|
||||
"pr_warning": "Please be careful with this option as a bad actor can submit a malicious pull request that exposes your secrets."
|
||||
},
|
||||
"plugins_only": "Only available for plugins",
|
||||
"edit": "Edit secret",
|
||||
"delete": "Delete secret"
|
||||
},
|
||||
"default": "default",
|
||||
"info": "Info",
|
||||
"running_version": "You are running Woodpecker {0}",
|
||||
|
@ -520,5 +460,6 @@
|
|||
"cli_login_success": "Login to CLI successful",
|
||||
"cli_login_failed": "Login to CLI failed",
|
||||
"cli_login_denied": "Login to CLI denied",
|
||||
"return_to_cli": "You can now close this tab and return to the CLI."
|
||||
"return_to_cli": "You can now close this tab and return to the CLI.",
|
||||
"settings": "Settings"
|
||||
}
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
<template>
|
||||
<Settings
|
||||
:title="$t('admin.settings.secrets.secrets')"
|
||||
:title="$t('secrets.secrets')"
|
||||
:desc="$t('admin.settings.secrets.desc')"
|
||||
docs-url="docs/usage/secrets"
|
||||
:warning="$t('admin.settings.secrets.warning')"
|
||||
>
|
||||
<template #titleActions>
|
||||
<Button
|
||||
v-if="selectedSecret"
|
||||
:text="$t('admin.settings.secrets.show')"
|
||||
start-icon="back"
|
||||
@click="selectedSecret = undefined"
|
||||
/>
|
||||
<Button v-else :text="$t('admin.settings.secrets.add')" start-icon="plus" @click="showAddSecret" />
|
||||
<Button v-if="selectedSecret" :text="$t('secrets.show')" start-icon="back" @click="selectedSecret = undefined" />
|
||||
<Button v-else :text="$t('secrets.add')" start-icon="plus" @click="showAddSecret" />
|
||||
</template>
|
||||
|
||||
<SecretList
|
||||
v-if="!selectedSecret"
|
||||
v-model="secrets"
|
||||
i18n-prefix="admin.settings.secrets."
|
||||
:is-deleting="isDeleting"
|
||||
@edit="editSecret"
|
||||
@delete="deleteSecret"
|
||||
|
@ -27,7 +21,6 @@
|
|||
<SecretEdit
|
||||
v-else
|
||||
v-model="selectedSecret"
|
||||
i18n-prefix="admin.settings.secrets."
|
||||
:is-saving="isSaving"
|
||||
@save="createSecret"
|
||||
@cancel="selectedSecret = undefined"
|
||||
|
@ -81,7 +74,7 @@ const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async ()
|
|||
await apiClient.createGlobalSecret(selectedSecret.value);
|
||||
}
|
||||
notifications.notify({
|
||||
title: i18n.t(isEditingSecret.value ? 'admin.settings.secrets.saved' : 'admin.settings.secrets.created'),
|
||||
title: i18n.t(isEditingSecret.value ? 'secrets.saved' : 'secrets.created'),
|
||||
type: 'success',
|
||||
});
|
||||
selectedSecret.value = undefined;
|
||||
|
@ -90,7 +83,7 @@ const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async ()
|
|||
|
||||
const { doSubmit: deleteSecret, isLoading: isDeleting } = useAsyncAction(async (_secret: Secret) => {
|
||||
await apiClient.deleteGlobalSecret(_secret.name);
|
||||
notifications.notify({ title: i18n.t('admin.settings.secrets.deleted'), type: 'success' });
|
||||
notifications.notify({ title: i18n.t('secrets.deleted'), type: 'success' });
|
||||
resetPage();
|
||||
});
|
||||
|
||||
|
|
|
@ -20,12 +20,7 @@
|
|||
</div>
|
||||
<div class="flex ml-auto -m-1.5 items-center space-x-2">
|
||||
<div v-if="user?.admin" class="relative">
|
||||
<IconButton
|
||||
class="navbar-icon"
|
||||
:title="$t('admin.settings.settings')"
|
||||
:to="{ name: 'admin-settings' }"
|
||||
icon="settings"
|
||||
/>
|
||||
<IconButton class="navbar-icon" :title="$t('settings')" :to="{ name: 'admin-settings' }" icon="settings" />
|
||||
<div
|
||||
v-if="version?.needsUpdate"
|
||||
class="absolute top-2 right-2 bg-int-wp-state-error-100 rounded-full w-3 h-3"
|
||||
|
|
|
@ -1,23 +1,13 @@
|
|||
<template>
|
||||
<Settings
|
||||
:title="$t('org.settings.secrets.secrets')"
|
||||
:desc="$t('org.settings.secrets.desc')"
|
||||
docs-url="docs/usage/secrets"
|
||||
>
|
||||
<Settings :title="$t('secrets.secrets')" :desc="$t('org.settings.secrets.desc')" docs-url="docs/usage/secrets">
|
||||
<template #titleActions>
|
||||
<Button
|
||||
v-if="selectedSecret"
|
||||
:text="$t('org.settings.secrets.show')"
|
||||
start-icon="back"
|
||||
@click="selectedSecret = undefined"
|
||||
/>
|
||||
<Button v-else :text="$t('org.settings.secrets.add')" start-icon="plus" @click="showAddSecret" />
|
||||
<Button v-if="selectedSecret" :text="$t('secrets.show')" start-icon="back" @click="selectedSecret = undefined" />
|
||||
<Button v-else :text="$t('secrets.add')" start-icon="plus" @click="showAddSecret" />
|
||||
</template>
|
||||
|
||||
<SecretList
|
||||
v-if="!selectedSecret"
|
||||
v-model="secrets"
|
||||
i18n-prefix="org.settings.secrets."
|
||||
:is-deleting="isDeleting"
|
||||
@edit="editSecret"
|
||||
@delete="deleteSecret"
|
||||
|
@ -26,7 +16,6 @@
|
|||
<SecretEdit
|
||||
v-else
|
||||
v-model="selectedSecret"
|
||||
i18n-prefix="org.settings.secrets."
|
||||
:is-saving="isSaving"
|
||||
@save="createSecret"
|
||||
@cancel="selectedSecret = undefined"
|
||||
|
@ -89,7 +78,7 @@ const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async ()
|
|||
await apiClient.createOrgSecret(org.value.id, selectedSecret.value);
|
||||
}
|
||||
notifications.notify({
|
||||
title: i18n.t(isEditingSecret.value ? 'org.settings.secrets.saved' : 'org.settings.secrets.created'),
|
||||
title: i18n.t(isEditingSecret.value ? 'secrets.saved' : 'secrets.created'),
|
||||
type: 'success',
|
||||
});
|
||||
selectedSecret.value = undefined;
|
||||
|
@ -102,7 +91,7 @@ const { doSubmit: deleteSecret, isLoading: isDeleting } = useAsyncAction(async (
|
|||
}
|
||||
|
||||
await apiClient.deleteOrgSecret(org.value.id, _secret.name);
|
||||
notifications.notify({ title: i18n.t('org.settings.secrets.deleted'), type: 'success' });
|
||||
notifications.notify({ title: i18n.t('secrets.deleted'), type: 'success' });
|
||||
resetPage();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,23 +1,13 @@
|
|||
<template>
|
||||
<Settings
|
||||
:title="$t('repo.settings.secrets.secrets')"
|
||||
:desc="$t('repo.settings.secrets.desc')"
|
||||
docs-url="docs/usage/secrets"
|
||||
>
|
||||
<Settings :title="$t('secrets.secrets')" :desc="$t('secrets.desc')" docs-url="docs/usage/secrets">
|
||||
<template #titleActions>
|
||||
<Button
|
||||
v-if="selectedSecret"
|
||||
:text="$t('repo.settings.secrets.show')"
|
||||
start-icon="back"
|
||||
@click="selectedSecret = undefined"
|
||||
/>
|
||||
<Button v-else :text="$t('repo.settings.secrets.add')" start-icon="plus" @click="showAddSecret" />
|
||||
<Button v-if="selectedSecret" :text="$t('secrets.show')" start-icon="back" @click="selectedSecret = undefined" />
|
||||
<Button v-else :text="$t('secrets.add')" start-icon="plus" @click="showAddSecret" />
|
||||
</template>
|
||||
|
||||
<SecretList
|
||||
v-if="!selectedSecret"
|
||||
:model-value="secrets"
|
||||
i18n-prefix="repo.settings.secrets."
|
||||
:is-deleting="isDeleting"
|
||||
@edit="editSecret"
|
||||
@delete="deleteSecret"
|
||||
|
@ -26,7 +16,6 @@
|
|||
<SecretEdit
|
||||
v-else
|
||||
v-model="selectedSecret"
|
||||
i18n-prefix="repo.settings.secrets."
|
||||
:is-saving="isSaving"
|
||||
@save="createSecret"
|
||||
@cancel="selectedSecret = undefined"
|
||||
|
@ -129,7 +118,7 @@ const { doSubmit: createSecret, isLoading: isSaving } = useAsyncAction(async ()
|
|||
await apiClient.createSecret(repo.value.id, selectedSecret.value);
|
||||
}
|
||||
notifications.notify({
|
||||
title: i18n.t(isEditingSecret.value ? 'repo.settings.secrets.saved' : 'repo.settings.secrets.created'),
|
||||
title: i18n.t(isEditingSecret.value ? 'secrets.saved' : 'secrets.created'),
|
||||
type: 'success',
|
||||
});
|
||||
selectedSecret.value = undefined;
|
||||
|
@ -142,7 +131,7 @@ const { doSubmit: deleteSecret, isLoading: isDeleting } = useAsyncAction(async (
|
|||
}
|
||||
|
||||
await apiClient.deleteSecret(repo.value.id, _secret.name);
|
||||
notifications.notify({ title: i18n.t('repo.settings.secrets.deleted'), type: 'success' });
|
||||
notifications.notify({ title: i18n.t('secrets.deleted'), type: 'success' });
|
||||
await resetPage();
|
||||
});
|
||||
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
<template>
|
||||
<div v-if="innerValue" class="space-y-4">
|
||||
<form @submit.prevent="save">
|
||||
<InputField v-slot="{ id }" :label="$t(i18nPrefix + 'name')">
|
||||
<InputField v-slot="{ id }" :label="$t('secrets.name')">
|
||||
<TextField
|
||||
:id="id"
|
||||
v-model="innerValue.name"
|
||||
:placeholder="$t(i18nPrefix + 'name')"
|
||||
:placeholder="$t('secrets.name')"
|
||||
required
|
||||
:disabled="isEditingSecret"
|
||||
/>
|
||||
</InputField>
|
||||
|
||||
<InputField v-slot="{ id }" :label="$t(i18nPrefix + 'value')">
|
||||
<InputField v-slot="{ id }" :label="$t('secrets.value')">
|
||||
<TextField
|
||||
:id="id"
|
||||
v-model="innerValue.value"
|
||||
:placeholder="$t(i18nPrefix + 'value')"
|
||||
:placeholder="$t('secrets.value')"
|
||||
:lines="5"
|
||||
:required="!isEditingSecret"
|
||||
/>
|
||||
</InputField>
|
||||
|
||||
<InputField v-slot="{ id }" :label="$t(i18nPrefix + 'images.images')">
|
||||
<span class="ml-1 mb-2 text-wp-text-alt-100">{{ $t(i18nPrefix + 'images.desc') }}</span>
|
||||
<InputField v-slot="{ id }" :label="$t('secrets.images.images')">
|
||||
<span class="ml-1 mb-2 text-wp-text-alt-100">{{ $t('secrets.images.desc') }}</span>
|
||||
|
||||
<div class="flex flex-col gap-2">
|
||||
<div v-for="image in innerValue.images" :key="image" class="flex gap-2">
|
||||
|
@ -36,7 +36,7 @@
|
|||
</div>
|
||||
</InputField>
|
||||
|
||||
<InputField :label="$t(i18nPrefix + 'events.events')">
|
||||
<InputField :label="$t('secrets.events.events')">
|
||||
<CheckboxesField v-model="innerValue.events" :options="secretEventsOptions" />
|
||||
</InputField>
|
||||
|
||||
|
@ -46,7 +46,7 @@
|
|||
type="submit"
|
||||
color="green"
|
||||
:is-loading="isSaving"
|
||||
:text="isEditingSecret ? $t(i18nPrefix + 'save') : $t(i18nPrefix + 'add')"
|
||||
:text="isEditingSecret ? $t('secrets.save') : $t('secrets.add')"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
@ -67,7 +67,6 @@ import { Secret, WebhookEvents } from '~/lib/api/types';
|
|||
const props = defineProps<{
|
||||
modelValue: Partial<Secret>;
|
||||
isSaving: boolean;
|
||||
i18nPrefix: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
@ -106,7 +105,7 @@ const secretEventsOptions: CheckboxOption[] = [
|
|||
{
|
||||
value: WebhookEvents.PullRequest,
|
||||
text: i18n.t('repo.pipeline.event.pr'),
|
||||
description: i18n.t('repo.settings.secrets.events.pr_warning'),
|
||||
description: i18n.t('secrets.events.pr_warning'),
|
||||
},
|
||||
{ value: WebhookEvents.Deploy, text: i18n.t('repo.pipeline.event.deploy') },
|
||||
{ value: WebhookEvents.Cron, text: i18n.t('repo.pipeline.event.cron') },
|
||||
|
|
|
@ -18,20 +18,20 @@
|
|||
<IconButton
|
||||
icon="edit"
|
||||
class="ml-2 <md:ml-auto w-8 h-8"
|
||||
:title="$t('repo.settings.secrets.edit')"
|
||||
:title="$t('secrets.edit')"
|
||||
@click="editSecret(secret)"
|
||||
/>
|
||||
<IconButton
|
||||
icon="trash"
|
||||
class="ml-2 w-8 h-8 hover:text-wp-control-error-100"
|
||||
:is-loading="isDeleting"
|
||||
:title="$t('repo.settings.secrets.delete')"
|
||||
:title="$t('secrets.delete')"
|
||||
@click="deleteSecret(secret)"
|
||||
/>
|
||||
</template>
|
||||
</ListItem>
|
||||
|
||||
<div v-if="secrets?.length === 0" class="ml-2">{{ $t(i18nPrefix + 'none') }}</div>
|
||||
<div v-if="secrets?.length === 0" class="ml-2">{{ $t('secrets.none') }}</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -47,7 +47,6 @@ import { Secret } from '~/lib/api/types';
|
|||
const props = defineProps<{
|
||||
modelValue: (Secret & { edit?: boolean })[];
|
||||
isDeleting: boolean;
|
||||
i18nPrefix: string;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<Scaffold enable-tabs>
|
||||
<template #title>
|
||||
{{ $t('repo.settings.settings') }}
|
||||
{{ $t('settings') }}
|
||||
</template>
|
||||
<Tab id="info" :title="$t('info')">
|
||||
<AdminInfoTab />
|
||||
</Tab>
|
||||
<Tab id="secrets" :title="$t('admin.settings.secrets.secrets')">
|
||||
<Tab id="secrets" :title="$t('secrets.secrets')">
|
||||
<AdminSecretsTab />
|
||||
</Tab>
|
||||
<Tab id="repos" :title="$t('admin.settings.repos.repos')">
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
v-if="orgPermissions.admin"
|
||||
icon="settings"
|
||||
:to="{ name: org.is_user ? 'user' : 'org-settings' }"
|
||||
:title="$t('org.settings.settings')"
|
||||
:title="$t('settings')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
|
|
|
@ -6,11 +6,11 @@
|
|||
{{ org.name }}
|
||||
</router-link>
|
||||
/
|
||||
{{ $t('org.settings.settings') }}
|
||||
{{ $t('settings') }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<Tab id="secrets" :title="$t('org.settings.secrets.secrets')">
|
||||
<Tab id="secrets" :title="$t('secrets.secrets')">
|
||||
<OrgSecretsTab />
|
||||
</Tab>
|
||||
</Scaffold>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<IconButton
|
||||
v-if="orgPermissions.admin"
|
||||
:to="{ name: org.is_user ? 'user' : 'repo-settings' }"
|
||||
:title="$t('org.settings.settings')"
|
||||
:title="$t('settings')"
|
||||
icon="settings"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -10,14 +10,14 @@
|
|||
{{ repo.name }}
|
||||
</router-link>
|
||||
/
|
||||
{{ $t('repo.settings.settings') }}
|
||||
{{ $t('settings') }}
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<Tab id="general" :title="$t('repo.settings.general.general')">
|
||||
<GeneralTab />
|
||||
</Tab>
|
||||
<Tab id="secrets" :title="$t('repo.settings.secrets.secrets')">
|
||||
<Tab id="secrets" :title="$t('secrets.secrets')">
|
||||
<SecretsTab />
|
||||
</Tab>
|
||||
<Tab id="registries" :title="$t('repo.settings.registries.registries')">
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<IconButton
|
||||
v-if="repoPermissions.admin"
|
||||
:to="{ name: 'repo-settings' }"
|
||||
:title="$t('repo.settings.settings')"
|
||||
:title="$t('settings')"
|
||||
icon="settings"
|
||||
/>
|
||||
</template>
|
||||
|
|
Loading…
Reference in a new issue