Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest]
os: [ubuntu-latest, macos-latest]
go-version: [1.24.0]
arch: [amd64, arm64]

Expand All @@ -54,7 +54,7 @@ jobs:

- name: Build binary
env:
GOOS: linux
GOOS: ${{ matrix.os == 'macos-latest' && 'darwin' || 'linux' }}
GOARCH: ${{ matrix.arch }}
CGO_ENABLED: 0
run: |
Expand All @@ -64,7 +64,11 @@ jobs:
.

# Create checksum file
shasum -a 256 "dist/${{ env.BINARY_NAME }}-${{ matrix.os }}-${{ matrix.arch }}" > "dist/${{ env.BINARY_NAME }}-${{ matrix.os }}-${{ matrix.arch }}.sha256"
if [[ "${{ matrix.os }}" == "macos-latest" ]]; then
shasum -a 256 "dist/${{ env.BINARY_NAME }}-${{ matrix.os }}-${{ matrix.arch }}" > "dist/${{ env.BINARY_NAME }}-${{ matrix.os }}-${{ matrix.arch }}.sha256"
else
shasum -a 256 "dist/${{ env.BINARY_NAME }}-${{ matrix.os }}-${{ matrix.arch }}" > "dist/${{ env.BINARY_NAME }}-${{ matrix.os }}-${{ matrix.arch }}.sha256"
fi

# List files for debugging
ls -la dist/
Expand Down
107 changes: 31 additions & 76 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,113 +17,68 @@
3. 安装 operator
4. 运行测试,再到 步骤2 升级到新版本 operator

## 配置文件
## 运行升级

```yaml
operatorConfig:
workspace: /Users/mac/Desktop/kychen/alaudadevops/gitlab-operator
namespace: gitlab-ce-operator # operator 部署 ns
name: gitlab-ce-operator # operator 名称
upgradePaths: # 定义升级路径,可以包含多个
- name: v17.8 upgrade to v17.11 # 升级名称
versions: # 定义升级路经
- name: v17.8 # 版本名称
testCommand: | # 执行测试指令
# git checkout feat/upgrade-case-17.8
# export REPORT=allure
# make prepare
gitlab17.8.test --godog.concurrency=1 --godog.format=allure --godog.tags=@prepare --bdd.cleanup=false
# testSubPath: v17.8.10
bundleVersion: v17.8.10 # bundle 版本号
- name: v17.11 # 版本名称
testCommand: |
# git checkout feat/upgrade-case-17.11
# export REPORT=allure
# make upgrade
gitlab17.11.test --godog.concurrency=1 --godog.format=allure --godog.tags=@upgrade --bdd.cleanup=false
# testSubPath: v17.11.1
bundleVersion: v17.11.1 # bundle 版本号
### 安装升级工具

通过源码安装

```sh
git clone https://github.com/AlaudaDevops/upgrade-test
cd upgrade-test
go build -o upgrade
```

在 [release](https://github.com/AlaudaDevops/upgrade-test/releases) 页面下载对应系统版本的二进制。

```bash
wget https://github.com/AlaudaDevops/upgrade-test/releases/download/v0.0.5/upgrade-ubuntu-latest-amd64
mv upgrade-ubuntu-latest-amd64 upgrade && chmod +x upgrade
./upgrade
```

## 测试用例的编写
### 测试用例的编写

测试用例分文两个部分:

1. 数据准备。

- 数据准备多次执行应该具备幂等性,确保可以重复运行。
- 需要添加 skip-clean-namespace 的 Tag 确保执行后实例不被清理。
- 需要添加 `skip-clean-namespace` 的 Tag 确保执行后实例不被清理。

2. 检查升级数据。

- 和数据准备相对应,负责升级实例以及检查准备的数据是否丢失。
- 存在多次升级时,需要添加 skip-clean-namespace 的 Tag 确保执行后实例不被清理。
- 存在多次升级时,需要添加 `skip-clean-namespace` 的 Tag 确保执行后实例不被清理。

## 本地运行
### 编写配置文件

本地可以使用 git 命令切换分支,达到更换测试case的目的,然后使用 make 命令执行case。配置示例:
将文件保存为 upgrade.yaml

```yaml
operatorConfig:
workspace: /Users/mac/Desktop/kychen/alaudadevops/gitlab-operator
workspace: /app/testing/ # test case 执行位置
namespace: gitlab-ce-operator # operator 部署 ns
name: gitlab-ce-operator # operator 名称
upgradePaths: # 定义升级路径,可以包含多个
- name: v17.8 upgrade to v17.11 # 升级名称
versions: # 定义升级路经
- name: v17.8 # 版本名称
testCommand: | # 执行测试指令
git checkout feat/upgrade-case-17.8
export REPORT=allure
make prepare
testSubPath: testing
gitlab17.8.test --godog.concurrency=1 --godog.format=allure --godog.tags=@prepare
bundleVersion: v17.8.10 # bundle 版本号
channel: stable
- name: v17.11 # 版本名称
testCommand: |
git checkout feat/upgrade-case-17.11
export REPORT=allure
make upgrade
testSubPath: testing
gitlab17.11.test --godog.concurrency=1 --godog.format=allure --godog.tags=@upgrade --bdd.cleanup=false
bundleVersion: v17.11.1 # bundle 版本号
channel: stable
```

## 流水线中运行

流水线中运行需要提前构建好执行测试的二进制,以及升级工具。镜像目录结构如下:
### 运行测试

```sh
├── /bin/
│   └── gitlab17.11.test # 17.11 用例执行文件
│   └── gitlab17.8.test # #17.8 用例执行文件
│   └── upgrade # 升级测试工具
├── /app/testing
│   └── v17.8
│   └──── allure-results... # 测试所需文件
│   └── v17.11
│   └──── allure-results... # 测试所需文件
│   └── config.yaml # 测试执行的 yaml 配置
```

config yaml 配置如下:

```yaml
operatorConfig:
workspace: /app/testing
namespace: gitlab-ce-operator # operator 部署 ns
name: gitlab-ce-operator # operator 名称
upgradePaths: # 定义升级路径,可以包含多个
- name: v17.8 upgrade to v17.11 # 升级名称
versions: # 定义升级路经
- name: v17.8 # 版本名称
testCommand: | # 执行测试指令
gitlab17.8.test --godog.concurrency=1 --godog.format=allure --godog.tags=@prepare --bdd.cleanup=false
testSubPath: v17.8
bundleVersion: v17.8.10 # bundle 版本号
testImage: testimage:v17.8.10
- name: v17.11 # 版本名称
testCommand: |
gitlab17.11.test --godog.concurrency=1 --godog.format=allure --godog.tags=@upgrade --bdd.cleanup=false
testSubPath: v17.11
bundleVersion: v17.11.1 # bundle 版本号
testImage: testimage:v17.8.10
# 配置链接的集群
export KUBECONFIG=<kubeconfig.yaml>
./upgrade --config upgrade.yaml
```
13 changes: 10 additions & 3 deletions cmd/upgrade_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,12 @@ func (uc *UpgradeCommand) getKubeconfig() string {
uc.kubeconfig = filepath.Join(os.Getenv("HOME"), ".kube", "config")
}
}

// If KUBECONFIG is not set, set it to the kubeconfig path from config file, which will be inherited by the shell running test commands
if os.Getenv("KUBECONFIG") == "" {
os.Setenv("KUBECONFIG", uc.kubeconfig)
}

return uc.kubeconfig
}

Expand Down Expand Up @@ -197,13 +203,14 @@ func (uc *UpgradeCommand) process(ctx context.Context, path config.UpgradePath)
testCommand = version.TestCommand
}

if version.TestSubPath == "" {
version.TestSubPath = "testing"
workspace := uc.config.OperatorConfig.Workspace
if version.TestSubPath != "" {
workspace = fmt.Sprintf("%s/%s", uc.config.OperatorConfig.Workspace, version.TestSubPath)
Comment on lines +206 to +208
Copy link

Copilot AI Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The workspace path construction duplicates uc.config.OperatorConfig.Workspace. Consider using filepath.Join() for cross-platform path handling and store the base workspace in a variable to avoid repetition.

Suggested change
workspace := uc.config.OperatorConfig.Workspace
if version.TestSubPath != "" {
workspace = fmt.Sprintf("%s/%s", uc.config.OperatorConfig.Workspace, version.TestSubPath)
baseWorkspace := uc.config.OperatorConfig.Workspace
workspace := baseWorkspace
if version.TestSubPath != "" {
workspace = filepath.Join(baseWorkspace, version.TestSubPath)

Copilot uses AI. Check for mistakes.
}

// Execute test commands
if err := uc.execCommand(ctx,
fmt.Sprintf("%s/%s", uc.config.OperatorConfig.Workspace, version.TestSubPath),
workspace,
testCommand); err != nil {
return fmt.Errorf("failed to execute test command: %v", err)
}
Expand Down
4 changes: 3 additions & 1 deletion configs/gitlab/config.yaml → configs/demo.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
operatorConfig:
workspace: /Users/mac/Desktop/kychen/alaudadevops/gitlab-operator
workspace: /Users/mac/Desktop/kychen/alaudadevops/gitlab-operator/testing
namespace: gitlab-ce-operator
name: gitlab-ce-operator
upgradePaths: # 定义升级路径,可以包含多个
Expand All @@ -10,8 +10,10 @@ upgradePaths: # 定义升级路径,可以包含多个
export REPORT=allure
[email protected] make test
bundleVersion: v17.8.10
channel: stable
- name: v17.11 # 版本名称
testCommand: |
[email protected] GODOG_ARGS="--godog.format=allure --bdd.cleanup=false" make test
bundleVersion: v17.11.1
channel: stable

22 changes: 21 additions & 1 deletion pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ package config

import (
"os"
"time"

"gopkg.in/yaml.v2"
)
Expand Down Expand Up @@ -38,6 +39,14 @@ type OperatorConfig struct {
// workspace is the path to the workspace directory
Workspace string `yaml:"workspace,omitempty"`

// artifactPrefix is the prefix of the artifact to use, default is "operatorhub"
ArtifactPrefix string `yaml:"artifactPrefix,omitempty"`

// interval is the interval to use for the operator, default is 5 seconds
Interval time.Duration `yaml:"interval,omitempty"`
// timeout is the timeout to use for the operator, default is 10 minutes
Timeout time.Duration `yaml:"timeout,omitempty"`

// command for running the operator, just for local operator, default is "make deploy"
Command string `yaml:"command,omitempty"`
}
Expand All @@ -61,7 +70,7 @@ type Version struct {
// testSubPath is the path to the test sub-directory, default is "testing"
TestSubPath string `yaml:"testSubPath,omitempty"`
// revision is the revision to use for the version
Revision string `yaml:"revision,omitempty"`
Channel string `yaml:"channel,omitempty"`
}

// LoadConfig loads the configuration from a YAML file
Expand All @@ -88,5 +97,16 @@ func defaultConfig(config *Config) *Config {
config.OperatorConfig.Type = "operatorhub"
}

if config.OperatorConfig.ArtifactPrefix == "" {
config.OperatorConfig.ArtifactPrefix = "operatorhub"
}

if config.OperatorConfig.Interval == 0 {
config.OperatorConfig.Interval = 5 * time.Second
}
if config.OperatorConfig.Timeout == 0 {
config.OperatorConfig.Timeout = 10 * time.Minute
}

return config
}
9 changes: 9 additions & 0 deletions pkg/exec/exec.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type Command struct {
Name string
Args []string
Dir string
Env []string
}

// CommandResult represents the result of a command execution
Expand Down Expand Up @@ -43,6 +44,14 @@ func RunCommand(ctx context.Context, cmd Command) CommandResult {
runCmd := exec.CommandContext(ctx, cmd.Name, cmd.Args...)
runCmd.Dir = cmd.Dir

// Inherit current process environment variables
runCmd.Env = os.Environ()

// Add custom environment variables if specified
if len(cmd.Env) > 0 {
runCmd.Env = append(runCmd.Env, cmd.Env...)
}

// Create buffers to capture output
var stdoutBuf, stderrBuf bytes.Buffer

Expand Down
4 changes: 2 additions & 2 deletions pkg/operator/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ func NewOperatorFactory() *OperatorFactory {
func (f *OperatorFactory) CreateOperator(operatorType OperatorType, options OperatorOptions) (OperatorInterface, error) {
switch operatorType {
case OperatorTypeLocal:
return local.NewLocalOperator(options.OperatorConfig.Workspace, options.OperatorConfig.Command)
return local.NewLocalOperator(options.OperatorConfig)
default:
return operatorhub.NewOperator(options.Config, options.Namespace, options.Name)
return operatorhub.NewOperator(options.Config, options.OperatorConfig)
}
}
7 changes: 4 additions & 3 deletions pkg/operator/local/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"fmt"

"github.com/AlaudaDevops/upgrade-test/pkg/config"
"github.com/AlaudaDevops/upgrade-test/pkg/exec"
"knative.dev/pkg/logging"
)
Expand All @@ -14,10 +15,10 @@ type LocalOperator struct {
versionRevision map[string]string
}

func NewLocalOperator(workDir string, command string) (*LocalOperator, error) {
func NewLocalOperator(options config.OperatorConfig) (*LocalOperator, error) {
return &LocalOperator{
workDir: workDir,
command: command,
workDir: options.Workspace,
command: options.Command,
}, nil
}

Expand Down
4 changes: 2 additions & 2 deletions pkg/operator/operatorhub/artifact_versiong.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func (o *Operator) InstallArtifactVersion(ctx context.Context, version string) (
log := logging.FromContext(ctx)
log.Infow("installing artifact version", "version", version)

artifact, err := o.GetResource(ctx, fmt.Sprintf("operatorhub-%s", o.name), systemNamespace, artifactGVR)
artifact, err := o.GetResource(ctx, o.artifact, systemNamespace, artifactGVR)
if err != nil {
return nil, fmt.Errorf("failed to get artifact: %v", err)
}
Expand Down Expand Up @@ -91,7 +91,7 @@ func (o *Operator) createArtifactVersion(ctx context.Context, version string, ar

func (o *Operator) waitArtifactVersionPresent(ctx context.Context, name string) (*unstructured.Unstructured, error) {
lastResource := &unstructured.Unstructured{}
err := wait.PollUntilContextTimeout(ctx, o.interval, o.timeout, false, func(ctx context.Context) (done bool, err error) {
err := wait.PollUntilContextTimeout(ctx, o.interval, o.timeout, true, func(ctx context.Context) (done bool, err error) {
obj, err := o.client.Resource(artifactVersionGVR).Namespace(systemNamespace).Get(ctx, name, metav1.GetOptions{})
if err != nil {
return false, err
Expand Down
18 changes: 13 additions & 5 deletions pkg/operator/operatorhub/operator.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"time"

"github.com/AlaudaDevops/upgrade-test/pkg/config"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand All @@ -17,6 +18,7 @@ type Operator struct {
client dynamic.Interface
namespace string
name string
artifact string

timeout time.Duration
interval time.Duration
Expand Down Expand Up @@ -68,18 +70,24 @@ var (
)

// NewOperator creates a new Operator instance
func NewOperator(config *rest.Config, namespace, name string) (*Operator, error) {
func NewOperator(config *rest.Config, options config.OperatorConfig) (*Operator, error) {
client, err := dynamic.NewForConfig(config)
if err != nil {
return nil, err
}

artifact := options.Artifact
if artifact == "" {
artifact = fmt.Sprintf("%s-%s", options.ArtifactPrefix, options.Name)
}

return &Operator{
client: client,
namespace: namespace,
name: name,
timeout: 10 * time.Minute,
interval: 5 * time.Second,
namespace: options.Namespace,
name: options.Name,
artifact: artifact,
timeout: options.Timeout,
interval: options.Interval,
}, nil
}

Expand Down
Loading