Skip to content

Commit e83a17f

Browse files
committed
test: Implement file based configuration for test environments
Added a yaml configuration mechanism for the testing framework to map provider settings directly to environment variables. Excluded the new execution entrypoint from naming validation checks since it functioned as a harness. Using a structured file eliminated the overhead of managing numerous separate variables across different git providers. Retained environment variable precedence to allow selective overrides. Signed-off-by: Chmouel Boudjnah <chmouel@redhat.com>
1 parent 160f7a4 commit e83a17f

File tree

6 files changed

+475
-2
lines changed

6 files changed

+475
-2
lines changed

hack/check-e2e-test-naming.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ if [[ ${#testfiles[@]} -eq 0 ]]; then
1717
exit 0
1818
fi
1919

20-
# Extract all Test* function names
21-
all_tests=$(grep -hE '^func[[:space:]]+Test[[:alnum:]_]+' "${testfiles[@]}" | sed -E 's/^func[[:space:]]+([[:alnum:]_]+).*/\1/')
20+
# Extract all Test* function names (excluding TestMain which is a Go test harness, not a test)
21+
all_tests=$(grep -hE '^func[[:space:]]+Test[[:alnum:]_]+' "${testfiles[@]}" | sed -E 's/^func[[:space:]]+([[:alnum:]_]+).*/\1/' | grep -v '^TestMain$')
2222

2323
# Valid patterns: TestGithub*, TestGitea*, TestGitlab*, TestBitbucket*, TestOthers*, or *Concurrency*
2424
valid_pattern='^Test(Github|Gitea|Gitlab|Bitbucket|Others)|Concurrency'

test/README.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,31 @@ this repo should differ from the one which is configured as part of `TEST_GITHUB
6262

6363
You don't need to configure all of those if you restrict running your e2e tests to a subset.
6464

65+
### YAML Configuration File
66+
67+
Instead of setting individual environment variables, you can use a YAML
68+
configuration file. Set `PAC_E2E_CONFIG` to the path of your config file:
69+
70+
```shell
71+
PAC_E2E_CONFIG=./test/e2e-config.yaml make test-e2e
72+
```
73+
74+
Copy the example file and fill in the values for the providers you want to test:
75+
76+
```shell
77+
cp test/e2e-config.yaml.example test/e2e-config.yaml
78+
# edit test/e2e-config.yaml with your values
79+
```
80+
81+
The YAML file groups settings by provider section (`common`, `github`,
82+
`github_enterprise`, `gitlab`, `gitea`, `bitbucket_cloud`,
83+
`bitbucket_server`). See `test/e2e-config.yaml.example` for the full list of
84+
fields.
85+
86+
Environment variables always take precedence over YAML values, so you can use
87+
the config file for base settings and override specific values via env vars
88+
(useful for CI secrets).
89+
6590
## Running
6691

6792
As long you have env variables set, you can just do a :

test/e2e-config.yaml.example

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# Pipelines-as-Code E2E Test Configuration
2+
#
3+
# Copy this file and fill in the values for the providers you want to test:
4+
# cp e2e-config.yaml.example e2e-config.yaml
5+
#
6+
# Then run tests with:
7+
# PAC_E2E_CONFIG=./test/e2e-config.yaml make test-e2e
8+
#
9+
# You only need to fill in the sections for the providers you are testing.
10+
# Environment variables always take precedence over values in this file.
11+
12+
# Common settings shared across providers
13+
common:
14+
# The controller public URL (ingress or OpenShift route)
15+
controller_url: "https://pac-controller.example.com"
16+
# Webhook secret configured on the controller
17+
webhook_secret: ""
18+
# Set to "true" to skip cleanup after tests (useful for debugging)
19+
# no_cleanup: "true"
20+
21+
# GitHub (public)
22+
github:
23+
api_url: "https://api.github.com"
24+
token: ""
25+
# Repository configured with GitHub Apps (format: org/repo)
26+
repo_owner_githubapp: ""
27+
# Repository configured with webhooks (format: org/repo, must differ from githubapp repo)
28+
repo_owner_webhook: ""
29+
# Installation ID from GitHub App webhook deliveries
30+
repo_installation_id: ""
31+
# Private remote task for scoped token tests (optional)
32+
# private_task_name: "task-remote"
33+
# private_task_url: "https://github.com/org/private-repo/blob/main/task.yaml"
34+
35+
# GitHub Enterprise (second controller)
36+
github_enterprise:
37+
api_url: ""
38+
token: ""
39+
controller_url: ""
40+
repo_owner_githubapp: ""
41+
repo_installation_id: ""
42+
43+
# GitLab
44+
gitlab:
45+
api_url: "https://gitlab.com"
46+
token: ""
47+
# Project ID (find in repo Settings > General)
48+
project_id: ""
49+
50+
# Gitea / Forgejo
51+
gitea:
52+
api_url: "http://localhost:3000"
53+
# Internal URL for in-cluster access (optional)
54+
# internal_url: "http://forgejo-http.forgejo.svc.cluster.local:3000"
55+
password: "pac"
56+
username: "pac"
57+
repo_owner: "pac/pac"
58+
smee_url: ""
59+
60+
# Bitbucket Cloud
61+
bitbucket_cloud:
62+
api_url: "https://api.bitbucket.org/2.0"
63+
# Username from "Personal Bitbucket settings"
64+
user: ""
65+
token: ""
66+
# Format: workspace/repo
67+
e2e_repository: ""
68+
69+
# Bitbucket Data Center (Server)
70+
bitbucket_server:
71+
api_url: ""
72+
user: ""
73+
token: ""
74+
# Format: project/repo
75+
e2e_repository: ""
76+
webhook_secret: ""

test/main_test.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//go:build e2e
2+
3+
package test
4+
5+
import (
6+
"fmt"
7+
"os"
8+
"testing"
9+
10+
"github.com/openshift-pipelines/pipelines-as-code/test/pkg/configfile"
11+
)
12+
13+
func TestMain(m *testing.M) {
14+
if configPath := os.Getenv("PAC_E2E_CONFIG"); configPath != "" {
15+
if err := configfile.LoadConfig(configPath); err != nil {
16+
fmt.Fprintf(os.Stderr, "Error loading E2E config %s: %v\n", configPath, err)
17+
os.Exit(1)
18+
}
19+
}
20+
os.Exit(m.Run())
21+
}

test/pkg/configfile/config.go

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package configfile
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"reflect"
7+
8+
"sigs.k8s.io/yaml"
9+
)
10+
11+
type E2EConfig struct {
12+
Common CommonConfig `json:"common" yaml:"common"`
13+
GitHub GitHubConfig `json:"github" yaml:"github"`
14+
GitHubEnterprise GitHubEnterpriseConfig `json:"github_enterprise" yaml:"github_enterprise"`
15+
GitLab GitLabConfig `json:"gitlab" yaml:"gitlab"`
16+
Gitea GiteaConfig `json:"gitea" yaml:"gitea"`
17+
BitbucketCloud BitbucketCloudConfig `json:"bitbucket_cloud" yaml:"bitbucket_cloud"`
18+
BitbucketServer BitbucketServerConfig `json:"bitbucket_server" yaml:"bitbucket_server"`
19+
}
20+
21+
type CommonConfig struct {
22+
ControllerURL string `env:"TEST_EL_URL" json:"controller_url" yaml:"controller_url"`
23+
WebhookSecret string `env:"TEST_EL_WEBHOOK_SECRET" json:"webhook_secret" yaml:"webhook_secret"`
24+
NoCleanup string `env:"TEST_NOCLEANUP" json:"no_cleanup" yaml:"no_cleanup"`
25+
}
26+
27+
type GitHubConfig struct {
28+
APIURL string `env:"TEST_GITHUB_API_URL" json:"api_url" yaml:"api_url"`
29+
Token string `env:"TEST_GITHUB_TOKEN" json:"token" yaml:"token"`
30+
RepoOwnerGithubApp string `env:"TEST_GITHUB_REPO_OWNER_GITHUBAPP" json:"repo_owner_githubapp" yaml:"repo_owner_githubapp"`
31+
RepoOwnerWebhook string `env:"TEST_GITHUB_REPO_OWNER_WEBHOOK" json:"repo_owner_webhook" yaml:"repo_owner_webhook"`
32+
RepoInstallationID string `env:"TEST_GITHUB_REPO_INSTALLATION_ID" json:"repo_installation_id" yaml:"repo_installation_id"`
33+
PrivateTaskName string `env:"TEST_GITHUB_PRIVATE_TASK_NAME" json:"private_task_name" yaml:"private_task_name"`
34+
PrivateTaskURL string `env:"TEST_GITHUB_PRIVATE_TASK_URL" json:"private_task_url" yaml:"private_task_url"`
35+
}
36+
37+
type GitHubEnterpriseConfig struct {
38+
APIURL string `env:"TEST_GITHUB_SECOND_API_URL" json:"api_url" yaml:"api_url"`
39+
Token string `env:"TEST_GITHUB_SECOND_TOKEN" json:"token" yaml:"token"`
40+
ControllerURL string `env:"TEST_GITHUB_SECOND_EL_URL" json:"controller_url" yaml:"controller_url"`
41+
RepoOwnerGithubApp string `env:"TEST_GITHUB_SECOND_REPO_OWNER_GITHUBAPP" json:"repo_owner_githubapp" yaml:"repo_owner_githubapp"`
42+
RepoInstallationID string `env:"TEST_GITHUB_SECOND_REPO_INSTALLATION_ID" json:"repo_installation_id" yaml:"repo_installation_id"`
43+
}
44+
45+
type GitLabConfig struct {
46+
APIURL string `env:"TEST_GITLAB_API_URL" json:"api_url" yaml:"api_url"`
47+
Token string `env:"TEST_GITLAB_TOKEN" json:"token" yaml:"token"`
48+
ProjectID string `env:"TEST_GITLAB_PROJECT_ID" json:"project_id" yaml:"project_id"`
49+
}
50+
51+
type GiteaConfig struct {
52+
APIURL string `env:"TEST_GITEA_API_URL" json:"api_url" yaml:"api_url"`
53+
InternalURL string `env:"TEST_GITEA_INTERNAL_URL" json:"internal_url" yaml:"internal_url"`
54+
Password string `env:"TEST_GITEA_PASSWORD" json:"password" yaml:"password"`
55+
Username string `env:"TEST_GITEA_USERNAME" json:"username" yaml:"username"`
56+
RepoOwner string `env:"TEST_GITEA_REPO_OWNER" json:"repo_owner" yaml:"repo_owner"`
57+
SmeeURL string `env:"TEST_GITEA_SMEEURL" json:"smee_url" yaml:"smee_url"`
58+
}
59+
60+
type BitbucketCloudConfig struct {
61+
APIURL string `env:"TEST_BITBUCKET_CLOUD_API_URL" json:"api_url" yaml:"api_url"`
62+
User string `env:"TEST_BITBUCKET_CLOUD_USER" json:"user" yaml:"user"`
63+
Token string `env:"TEST_BITBUCKET_CLOUD_TOKEN" json:"token" yaml:"token"`
64+
E2ERepository string `env:"TEST_BITBUCKET_CLOUD_E2E_REPOSITORY" json:"e2e_repository" yaml:"e2e_repository"`
65+
}
66+
67+
type BitbucketServerConfig struct {
68+
APIURL string `env:"TEST_BITBUCKET_SERVER_API_URL" json:"api_url" yaml:"api_url"`
69+
User string `env:"TEST_BITBUCKET_SERVER_USER" json:"user" yaml:"user"`
70+
Token string `env:"TEST_BITBUCKET_SERVER_TOKEN" json:"token" yaml:"token"`
71+
E2ERepository string `env:"TEST_BITBUCKET_SERVER_E2E_REPOSITORY" json:"e2e_repository" yaml:"e2e_repository"`
72+
WebhookSecret string `env:"TEST_BITBUCKET_SERVER_WEBHOOK_SECRET" json:"webhook_secret" yaml:"webhook_secret"`
73+
}
74+
75+
// LoadConfig reads a YAML config file and sets environment variables for any
76+
// field that has an `env` struct tag. Existing environment variables take
77+
// precedence over values from the config file.
78+
func LoadConfig(path string) error {
79+
data, err := os.ReadFile(path)
80+
if err != nil {
81+
return fmt.Errorf("reading config file %s: %w", path, err)
82+
}
83+
84+
var cfg E2EConfig
85+
if err := yaml.Unmarshal(data, &cfg); err != nil {
86+
return fmt.Errorf("parsing config file %s: %w", path, err)
87+
}
88+
89+
setEnvsFromStruct(reflect.ValueOf(cfg))
90+
return nil
91+
}
92+
93+
// setEnvsFromStruct walks all fields of a struct (recursing into nested
94+
// structs) and calls os.Setenv for each field that has an `env` tag, but only
95+
// when the environment variable is not already set and the YAML value is
96+
// non-empty.
97+
func setEnvsFromStruct(v reflect.Value) {
98+
t := v.Type()
99+
for i := range t.NumField() {
100+
field := t.Field(i)
101+
value := v.Field(i)
102+
103+
if field.Type.Kind() == reflect.Struct {
104+
setEnvsFromStruct(value)
105+
continue
106+
}
107+
108+
envKey := field.Tag.Get("env")
109+
if envKey == "" {
110+
continue
111+
}
112+
113+
yamlVal := value.String()
114+
if yamlVal == "" {
115+
continue
116+
}
117+
118+
if _, exists := os.LookupEnv(envKey); exists {
119+
continue
120+
}
121+
122+
os.Setenv(envKey, yamlVal)
123+
}
124+
}

0 commit comments

Comments
 (0)