Compare commits

..

9 Commits

Author SHA1 Message Date
Somefive
12f392cd92 Fix: rollout workload namespace not aligned with rollout (#3107)
Signed-off-by: Somefive <yd219913@alibaba-inc.com>
2022-01-17 20:06:27 +08:00
StevenLeiZhang
af27e6a776 ignore vela-system, which is specified in needNamespace for addon metadata information (#3109)
Signed-off-by: StevenLeiZhang <zhangleiic@163.com>
2022-01-17 20:02:05 +08:00
StevenLeiZhang
f57815a5bf ignore files under the addon path of github addon registry (#3099)
Signed-off-by: StevenLeiZhang <zhangleiic@163.com>
2022-01-17 20:01:46 +08:00
Somefive
69527b257c Feat: support external revision in patch component (#3106)
Signed-off-by: Somefive <yd219913@alibaba-inc.com>
2022-01-17 19:29:28 +08:00
barnettZQG
d88d4d8eca Fix: clear old data in mongodb unit test case (#3103)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2022-01-17 19:06:29 +08:00
Zheng Xi Zhou
4e881b44af Fix: support generate cloud resource docs in Chinese (#3079)
* Fix: support generate cloud resource docs in Chinese

`vela def doc-gen` will also generate Chinese cloud resource docs

Signed-off-by: Zheng Xi Zhou <zzxwill@gmail.com>

* Continue the development

Signed-off-by: Zheng Xi Zhou <zzxwill@gmail.com>

* add ut

Signed-off-by: Zheng Xi Zhou <zzxwill@gmail.com>

* add ut and fix linting issue

Signed-off-by: Zheng Xi Zhou <zzxwill@gmail.com>

* Address comments

Signed-off-by: Zheng Xi Zhou <zzxwill@gmail.com>

* Fix `Should not use dot imports. (ST1001) ` issue

Signed-off-by: Zheng Xi Zhou <zzxwill@gmail.com>

* add copyright

Signed-off-by: Zheng Xi Zhou <zzxwill@gmail.com>
2022-01-17 16:18:59 +08:00
wyike
800b50cf0b fix acr image no version (#3100)
Signed-off-by: 楚岳 <wangyike.wyk@alibaba-inc.com>
2022-01-17 16:09:21 +08:00
Jianbo Sun
3d9e1c7d80 Fix: use personel token of vela-bot instead of github token for homebrew update (#3096)
Signed-off-by: Jianbo Sun <jianbo.sjb@alibaba-inc.com>
2022-01-17 11:45:01 +08:00
barnettZQG
fccc5df25e Fix: can't query data from the MongoDB (#3095)
Signed-off-by: barnettZQG <barnett.zqg@gmail.com>
2022-01-17 11:25:09 +08:00
17 changed files with 529 additions and 215 deletions

View File

@@ -57,7 +57,7 @@ jobs:
- name: Build & Pushing vela-core for ACR
run: |
docker build --build-arg GOPROXY=https://proxy.golang.org -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }} .
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }} .
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-core:${{ steps.get_version.outputs.VERSION }}
- uses: docker/build-push-action@v2
name: Build & Pushing vela-core for Dockerhub and GHCR
@@ -79,7 +79,7 @@ jobs:
- name: Build & Pushing vela-apiserver for ACR
run: |
docker build --build-arg GOPROXY=https://proxy.golang.org -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }} -f Dockerfile.apiserver .
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }} -f Dockerfile.apiserver .
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-apiserver:${{ steps.get_version.outputs.VERSION }}
- uses: docker/build-push-action@v2
name: Build & Pushing vela-apiserver for Dockerhub and GHCR
@@ -101,7 +101,7 @@ jobs:
- name: Build & Pushing vela runtime rollout for ACR
run: |
docker build --build-arg GOPROXY=https://proxy.golang.org -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }} .
docker build --build-arg GOPROXY=https://proxy.golang.org --build-arg VERSION=${{ steps.get_version.outputs.VERSION }} --build-arg GITVERSION=git-${{ steps.vars.outputs.git_revision }} -t kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }} .
docker push kubevela-registry.cn-hangzhou.cr.aliyuncs.com/oamdev/vela-rollout:${{ steps.get_version.outputs.VERSION }}
- uses: docker/build-push-action@v2
name: Build & Pushing runtime rollout for Dockerhub and GHCR

View File

@@ -142,7 +142,7 @@ jobs:
- name: Update Homebrew formula
uses: dawidd6/action-homebrew-bump-formula@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
token: ${{ secrets.HOMEBREW_TOKEN }}
formula: kubevela
tag: ${{ github.ref }}
revision: ${{ github.sha }}

View File

@@ -45,10 +45,11 @@ func (in *EnvTraitPatch) ToApplicationTrait() *common.ApplicationTrait {
// EnvComponentPatch is the patch to component
type EnvComponentPatch struct {
Name string `json:"name"`
Type string `json:"type"`
Properties *runtime.RawExtension `json:"properties,omitempty"`
Traits []EnvTraitPatch `json:"traits,omitempty"`
Name string `json:"name"`
Type string `json:"type"`
Properties *runtime.RawExtension `json:"properties,omitempty"`
Traits []EnvTraitPatch `json:"traits,omitempty"`
ExternalRevision string `json:"externalRevision,omitempty"`
}
// ToApplicationComponent convert EnvComponentPatch into ApplicationComponent

View File

@@ -467,6 +467,10 @@ func RenderApp(ctx context.Context, addon *InstallPackage, config *rest.Config,
}
app.Labels = util.MergeMapOverrideWithDst(app.Labels, map[string]string{oam.LabelAddonName: addon.Name})
for _, namespace := range addon.NeedNamespace {
// vela-system must exist before rendering vela addon
if namespace == types.DefaultKubeVelaNS {
continue
}
comp := common2.ApplicationComponent{
Type: "raw",
Name: fmt.Sprintf("%s-namespace", namespace),

View File

@@ -226,6 +226,17 @@ func TestRenderApp(t *testing.T) {
assert.Equal(t, len(app.Spec.Components), 2)
}
func TestRenderAppWithNeedNamespace(t *testing.T) {
addon := baseAddon
addon.NeedNamespace = append(addon.NeedNamespace, types.DefaultKubeVelaNS)
app, err := RenderApp(ctx, &addon, nil, nil, map[string]interface{}{})
assert.NoError(t, err, "render app fail")
assert.Equal(t, len(app.Spec.Components), 2)
for _, c := range app.Spec.Components {
assert.NotEqual(t, types.DefaultKubeVelaNS+"-namespace", c.Name, "namespace vela-system should not be rendered")
}
}
func TestRenderDeploy2RuntimeAddon(t *testing.T) {
addonDeployToRuntime := baseAddon
addonDeployToRuntime.Meta.DeployTo = &DeployTo{

View File

@@ -48,6 +48,9 @@ func (g *gitReader) ListAddonMeta() (map[string]SourceMeta, error) {
}
for _, item := range items {
// single addon
if item.GetType() != DirType {
continue
}
addonName := path.Base(item.GetPath())
addonMeta, err := g.listAddonMeta(g.RelativePath(item))
if err != nil {

View File

@@ -41,6 +41,9 @@ var (
// ErrIndexInvalid Error that entity index is invalid
ErrIndexInvalid = NewDBError(fmt.Errorf("entity index is invalid"))
// ErrEntityInvalid Error that entity is invalid
ErrEntityInvalid = NewDBError(fmt.Errorf("entity is invalid"))
)
// DBError datastore error

View File

@@ -37,6 +37,9 @@ type mongodb struct {
database string
}
// PrimaryKey primary key
const PrimaryKey = "_name"
// New new mongodb datastore instance
func New(ctx context.Context, cfg datastore.Config) (datastore.DataStore, error) {
if !strings.HasPrefix(cfg.URL, "mongodb://") {
@@ -67,8 +70,13 @@ func (m *mongodb) Add(ctx context.Context, entity datastore.Entity) error {
if err := m.Get(ctx, entity); err == nil {
return datastore.ErrRecordExist
}
model, err := convertToMap(entity)
if err != nil {
return datastore.ErrEntityInvalid
}
model[PrimaryKey] = entity.PrimaryKey()
collection := m.client.Database(m.database).Collection(entity.TableName())
_, err := collection.InsertOne(ctx, entity)
_, err = collection.InsertOne(ctx, model)
if err != nil {
return datastore.NewDBError(err)
}
@@ -203,7 +211,7 @@ func (m *mongodb) List(ctx context.Context, entity datastore.Entity, op *datasto
if entity.Index() != nil {
for k, v := range entity.Index() {
filter = append(filter, bson.E{
Key: k,
Key: strings.ToLower(k),
Value: v,
})
}
@@ -279,9 +287,21 @@ func (m *mongodb) Count(ctx context.Context, entity datastore.Entity, filterOpti
}
func makeNameFilter(name string) bson.D {
return bson.D{{Key: "name", Value: name}}
return bson.D{{Key: PrimaryKey, Value: name}}
}
func makeEntityUpdate(entity interface{}) bson.M {
return bson.M{"$set": entity}
}
func convertToMap(model interface{}) (bson.M, error) {
b, err := bson.Marshal(model)
if err != nil {
return nil, err
}
var re = make(bson.M)
if err := bson.Unmarshal(b, &re); err != nil {
return nil, err
}
return re, nil
}

View File

@@ -26,6 +26,8 @@ import (
"github.com/google/go-cmp/cmp/cmpopts"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
"github.com/oam-dev/kubevela/pkg/apiserver/datastore"
"github.com/oam-dev/kubevela/pkg/apiserver/model"
@@ -35,7 +37,11 @@ var mongodbDriver datastore.DataStore
var _ = BeforeSuite(func(done Done) {
rand.Seed(time.Now().UnixNano())
By("bootstrapping mongodb test environment")
var err error
clientOpts := options.Client().ApplyURI("mongodb://localhost:27017")
client, err := mongo.Connect(context.TODO(), clientOpts)
Expect(err).ToNot(HaveOccurred())
client.Database("kubevela").Drop(context.TODO())
mongodbDriver, err = New(context.TODO(), datastore.Config{
URL: "mongodb://localhost:27017",
Database: "kubevela",
@@ -65,6 +71,8 @@ var _ = Describe("Test mongodb datastore driver", func() {
&model.Application{Name: "kubevela-app-2", Description: "this is demo 2"},
&model.Application{Name: "kubevela-app-3", Description: "this is demo 3"},
&model.Application{Name: "kubevela-app-4", Description: "this is demo 4"},
&model.Workflow{Name: "kubevela-app-workflow", AppPrimaryKey: "kubevela-app-2", Description: "this is workflow"},
&model.ApplicationTrigger{Name: "kubevela-app-trigger", AppPrimaryKey: "kubevela-app-2", Token: "token-test", Description: "this is demo 4"},
}
err := mongodbDriver.BatchAdd(context.TODO(), datas)
Expect(err).ToNot(HaveOccurred())
@@ -84,6 +92,12 @@ var _ = Describe("Test mongodb datastore driver", func() {
Expect(err).Should(BeNil())
diff := cmp.Diff(app.Description, "default")
Expect(diff).Should(BeEmpty())
workflow := &model.Workflow{Name: "kubevela-app-workflow", AppPrimaryKey: "kubevela-app-2"}
err = mongodbDriver.Get(context.TODO(), workflow)
Expect(err).Should(BeNil())
diff = cmp.Diff(workflow.Description, "this is workflow")
Expect(diff).Should(BeEmpty())
})
It("Test put function", func() {
@@ -111,6 +125,14 @@ var _ = Describe("Test mongodb datastore driver", func() {
Expect(err).ShouldNot(HaveOccurred())
diff = cmp.Diff(len(list), 4)
Expect(diff).Should(BeEmpty())
var workflow = model.Workflow{
AppPrimaryKey: "kubevela-app-2",
}
list, err = mongodbDriver.List(context.TODO(), &workflow, nil)
Expect(err).ShouldNot(HaveOccurred())
diff = cmp.Diff(len(list), 1)
Expect(diff).Should(BeEmpty())
})
It("Test list clusters with sort and fuzzy query", func() {
@@ -213,5 +235,13 @@ var _ = Describe("Test mongodb datastore driver", func() {
err = mongodbDriver.Delete(context.TODO(), &app)
equal := cmp.Equal(err, datastore.ErrRecordNotExist, cmpopts.EquateErrors())
Expect(equal).Should(BeTrue())
workflow := model.Workflow{Name: "kubevela-app-workflow", AppPrimaryKey: "kubevela-app-2", Description: "this is workflow"}
err = mongodbDriver.Delete(context.TODO(), &workflow)
Expect(err).ShouldNot(HaveOccurred())
trigger := model.ApplicationTrigger{Name: "kubevela-app-trigger", AppPrimaryKey: "kubevela-app-2", Token: "token-test", Description: "this is demo 4"}
err = mongodbDriver.Delete(context.TODO(), &trigger)
Expect(err).ShouldNot(HaveOccurred())
})
})

View File

@@ -221,10 +221,8 @@ func (h *handler) handleRolloutModified() {
// setWorkloadBaseInfo set base workload base info, which is such as workload name and component revision label
func (h *handler) setWorkloadBaseInfo() {
if len(h.targetWorkload.GetNamespace()) == 0 {
h.targetWorkload.SetNamespace(h.rollout.Namespace)
}
if h.sourceWorkload != nil && len(h.sourceWorkload.GetNamespace()) == 0 {
h.targetWorkload.SetNamespace(h.rollout.Namespace)
if h.sourceWorkload != nil {
h.sourceWorkload.SetNamespace(h.rollout.Namespace)
}

View File

@@ -66,6 +66,11 @@ func MergeComponent(base *common.ApplicationComponent, patch *v1alpha1.EnvCompon
return nil, errors.Wrapf(err, "failed to merge component properties")
}
// merge component external revision
if patch.ExternalRevision != "" {
newComponent.ExternalRevision = patch.ExternalRevision
}
// prepare traits
traitMaps := map[string]*common.ApplicationTrait{}
var traitOrders []string

View File

@@ -19,7 +19,7 @@ package envbinding
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"github.com/oam-dev/kubevela/apis/core.oam.dev/common"
@@ -29,111 +29,68 @@ import (
)
func Test_EnvBindApp_GenerateConfiguredApplication(t *testing.T) {
testcases := []struct {
testCases := map[string]struct {
baseApp *v1beta1.Application
envName string
envPatch v1alpha1.EnvPatch
expectedApp *v1beta1.Application
selector *v1alpha1.EnvSelector
}{{
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
Traits: []v1alpha1.EnvTraitPatch{{
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "newTestsvc.example.com",
}),
}},
}},
},
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
}{
"normal-test": {
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"port": 8000,
}),
Traits: []common.ApplicationTrait{{
Traits: []v1alpha1.EnvTraitPatch{{
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "newTestsvc.example.com",
"http": map[string]interface{}{
"/": 8000,
},
}),
}},
}},
},
},
}, {
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "express-server",
Type: "webservice",
Traits: []v1alpha1.EnvTraitPatch{{
Type: "labels",
Properties: util.Object2RawExtension(map[string]interface{}{
"test": "label",
}),
}},
}, {
Name: "new-server",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"cmd": []string{"sleep", "1000"},
}),
Traits: []v1alpha1.EnvTraitPatch{{
Type: "labels",
Properties: util.Object2RawExtension(map[string]interface{}{
"test": "label",
}),
}},
}},
},
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"port": 8000,
}),
Traits: []common.ApplicationTrait{{
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "newTestsvc.example.com",
"http": map[string]interface{}{
"/": 8000,
},
}),
}},
}},
},
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
},
"add-component": {
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
"port": 8000,
}),
Traits: []common.ApplicationTrait{{
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "testsvc.example.com",
"http": map[string]interface{}{
"/": 8000,
},
}),
}, {
Traits: []v1alpha1.EnvTraitPatch{{
Type: "labels",
Properties: util.Object2RawExtension(map[string]interface{}{
"test": "label",
@@ -146,7 +103,7 @@ func Test_EnvBindApp_GenerateConfiguredApplication(t *testing.T) {
"image": "busybox",
"cmd": []string{"sleep", "1000"},
}),
Traits: []common.ApplicationTrait{{
Traits: []v1alpha1.EnvTraitPatch{{
Type: "labels",
Properties: util.Object2RawExtension(map[string]interface{}{
"test": "label",
@@ -154,67 +111,92 @@ func Test_EnvBindApp_GenerateConfiguredApplication(t *testing.T) {
}},
}},
},
},
}, {
// Test Disable Trait
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "express-server",
Type: "webservice",
Traits: []v1alpha1.EnvTraitPatch{{
Type: "ingress-1-20",
Disable: true,
}},
}},
},
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
"port": 8000,
}),
Traits: []common.ApplicationTrait{{
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "testsvc.example.com",
"http": map[string]interface{}{
"/": 8000,
},
}),
}, {
Type: "labels",
Properties: util.Object2RawExtension(map[string]interface{}{
"test": "label",
}),
}},
}, {
Name: "new-server",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
"cmd": []string{"sleep", "1000"},
}),
Traits: []common.ApplicationTrait{{
Type: "labels",
Properties: util.Object2RawExtension(map[string]interface{}{
"test": "label",
}),
}},
}},
},
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
},
"disable-trait": {
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
"port": 8000,
}),
Traits: []common.ApplicationTrait{},
Traits: []v1alpha1.EnvTraitPatch{{
Type: "ingress-1-20",
Disable: true,
}},
}},
},
},
}, {
// Test component selector
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "new-server",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
}},
},
selector: &v1alpha1.EnvSelector{
Components: []string{"new-server"},
},
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
"port": 8000,
}),
Traits: []common.ApplicationTrait{},
}},
},
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
},
"component-selector": {
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "new-server",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
@@ -222,41 +204,105 @@ func Test_EnvBindApp_GenerateConfiguredApplication(t *testing.T) {
}),
}},
},
},
}, {
// Test empty component selector
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "new-server",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
}},
},
selector: &v1alpha1.EnvSelector{
Components: []string{},
},
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
selector: &v1alpha1.EnvSelector{
Components: []string{"new-server"},
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{},
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "new-server",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
}},
},
},
},
}}
"empty-component-selector": {
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "new-server",
Type: "worker",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "busybox",
}),
}},
},
selector: &v1alpha1.EnvSelector{
Components: []string{},
},
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{},
},
},
},
"patch-external-revision": {
baseApp: baseApp,
envName: "prod",
envPatch: v1alpha1.EnvPatch{
Components: []v1alpha1.EnvComponentPatch{{
Name: "express-server",
Type: "webservice",
ExternalRevision: "external-rev",
}},
},
expectedApp: &v1beta1.Application{
TypeMeta: metav1.TypeMeta{
APIVersion: "v1beta1",
Kind: "Application",
},
ObjectMeta: metav1.ObjectMeta{
Name: "test",
},
Spec: v1beta1.ApplicationSpec{
Components: []common.ApplicationComponent{{
Name: "express-server",
Type: "webservice",
Properties: util.Object2RawExtension(map[string]interface{}{
"image": "crccheck/hello-world",
"port": 8000,
}),
ExternalRevision: "external-rev",
Traits: []common.ApplicationTrait{{
Type: "ingress-1-20",
Properties: util.Object2RawExtension(map[string]interface{}{
"domain": "testsvc.example.com",
"http": map[string]interface{}{
"/": 8000,
},
}),
}},
}},
},
},
},
}
for _, testcase := range testcases {
app, err := PatchApplication(testcase.baseApp, &testcase.envPatch, testcase.selector)
assert.NoError(t, err)
assert.Equal(t, testcase.expectedApp, app)
for name, tc := range testCases {
t.Run(name, func(t *testing.T) {
app, err := PatchApplication(tc.baseApp, &tc.envPatch, tc.selector)
r := require.New(t)
r.NoError(err)
r.Equal(tc.expectedApp, app)
})
}
}

View File

@@ -23,6 +23,7 @@
disable?: bool
properties: {...}
}]
externalRevision?: string
}
#ReadPlacementDecisions: {

View File

@@ -432,12 +432,20 @@ func NewDefinitionGenDocCommand(c common.Args) *cobra.Command {
ref := &plugins.MarkdownReference{}
ctx := context.Background()
ref.DefinitionName = args[0]
path := plugins.KubeVelaIOTerraformPath
if err := ref.GenerateReferenceDocs(ctx, c, path, namespace); err != nil {
pathEn := plugins.KubeVelaIOTerraformPath
ref.I18N = plugins.En
if err := ref.GenerateReferenceDocs(ctx, c, pathEn, namespace); err != nil {
return errors.Wrap(err, "failed to generate reference docs")
}
cmd.Printf("Generated docs for %s in ./%s/%s.md\n", args[0], path, args[0])
cmd.Printf("Generated docs in English for %s in %s/%s.md\n", args[0], pathEn, args[0])
pathZh := plugins.KubeVelaIOTerraformPathZh
ref.I18N = plugins.Zh
if err := ref.GenerateReferenceDocs(ctx, c, pathZh, namespace); err != nil {
return errors.Wrap(err, "failed to generate reference docs")
}
cmd.Printf("Generated docs in Chinese for %s in %s/%s.md\n", args[0], pathZh, args[0])
return nil
},
}

View File

@@ -0,0 +1,79 @@
/*
Copyright 2022 The KubeVela Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package plugins
// Language is used to define the language
type Language string
const (
// En is English, the default language
En Language = "English"
// Zh is Chinese
Zh Language = "Chinese"
)
// Definitions are all the words and phrases for internationalization in cli and docs
var Definitions = map[string]map[Language]string{
"Description": {
Zh: "描述",
En: "Description",
},
"Samples": {
Zh: "示例",
En: "Samples",
},
"Specification": {
Zh: "参数说明",
En: "Specification",
},
"AlibabaCloud": {
Zh: "阿里云",
En: "Alibaba Cloud",
},
"Name": {
Zh: "名称",
En: "Name",
},
"Type": {
Zh: "类型",
En: "Type",
},
"Required": {
Zh: "是否必须",
En: "Required",
},
"Default": {
Zh: "默认值",
En: "Default",
},
"WriteConnectionSecretToRefIntroduction": {
Zh: "如果设置了 `writeConnectionSecretToRef`,一个 Kubernetes Secret 将会被创建并且它的数据里有这些键key",
En: "If `writeConnectionSecretToRef` is set, a secret will be generated with these keys as below:",
},
"Outputs": {
Zh: "输出",
En: "Outputs",
},
"Properties": {
Zh: "属性",
En: "Properties",
},
"Terraform_configuration_for_Alibaba_Cloud_ACK_cluster": {
Zh: "用于部署阿里云 ACK 集群的组件说明",
En: "Terraform configuration for Alibaba Cloud ACK cluster",
},
}

View File

@@ -43,6 +43,12 @@ func TestCreateRefTestDir(t *testing.T) {
}
func TestCreateMarkdown(t *testing.T) {
ctx := context.Background()
ref := &MarkdownReference{}
refZh := &MarkdownReference{}
refZh.I18N = Zh
workloadName := "workload1"
traitName := "trait1"
scopeName := "scope1"
@@ -86,11 +92,13 @@ variable "acl" {
cases := map[string]struct {
reason string
ref *MarkdownReference
capabilities []types.Capability
want error
}{
"WorkloadTypeAndTraitCapability": {
reason: "valid capabilities",
ref: ref,
capabilities: []types.Capability{
{
Name: workloadName,
@@ -115,6 +123,7 @@ variable "acl" {
},
"ScopeTypeCapability": {
reason: "invalid capabilities",
ref: ref,
capabilities: []types.Capability{
{
Name: scopeName,
@@ -123,12 +132,24 @@ variable "acl" {
},
want: fmt.Errorf("the type of the capability is not right"),
},
"TerraformCapabilityInChinese": {
reason: "terraform capability",
ref: refZh,
capabilities: []types.Capability{
{
Name: workloadName2,
TerraformConfiguration: configuration,
Type: types.TypeWorkload,
Category: types.TerraformCategory,
},
},
want: nil,
},
}
ref := &MarkdownReference{}
ctx := context.Background()
for name, tc := range cases {
t.Run(name, func(t *testing.T) {
got := ref.CreateMarkdown(ctx, tc.capabilities, RefTestDir, ReferenceSourcePath)
got := tc.ref.CreateMarkdown(ctx, tc.capabilities, RefTestDir, ReferenceSourcePath)
if diff := cmp.Diff(tc.want, got, test.EquateErrors()); diff != "" {
t.Errorf("\n%s\nCreateMakrdown(...): -want error, +got error:\n%s", tc.reason, diff)
}
@@ -476,7 +497,7 @@ func TestPrepareTerraformOutputs(t *testing.T) {
tableName: "abc",
parameterList: []ReferenceParameter{param},
},
expect: "\n\nabc\n\nName | Description\n------------ | ------------- \n ID | Identity of the cloud resource\n",
expect: "\n\nabc\n\n Name | Description \n ------------ | ------------- \n ID | Identity of the cloud resource\n",
},
}
ref := &MarkdownReference{}
@@ -492,8 +513,15 @@ func TestPrepareTerraformOutputs(t *testing.T) {
func TestMakeReadableTitle(t *testing.T) {
type args struct {
ref *MarkdownReference
title string
}
ref := &MarkdownReference{}
refZh := &MarkdownReference{}
refZh.I18N = Zh
testcases := []struct {
args args
want string
@@ -501,25 +529,35 @@ func TestMakeReadableTitle(t *testing.T) {
{
args: args{
title: "abc",
ref: ref,
},
want: "Abc",
},
{
args: args{
title: "abc-def",
ref: ref,
},
want: "Abc-Def",
},
{
args: args{
title: "alibaba-def-ghi",
ref: ref,
},
want: "Alibaba Cloud DEF-GHI",
},
{
args: args{
title: "alibaba-def-ghi",
ref: refZh,
},
want: "阿里云 DEF-GHI",
},
}
for _, tc := range testcases {
t.Run("", func(t *testing.T) {
title := makeReadableTitle(tc.args.title)
title := tc.args.ref.makeReadableTitle(tc.args.title)
if title != tc.want {
t.Errorf("makeReadableTitle(...): -want, +got:\n%s\n", cmp.Diff(tc.want, title))
}

View File

@@ -44,7 +44,9 @@ const (
// BaseRefPath is the target path for reference docs
BaseRefPath = "docs/en/end-user"
// KubeVelaIOTerraformPath is the target path for kubevela.io terraform docs
KubeVelaIOTerraformPath = "kubevela.io/docs/end-user/components/cloud-services/terraform"
KubeVelaIOTerraformPath = "../kubevela.io/docs/end-user/components/cloud-services/terraform"
// KubeVelaIOTerraformPathZh is the target path for kubevela.io terraform docs in Chinese
KubeVelaIOTerraformPathZh = "../kubevela.io/i18n/zh/docusaurus-plugin-content-docs/current/end-user/components/cloud-services/terraform"
// ReferenceSourcePath is the location for source reference
ReferenceSourcePath = "hack/references"
// ComponentDefinitionTypePath is the URL path for component typed capability
@@ -72,6 +74,7 @@ type Reference interface {
// ParseReference is used to include the common function `parseParameter`
type ParseReference struct {
Client client.Client
I18N Language `json:"i18n"`
}
// MarkdownReference is the struct for capability information in
@@ -293,6 +296,7 @@ spec:
name: bar
key: bar
`,
"worker": `
apiVersion: core.oam.dev/v1beta1
kind: Application
@@ -324,6 +328,38 @@ spec:
writeConnectionSecretToRef:
name: vpc-conn
`,
"alibaba-rds": `
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: rds-cloud-source
spec:
components:
- name: sample-db
type: alibaba-rds
properties:
instance_name: sample-db
account_name: oamtest
password: U34rfwefwefffaked
writeConnectionSecretToRef:
name: db-conn
`,
"alibaba-ack": `
apiVersion: core.oam.dev/v1beta1
kind: Application
metadata:
name: ack-cloud-source
spec:
components:
- name: ack-cluster
type: alibaba-ack
properties:
writeConnectionSecretToRef:
name: ack-conn
namespace: vela-system
`,
}
// BaseOpenAPIV3Template is Standard OpenAPIV3 Template
@@ -391,6 +427,11 @@ func (ref *MarkdownReference) GenerateReferenceDocs(ctx context.Context, c commo
func (ref *MarkdownReference) CreateMarkdown(ctx context.Context, caps []types.Capability, baseRefPath, referenceSourcePath string) error {
setDisplayFormat("markdown")
for i, c := range caps {
var (
description string
sample string
specification string
)
if c.Type != types.TypeWorkload && c.Type != types.TypeComponentDefinition && c.Type != types.TypeTrait {
return fmt.Errorf("the type of the capability is not right")
}
@@ -412,7 +453,11 @@ func (ref *MarkdownReference) CreateMarkdown(ctx context.Context, caps []types.C
}
capName := c.Name
refContent = ""
capNameInTitle := makeReadableTitle(capName)
lang := ref.I18N
if lang == "" {
lang = En
}
capNameInTitle := ref.makeReadableTitle(capName)
switch c.Category {
case types.CUECategory:
cueValue, err := common.GetCUEParameterValue(c.CueTemplate)
@@ -448,14 +493,18 @@ func (ref *MarkdownReference) CreateMarkdown(ctx context.Context, caps []types.C
return fmt.Errorf("unsupport capability category %s", c.Category)
}
title := fmt.Sprintf("---\ntitle: %s\n---", capNameInTitle)
description := fmt.Sprintf("\n\n## Description\n\n%s", c.Description)
var sample string
sampleContent := ref.generateSample(capName)
if sampleContent != "" {
sample = fmt.Sprintf("\n\n## Samples\n\n%s", sampleContent)
descriptionI18N := c.Description
des := strings.ReplaceAll(c.Description, " ", "_")
if v, ok := Definitions[des]; ok {
descriptionI18N = v[lang]
}
specification := fmt.Sprintf("\n\n## Specification\n%s", refContent)
description = fmt.Sprintf("\n\n## %s\n\n%s", Definitions["Description"][lang], descriptionI18N)
if sampleContent != "" {
sample = fmt.Sprintf("\n\n## %s\n\n%s", Definitions["Samples"][lang], sampleContent)
}
specification = fmt.Sprintf("\n\n## %s\n%s", Definitions["Specification"][lang], refContent)
// it's fine if the conflict info files not found
conflictWithAndMoreSection, _ := ref.generateConflictWithAndMore(capName, referenceSourcePath)
@@ -471,11 +520,15 @@ func (ref *MarkdownReference) CreateMarkdown(ctx context.Context, caps []types.C
return nil
}
func makeReadableTitle(title string) string {
func (ref *MarkdownReference) makeReadableTitle(title string) string {
const alibabaCloud = "alibaba-"
if ref.I18N == "" {
ref.I18N = En
}
var AlibabaCloudTitle = Definitions["AlibabaCloud"][ref.I18N]
if strings.HasPrefix(title, alibabaCloud) {
cloudResource := strings.Replace(title, alibabaCloud, "", 1)
return "Alibaba Cloud " + strings.ToUpper(cloudResource)
return fmt.Sprintf("%s %s", AlibabaCloudTitle, strings.ToUpper(cloudResource))
}
return strings.Title(title)
}
@@ -483,8 +536,12 @@ func makeReadableTitle(title string) string {
// prepareParameter prepares the table content for each property
func (ref *MarkdownReference) prepareParameter(tableName string, parameterList []ReferenceParameter, category types.CapabilityCategory) string {
refContent := fmt.Sprintf("\n\n%s\n\n", tableName)
refContent += "Name | Description | Type | Required | Default \n"
refContent += "------------ | ------------- | ------------- | ------------- | ------------- \n"
lang := ref.I18N
if lang == "" {
lang = En
}
refContent += fmt.Sprintf(" %s | %s | %s | %s | %s \n", Definitions["Name"][lang], Definitions["Description"][lang], Definitions["Type"][lang], Definitions["Required"][lang], Definitions["Default"][lang])
refContent += " ------------ | ------------- | ------------- | ------------- | ------------- \n"
switch category {
case types.CUECategory:
for _, p := range parameterList {
@@ -519,8 +576,12 @@ func (ref *MarkdownReference) prepareTerraformOutputs(tableName string, paramete
return ""
}
refContent := fmt.Sprintf("\n\n%s\n\n", tableName)
refContent += "Name | Description\n"
refContent += "------------ | ------------- \n"
lang := ref.I18N
if lang == "" {
lang = En
}
refContent += fmt.Sprintf(" %s | %s \n", Definitions["Name"][lang], Definitions["Description"][lang])
refContent += " ------------ | ------------- \n"
for _, p := range parameterList {
refContent += fmt.Sprintf(" %s | %s\n", p.Name, p.Usage)
@@ -784,7 +845,15 @@ func (ref *ParseReference) parseTerraformCapabilityParameters(capability types.C
err error
outputsList []ReferenceParameter
outputsTables []ReferenceParameterTable
propertiesTitle string
outputsTableName string
)
lang := ref.I18N
if lang == "" {
lang = En
}
outputsTableName = fmt.Sprintf("%s %s\n\n%s", strings.Repeat("#", 3), Definitions["Outputs"][lang], Definitions["WriteConnectionSecretToRefIntroduction"][lang])
propertiesTitle = Definitions["Properties"][lang]
writeConnectionSecretToRefReferenceParameter.Name = terraform.TerraformWriteConnectionSecretToRefName
writeConnectionSecretToRefReferenceParameter.PrintableType = terraform.TerraformWriteConnectionSecretToRefType
@@ -814,7 +883,7 @@ func (ref *ParseReference) parseTerraformCapabilityParameters(capability types.C
}
refParameterList = append(refParameterList, writeConnectionSecretToRefReferenceParameter)
propertiesTableName := fmt.Sprintf("%s %s", strings.Repeat("#", 3), "Properties")
propertiesTableName := fmt.Sprintf("%s %s", strings.Repeat("#", 3), propertiesTitle)
tables = append(tables, ReferenceParameterTable{
Name: propertiesTableName,
Parameters: refParameterList,
@@ -852,8 +921,6 @@ func (ref *ParseReference) parseTerraformCapabilityParameters(capability types.C
outputsList = append(outputsList, refParam)
}
outputsTableName := fmt.Sprintf("%s %s\n\nIf `writeConnectionSecretToRef` is set, a secret will be generated with these keys as below:", strings.Repeat("#", 3), "Outputs")
outputsTables = append(outputsTables, ReferenceParameterTable{
Name: outputsTableName,
Parameters: outputsList,