diff --git a/.github/workflows/slack.yml b/.github/workflows/slack.yml index afd9a5b3..b7b85f31 100644 --- a/.github/workflows/slack.yml +++ b/.github/workflows/slack.yml @@ -1,16 +1,30 @@ -name: Slack Notify on Star -on: watch +name: Slack Notify +on: + watch: + types: [started] jobs: star-notify: + if: github.event_name == 'watch' name: Notify Slack on star - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 steps: - name: Get current star count run: | - echo "STARS=$(curl --silent 'https://api.github.com/repos/layer5io/meshkit' -H 'Accept: application/vnd.github.preview' | jq '.watchers_count')" >> $GITHUB_ENV + echo "STARS=$(curl --silent 'https://api.github.com/repos/${{github.repository}}' -H 'Accept: application/vnd.github.preview' | jq '.stargazers_count')" >> $GITHUB_ENV - name: Notify slack env: SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} uses: pullreminders/slack-action@master with: - args: '{\"channel\":\"CSK7N9TGX\",\"text\":\"${{ github.actor }} just starred Meshkit! (https://github.com/layer5io/meshkit/stargazers) Total ⭐️: ${{env.STARS}}\"}' + args: '{\"channel\":\"CSK7N9TGX\",\"text\":\"${{ github.actor }} just starred ${{github.repository}}! (https://github.com/${{github.repository}}/stargazers) Total ⭐️: ${{env.STARS}}\"}' + good-first-issue-notify: + if: github.event_name == 'issues' && github.event.label.name == 'good first issue' || github.event.label.name == 'first-timers-only' + name: Notify Slack for new good-first-issue + runs-on: ubuntu-22.04 + steps: + - name: Notify slack + env: + SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }} + uses: pullreminders/slack-action@master + with: + args: '{\"channel\":\"C019426UBNY\",\"text\":\"A good first issue label was just added to ${{github.event.issue.html_url}}.\"}' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 00417cc3..d254b26e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -50,22 +50,6 @@ Or you may configure your IDE, for example, Visual Studio Code to automatically -## Documentation Contribution Flow -Please contribute! Layer5 documentation uses Jekyll and GitHub Pages to host docs sites. Learn more about [Layer5's documentation framework](https://docs.google.com/document/d/17guuaxb0xsfutBCzyj2CT6OZiFnMu9w4PzoILXhRXSo/edit?usp=sharing). The process of contributing follows this flow: - -1. Create a fork, if you have not already, by following the steps described [here](./CONTRIBUTING-gitflow.md) -1. In the local copy of your fork, navigate to the docs folder. -`cd docs` -1. Create and checkout a new branch to make changes within -`git checkout -b ` -1. Edit/add documentation. -`vi .md` -1. Run site locally to preview changes. -`make site` -1. Commit, [sign-off](#commit-signing), and push changes to your remote branch. -`git push origin ` -1. Open a pull request (in your web browser) against the repo. - #### Tests Users can now test their code on their local machine against the CI checks implemented using `make run-tests`. @@ -92,7 +76,7 @@ All contributors are invited to review pull requests. See this short video on [h Resources: https://lab.github.com and https://try.github.com/ -# FQA +# FAQs ### Instructions for making custom dictionary entries diff --git a/go.mod b/go.mod index ea10a40a..8e252044 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/google/uuid v1.6.0 github.com/kubernetes/kompose v1.31.1 github.com/layer5io/meshery-operator v0.7.0 - github.com/meshery/schemas v0.7.31 + github.com/meshery/schemas v0.7.36 github.com/nats-io/nats.go v1.31.0 github.com/open-policy-agent/opa v0.67.1 github.com/opencontainers/image-spec v1.1.0 @@ -39,7 +39,7 @@ require ( gopkg.in/yaml.v3 v3.0.1 gorm.io/driver/postgres v1.5.3 gorm.io/driver/sqlite v1.5.4 - gorm.io/gorm v1.25.11 + gorm.io/gorm v1.25.12 helm.sh/helm/v3 v3.13.2 k8s.io/api v0.28.4 k8s.io/apimachinery v0.28.4 diff --git a/go.sum b/go.sum index 9aad5ca9..f4b94cd3 100644 --- a/go.sum +++ b/go.sum @@ -608,8 +608,8 @@ github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/meshery/kompose v1.0.1 h1:lg8B/pkLh6762jeFsQATD8UJZZwXZf/aviC3/dzw78A= github.com/meshery/kompose v1.0.1/go.mod h1:TWhWTEMbJBUzENf4JTEtBmZRFm/r8n0nS6v4/nSD2vA= -github.com/meshery/schemas v0.7.31 h1:FfVR+oErAiiEomt6sTZI5uKhoyU26QXawT6UDZHbthI= -github.com/meshery/schemas v0.7.31/go.mod h1:UfiO+zm92yLkaJP0aroNwVnjuozoh793AWDXrKDYmT0= +github.com/meshery/schemas v0.7.36 h1:KQOz/SODr+T6fDS2lDSrNo/Eu3LCaEUGIRauQtvXkjg= +github.com/meshery/schemas v0.7.36/go.mod h1:wOh519/EDxiYlC4aeGv74ru+t9h9VJ4P2JYIvSfdPWQ= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM= github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk= @@ -1198,8 +1198,8 @@ gorm.io/driver/postgres v1.5.3 h1:qKGY5CPHOuj47K/VxbCXJfFvIUeqMSXXadqdCY+MbBU= gorm.io/driver/postgres v1.5.3/go.mod h1:F+LtvlFhZT7UBiA81mC9W6Su3D4WUhSboc/36QZU0gk= gorm.io/driver/sqlite v1.5.4 h1:IqXwXi8M/ZlPzH/947tn5uik3aYQslP9BVveoax0nV0= gorm.io/driver/sqlite v1.5.4/go.mod h1:qxAuCol+2r6PannQDpOP1FP6ag3mKi4esLnB/jHed+4= -gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg= -gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= gotest.tools/v3 v3.4.0 h1:ZazjZUfuVeZGLAmlKKuyv3IKP5orXcwtOwDQH6YVr6o= diff --git a/models/meshmodel/registry/v1alpha3/relationship_filter.go b/models/meshmodel/registry/v1alpha3/relationship_filter.go index 624c683a..de31351e 100644 --- a/models/meshmodel/registry/v1alpha3/relationship_filter.go +++ b/models/meshmodel/registry/v1alpha3/relationship_filter.go @@ -74,6 +74,9 @@ func (relationshipFilter *RelationshipFilter) Get(db *database.Handler) ([]entit if relationshipFilter.SubType != "" { finder = finder.Where("relationship_definition_dbs.sub_type = ?", relationshipFilter.SubType) } + if relationshipFilter.Id != "" { + finder = finder.Where("relationship_definition_dbs.id = ?", relationshipFilter.Id) + } if relationshipFilter.ModelName != "" { finder = finder.Where("model_dbs.name = ?", relationshipFilter.ModelName) } diff --git a/models/meshmodel/registry/v1beta1/category_filter.go b/models/meshmodel/registry/v1beta1/category_filter.go index 399385a1..520614ae 100644 --- a/models/meshmodel/registry/v1beta1/category_filter.go +++ b/models/meshmodel/registry/v1beta1/category_filter.go @@ -50,6 +50,9 @@ func (cf *CategoryFilter) Get(db *database.Handler) ([]entity.Entity, int64, int finder = finder.Where("name = ?", cf.Name) } } + if cf.Id != "" { + finder = finder.Where("id = ?", cf.Id) + } if cf.OrderOn != "" { if cf.Sort == "desc" { finder = finder.Order(clause.OrderByColumn{Column: clause.Column{Name: cf.OrderOn}, Desc: true}) diff --git a/models/meshmodel/registry/v1beta1/component_filter.go b/models/meshmodel/registry/v1beta1/component_filter.go index 76a6fb57..47aefe58 100644 --- a/models/meshmodel/registry/v1beta1/component_filter.go +++ b/models/meshmodel/registry/v1beta1/component_filter.go @@ -116,7 +116,9 @@ func (componentFilter *ComponentFilter) Get(db *database.Handler) ([]entity.Enti if componentFilter.Version != "" { finder = finder.Where("model_dbs.model->>'version' = ?", componentFilter.Version) } - + if componentFilter.Id != "" { + finder = finder.Where("component_definition_dbs.id = ?", componentFilter.Id) + } if componentFilter.OrderOn != "" { if componentFilter.Sort == "desc" { finder = finder.Order(clause.OrderByColumn{Column: clause.Column{Name: componentFilter.OrderOn}, Desc: true}) diff --git a/models/meshmodel/registry/v1beta1/model_filter.go b/models/meshmodel/registry/v1beta1/model_filter.go index 6a512f79..cb014d5b 100644 --- a/models/meshmodel/registry/v1beta1/model_filter.go +++ b/models/meshmodel/registry/v1beta1/model_filter.go @@ -29,6 +29,9 @@ type ModelFilter struct { Components bool Relationships bool Status string + // When Trim is true it will only send necessary models data + // like: component count, relationship count, id and name of model + Trim bool } // Create the filter from map[string]interface{} @@ -138,6 +141,9 @@ func (mf *ModelFilter) Get(db *database.Handler) ([]entity.Entity, int64, int, e } else if mf.Annotations == "false" { finder = finder.Where("model_dbs.metadata->>'isAnnotation' = false") } + if mf.Id != "" { + finder = finder.Where("model_dbs.id = ?", mf.Id) + } if mf.OrderOn != "" { if mf.Sort == "desc" { finder = finder.Order(clause.OrderByColumn{Column: clause.Column{Name: mf.OrderOn}, Desc: true}) @@ -179,27 +185,48 @@ func (mf *ModelFilter) Get(db *database.Handler) ([]entity.Entity, int64, int, e for _, modelDB := range modelWithCategories { // resolve for loop scope _modelDB := modelDB - if includeComponents { - var components []component.ComponentDefinition - finder := db.Model(&component.ComponentDefinition{}). - Select("component_definition_dbs.id, component_definition_dbs.component, component_definition_dbs.display_name, component_definition_dbs.metadata, component_definition_dbs.schema_version, component_definition_dbs.version,component_definition_dbs.styles,component_definition_dbs.capabilities"). - Where("component_definition_dbs.model_id = ?", _modelDB.Id) - if err := finder.Scan(&components).Error; err != nil { - return nil, 0, 0, err + var componentCount int64 + db.Model(&component.ComponentDefinition{}).Where("component_definition_dbs.model_id = ?", _modelDB.Id).Count(&componentCount) + var relationshipCount int64 + db.Model(&relationship.RelationshipDefinition{}).Where("relationship_definition_dbs.model_id = ?", _modelDB.Id).Count(&relationshipCount) + _modelDB.ComponentsCount = int(componentCount) + _modelDB.RelationshipsCount = int(relationshipCount) + + // If Trim is true, only include the id, name, counts and metadata + if mf.Trim { + trimmedModel := &model.ModelDefinition{ + Id: _modelDB.Id, + Name: _modelDB.Name, + DisplayName: _modelDB.DisplayName, + Metadata: _modelDB.Metadata, + ComponentsCount: int(componentCount), + RelationshipsCount: int(relationshipCount), } - _modelDB.Components = components - } - if includeRelationships { - var relationships []relationship.RelationshipDefinition - finder := db.Model(&relationship.RelationshipDefinition{}). - Select("relationship_definition_dbs.*"). - Where("relationship_definition_dbs.model_id = ?", _modelDB.Id) - if err := finder.Scan(&relationships).Error; err != nil { - return nil, 0, 0, err + defs = append(defs, trimmedModel) + + } else { + if includeComponents { + var components []component.ComponentDefinition + finder := db.Model(&component.ComponentDefinition{}). + Select("component_definition_dbs.*"). + Where("component_definition_dbs.model_id = ?", _modelDB.Id) + if err := finder.Scan(&components).Error; err != nil { + return nil, 0, 0, err + } + _modelDB.Components = components + } + if includeRelationships { + var relationships []relationship.RelationshipDefinition + finder := db.Model(&relationship.RelationshipDefinition{}). + Select("relationship_definition_dbs.*"). + Where("relationship_definition_dbs.model_id = ?", _modelDB.Id) + if err := finder.Scan(&relationships).Error; err != nil { + return nil, 0, 0, err + } + _modelDB.Relationships = relationships } - _modelDB.Relationships = relationships + defs = append(defs, &_modelDB) } - defs = append(defs, &_modelDB) } return defs, count, countUniqueModels(modelWithCategories), nil } diff --git a/models/meshmodel/registry/v1beta1/policy_filter.go b/models/meshmodel/registry/v1beta1/policy_filter.go index d15d970c..3108d68c 100644 --- a/models/meshmodel/registry/v1beta1/policy_filter.go +++ b/models/meshmodel/registry/v1beta1/policy_filter.go @@ -49,7 +49,9 @@ func (pf *PolicyFilter) Get(db *database.Handler) ([]entity.Entity, int64, int, if pf.ModelName != "" { finder = finder.Where("model_dbs.name = ?", pf.ModelName) } - + if pf.Id != "" { + finder = finder.Where("policy_definition_dbs.id = ?", pf.Id) + } var count int64 finder.Count(&count) diff --git a/utils/component/openapi_generator.go b/utils/component/openapi_generator.go index 045fcd6f..8d0178de 100644 --- a/utils/component/openapi_generator.go +++ b/utils/component/openapi_generator.go @@ -4,6 +4,7 @@ import ( "encoding/json" "errors" "fmt" + "strings" "cuelang.org/go/cue" "cuelang.org/go/cue/cuecontext" @@ -100,6 +101,26 @@ func GenerateFromOpenAPI(resource string, pkg models.Package) ([]component.Compo continue } + // Determine if the resource is namespaced + var isNamespaced bool + + scopeCue, err := utils.Lookup(fieldVal, `"x-kubernetes-resource".scope`) + if err == nil { + scope, err := scopeCue.String() + if err == nil { + if scope == "Namespaced" { + isNamespaced = true + } else if scope == "Cluster" { + isNamespaced = false + } + } + } else { + isNamespaced, err = getResourceScope(resource, kind) + if err != nil { + isNamespaced = false + } + } + c := component.ComponentDefinition{ SchemaVersion: v1beta1.ComponentSchemaVersion, Format: component.JSON, @@ -109,6 +130,9 @@ func GenerateFromOpenAPI(resource string, pkg models.Package) ([]component.Compo Schema: string(crd), }, DisplayName: manifests.FormatToReadableString(kind), + Metadata: component.ComponentDefinition_Metadata{ + IsNamespaced: isNamespaced, + }, Model: model.ModelDefinition{ SchemaVersion: v1beta1.ModelSchemaVersion, Model: model.Model{ @@ -127,7 +151,27 @@ func GenerateFromOpenAPI(resource string, pkg models.Package) ([]component.Compo components = append(components, c) } return components, nil +} +func getResourceScope(manifest string, kind string) (bool, error) { + var m map[string]interface{} + + err := yaml.Unmarshal([]byte(manifest), &m) + if err != nil { + return false, utils.ErrDecodeYaml(err) + } + + paths, ok := m["paths"].(map[string]interface{}) + if !ok { + return false, fmt.Errorf("paths not found in manifest") + } + + for path := range paths { + if strings.Contains(path, "/namespaces/{namespace}/") && strings.Contains(path, strings.ToLower(kind)) { + return true, nil // Resource is namespaced + } + } + return false, nil // Resource is cluster-scoped } func getResolvedManifest(manifest string) (string, error) {