Provide global environment variables for pipeline substitution (#968)

* make global environment variables available for pipeline substitution

* lint fixes

* global env support in cli exec; procBuilder tests

* drop GLOBAL_ prefix

* docs

* documentation typo

* Update docs/docs/20-usage/50-environment.md

as suggested by anbraten

Co-authored-by: Anbraten <anton@ju60.de>

Co-authored-by: 6543 <6543@obermui.de>
Co-authored-by: Anbraten <anton@ju60.de>
This commit is contained in:
Arno Hautala 2022-07-30 02:06:03 -04:00 committed by GitHub
parent 6351684070
commit d5e31dc187
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 97 additions and 2 deletions

View file

@ -110,6 +110,11 @@ func execWithAxis(c *cli.Context, file, repoPath string, axis matrix.Axis) error
for _, env := range c.StringSlice("env") { for _, env := range c.StringSlice("env") {
envs := strings.SplitN(env, "=", 2) envs := strings.SplitN(env, "=", 2)
droneEnv[envs[0]] = envs[1] droneEnv[envs[0]] = envs[1]
if _, exists := environ[envs[0]]; exists {
// don't override existing values
continue
}
environ[envs[0]] = envs[1]
} }
tmpl, err := envsubst.ParseFile(file) tmpl, err := envsubst.ParseFile(file)

View file

@ -125,9 +125,9 @@ This is the reference list of all environment variables available to your pipeli
## Global environment variables ## Global environment variables
If you want specific environment variables to be available in all of your builds use the `WOODPECKER_ENVIRONMENT` setting on the Woodpecker server. If you want specific environment variables to be available in all of your builds use the `WOODPECKER_ENVIRONMENT` setting on the Woodpecker server. Note that these can't overwrite any existing, built-in variables.
```.diff ```diff
services: services:
woodpecker-server: woodpecker-server:
[...] [...]
@ -136,6 +136,19 @@ services:
+ - WOODPECKER_ENVIRONMENT=first_var:value1,second_var:value2 + - WOODPECKER_ENVIRONMENT=first_var:value1,second_var:value2
``` ```
These can be used, for example, to manage the image tag used by multiple projects.
```diff
pipeline:
build:
- image: golang:1.18
+ image: golang:${GOLANG_VERSION}
commands:
- [...]
environment:
- [...]
+ - WOODPECKER_ENVIRONMENT=GOLANG_VERSION:1.18
## String Substitution ## String Substitution
Woodpecker provides the ability to substitute environment variables at runtime. This gives us the ability to use dynamic build or commit details in our pipeline configuration. Woodpecker provides the ability to substitute environment variables at runtime. This gives us the ability to use dynamic build or commit details in our pipeline configuration.

View file

@ -89,6 +89,15 @@ func (b *ProcBuilder) Build() ([]*BuildItem, error) {
metadata := metadataFromStruct(b.Repo, b.Curr, b.Last, proc, b.Link) metadata := metadataFromStruct(b.Repo, b.Curr, b.Last, proc, b.Link)
environ := b.environmentVariables(metadata, axis) environ := b.environmentVariables(metadata, axis)
// add global environment variables for substituting
for k, v := range b.Envs {
if _, exists := environ[k]; exists {
// don't override existing values
continue
}
environ[k] = v
}
// substitute vars // substitute vars
substituted, err := b.envsubst(string(y.Data), environ) substituted, err := b.envsubst(string(y.Data), environ)
if err != nil { if err != nil {

View file

@ -24,6 +24,74 @@ import (
// TODO(974) move to pipeline/* // TODO(974) move to pipeline/*
func TestGlobalEnvsubst(t *testing.T) {
t.Parallel()
b := ProcBuilder{
Envs: map[string]string{
"KEY_K": "VALUE_V",
"IMAGE": "scratch",
},
Repo: &model.Repo{},
Curr: &model.Build{
Message: "aaa",
},
Last: &model.Build{},
Netrc: &model.Netrc{},
Secs: []*model.Secret{},
Regs: []*model.Registry{},
Link: "",
Yamls: []*remote.FileMeta{
{Data: []byte(`
pipeline:
build:
image: ${IMAGE}
yyy: ${CI_COMMIT_MESSAGE}
`)},
},
}
if buildItems, err := b.Build(); err != nil {
t.Fatal(err)
} else {
fmt.Println(buildItems)
}
}
func TestMissingGlobalEnvsubst(t *testing.T) {
t.Parallel()
b := ProcBuilder{
Envs: map[string]string{
"KEY_K": "VALUE_V",
"NO_IMAGE": "scratch",
},
Repo: &model.Repo{},
Curr: &model.Build{
Message: "aaa",
},
Last: &model.Build{},
Netrc: &model.Netrc{},
Secs: []*model.Secret{},
Regs: []*model.Registry{},
Link: "",
Yamls: []*remote.FileMeta{
{Data: []byte(`
pipeline:
build:
image: ${IMAGE}
yyy: ${CI_COMMIT_MESSAGE}
`)},
},
}
if _, err := b.Build(); err != nil {
fmt.Println("test rightfully failed")
} else {
t.Fatal("test erroneously succeeded")
}
}
func TestMultilineEnvsubst(t *testing.T) { func TestMultilineEnvsubst(t *testing.T) {
t.Parallel() t.Parallel()