Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(ui,api): ascode core mirror help #4872

Merged
merged 14 commits into from
Jan 27, 2020
69 changes: 36 additions & 33 deletions cli/cdsctl/tools.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"reflect"
"strings"

"github.com/alecthomas/jsonschema"
"github.com/spf13/cobra"

"github.com/ovh/cds/cli"
"github.com/ovh/cds/sdk/exportentities"
)

const (
Expand Down Expand Up @@ -75,6 +71,11 @@ func (y yamlSchemaVSCodeInstaller) Install(schemas yamlSchemaPath) error {
}

func toolsYamlSchemaRun(v cli.Values) error {
res, err := client.UserGetSchema()
if err != nil {
return err
}

var installer yamlSchemaInstaller

switch v.GetString("ide-name") {
Expand All @@ -84,13 +85,6 @@ func toolsYamlSchemaRun(v cli.Values) error {
return fmt.Errorf("Invalid given IDE name")
}

types := []reflect.Type{
reflect.TypeOf(exportentities.Workflow{}),
reflect.TypeOf(exportentities.PipelineV1{}),
reflect.TypeOf(exportentities.Application{}),
reflect.TypeOf(exportentities.Environment{}),
}

home, err := os.UserHomeDir()
targetFolder := home + "/" + targetFolderName
if err != nil {
Expand All @@ -103,28 +97,37 @@ func toolsYamlSchemaRun(v cli.Values) error {
return fmt.Errorf("Cannot create folder %s: %s", targetFolder, err)
}

results := make([]string, len(types))
for i := range types {
r := jsonschema.Reflector{
AllowAdditionalProperties: true,
RequiredFromJSONSchemaTags: true,
}
sch := r.ReflectFromType(types[i])

buf, _ := json.MarshalIndent(sch, "", "\t")
path := fmt.Sprintf("%s/%s.schema.json", targetFolder, types[i].Name())
if err := ioutil.WriteFile(path, buf, 0775); err != nil {
return fmt.Errorf("Cannot write file at %s: %s", path, err)
}
fmt.Printf("File %s successfully written.\n", path)

results[i] = "file://" + path
paths := yamlSchemaPath{
Workflow: fmt.Sprintf("%s/workflow.schema.json", targetFolder),
Pipeline: fmt.Sprintf("%s/pipeline.schema.json", targetFolder),
Application: fmt.Sprintf("%s/application.schema.json", targetFolder),
Environment: fmt.Sprintf("%s/environment.schema.json", targetFolder),
}

return installer.Install(yamlSchemaPath{
Workflow: results[0],
Pipeline: results[1],
Application: results[2],
Environment: results[3],
})
if err := ioutil.WriteFile(paths.Workflow, []byte(res.Workflow), 0775); err != nil {
return fmt.Errorf("Cannot write file at %s: %s", paths.Workflow, err)
}
fmt.Printf("File %s successfully written.\n", paths.Workflow)

if err := ioutil.WriteFile(paths.Pipeline, []byte(res.Pipeline), 0775); err != nil {
return fmt.Errorf("Cannot write file at %s: %s", paths.Pipeline, err)
}
fmt.Printf("File %s successfully written.\n", paths.Pipeline)

if err := ioutil.WriteFile(paths.Application, []byte(res.Application), 0775); err != nil {
return fmt.Errorf("Cannot write file at %s: %s", paths.Application, err)
}
fmt.Printf("File %s successfully written.\n", paths.Application)

if err := ioutil.WriteFile(paths.Environment, []byte(res.Environment), 0775); err != nil {
return fmt.Errorf("Cannot write file at %s: %s", paths.Environment, err)
}
fmt.Printf("File %s successfully written.\n", paths.Environment)

paths.Workflow = "file://" + paths.Workflow
paths.Pipeline = "file://" + paths.Pipeline
paths.Application = "file://" + paths.Application
paths.Environment = "file://" + paths.Environment

return installer.Install(paths)
}
1 change: 1 addition & 0 deletions engine/api/api_routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ func (api *API) InitRouter() {
// Users
r.Handle("/user", Scope(sdk.AuthConsumerScopeUser), r.GET(api.getUsersHandler))
r.Handle("/user/favorite", Scope(sdk.AuthConsumerScopeUser), r.POST(api.postUserFavoriteHandler))
r.Handle("/user/schema", Scope(sdk.AuthConsumerScopeUser), r.GET(api.getUserJSONSchema))
r.Handle("/user/timeline", Scope(sdk.AuthConsumerScopeUser), r.GET(api.getTimelineHandler))
r.Handle("/user/timeline/filter", Scope(sdk.AuthConsumerScopeUser), r.GET(api.getTimelineFilterHandler), r.POST(api.postTimelineFilterHandler))
r.Handle("/user/{permUsernamePublic}", Scope(sdk.AuthConsumerScopeUser), r.GET(api.getUserHandler), r.PUT(api.putUserHandler), r.DELETE(api.deleteUserHandler))
Expand Down
2 changes: 1 addition & 1 deletion engine/api/user_bookmark.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,6 @@ func (api *API) postUserFavoriteHandler() service.Handler {
return service.WriteJSON(w, p, http.StatusOK)
}

return sdk.ErrInvalidFavoriteType
return sdk.WithStack(sdk.ErrInvalidFavoriteType)
}
}
115 changes: 115 additions & 0 deletions engine/api/user_schema.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package api

import (
"context"
"encoding/json"
"fmt"
"net/http"
"reflect"

"github.com/alecthomas/jsonschema"

"github.com/ovh/cds/engine/api/action"
"github.com/ovh/cds/engine/api/group"
"github.com/ovh/cds/engine/service"
"github.com/ovh/cds/sdk"
"github.com/ovh/cds/sdk/exportentities"
"github.com/ovh/cds/sdk/slug"
)

func (api *API) getUserJSONSchema() service.Handler {
return func(ctx context.Context, w http.ResponseWriter, r *http.Request) error {
filter := FormString(r, "filter")

var res sdk.SchemaResponse

ref := jsonschema.Reflector{
RequiredFromJSONSchemaTags: true,
}

var sch *jsonschema.Schema
if filter == "" || filter == "workflow" {
sch = ref.ReflectFromType(reflect.TypeOf(exportentities.Workflow{}))
buf, _ := json.Marshal(sch)
res.Workflow = string(buf)
}

if filter == "" || filter == "pipeline" {
var as []sdk.Action
var err error
if isMaintainer(ctx) || isAdmin(ctx) {
as, err = action.LoadAllByTypes(ctx, api.mustDB(),
[]string{sdk.DefaultAction},
action.LoadOptions.WithGroup,
action.LoadOptions.WithParameters,
)
} else {
as, err = action.LoadAllTypeDefaultByGroupIDs(ctx, api.mustDB(),
append(getAPIConsumer(ctx).GetGroupIDs(), group.SharedInfraGroup.ID),
action.LoadOptions.WithGroup,
action.LoadOptions.WithParameters,
)
}
if err != nil {
return err
}

sch = ref.ReflectFromType(reflect.TypeOf(exportentities.PipelineV1{}))
for i := range as {
path := fmt.Sprintf("%s/%s", as[i].Group.Name, as[i].Name)
s := slug.Convert(path)
sch.Definitions["Step"].Properties[path] = &jsonschema.Type{
Version: "http://json-schema.org/draft-04/schema#",
Ref: "#/definitions/" + s,
Description: as[i].Description,
}
sch.Definitions["Step"].OneOf = append(sch.Definitions["Step"].OneOf, &jsonschema.Type{
Required: []string{
path,
},
Title: path,
})

sch.Definitions[s] = &jsonschema.Type{
Properties: map[string]*jsonschema.Type{},
AdditionalProperties: sch.Definitions["Step"].AdditionalProperties,
Type: "object",
}
for j := range as[i].Parameters {
p := as[i].Parameters[j]
switch p.Type {
case "number":
sch.Definitions[s].Properties[p.Name] = &jsonschema.Type{
Type: "integer",
}
case "boolean":
sch.Definitions[s].Properties[p.Name] = &jsonschema.Type{
Type: "boolean",
}
default:
sch.Definitions[s].Properties[p.Name] = &jsonschema.Type{
Type: "string",
}
}
}
}

buf, _ := json.Marshal(sch)
res.Pipeline = string(buf)
}

if filter == "" || filter == "application" {
sch = ref.ReflectFromType(reflect.TypeOf(exportentities.Application{}))
buf, _ := json.Marshal(sch)
res.Application = string(buf)
}

if filter == "" || filter == "environment" {
sch = ref.ReflectFromType(reflect.TypeOf(exportentities.Environment{}))
buf, _ := json.Marshal(sch)
res.Environment = string(buf)
}

return service.WriteJSON(w, res, http.StatusOK)
}
}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,8 @@ require (
sigs.k8s.io/yaml v1.1.0 // indirect
)

replace github.com/alecthomas/jsonschema => github.com/sguiheux/jsonschema v0.1.1
sguiheux marked this conversation as resolved.
Show resolved Hide resolved

replace github.com/go-gorp/gorp => github.com/yesnault/gorp v2.0.1-0.20190906143353-6210446a0d92+incompatible

replace github.com/docker/docker => github.com/docker/engine v0.0.0-20180816081446-320063a2ad06
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,9 @@ github.com/sethgrid/pester v0.0.0-20171127025028-760f8913c048 h1:6Men5bEVIDWxw4f
github.com/sethgrid/pester v0.0.0-20171127025028-760f8913c048/go.mod h1:Ad7IjTpvzZO8Fl0vh9AzQ+j/jYZfyp2diGwI8m5q+ns=
github.com/sguiheux/go-coverage v0.0.0-20190710153556-287b082a7197 h1:qu90yDtRE5WEfRT5mn9v0Xz9RaopLguhbPwZKx4dHq8=
github.com/sguiheux/go-coverage v0.0.0-20190710153556-287b082a7197/go.mod h1:0hhKrsUsoT7yvxwNGKa+TSYNA26DNWMqReeZEQq/9FI=
github.com/sguiheux/jsonschema v0.1.0/go.mod h1:Juc2PrI3wtNfUwptSvAIeNx+HrETwHQs6nf+TkOJlOA=
github.com/sguiheux/jsonschema v0.1.1 h1:kD5UgnA0NBlW/6jFgsYOeAAxcWYYtofHceqVVQ2X5aE=
github.com/sguiheux/jsonschema v0.1.1/go.mod h1:Juc2PrI3wtNfUwptSvAIeNx+HrETwHQs6nf+TkOJlOA=
github.com/shirou/gopsutil v0.0.0-20170406131756-e49a95f3d5f8 h1:05R1OwSk31dkzqf2Jf27n2IOoF9zkK9LcPgPsEm8U7U=
github.com/shirou/gopsutil v0.0.0-20170406131756-e49a95f3d5f8/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/sirupsen/logrus v1.0.6/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
Expand Down Expand Up @@ -523,6 +526,7 @@ github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 h1:hNna6Fi0eP1f2sMBe/rJicDmaHmoXGe1Ta84FPYHLuE=
Expand Down
8 changes: 8 additions & 0 deletions sdk/cdsclient/client_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,11 @@ func (c *client) UpdateFavorite(params sdk.FavoriteParams) (interface{}, error)
}
return res, nil
}

func (c *client) UserGetSchema() (sdk.SchemaResponse, error) {
var res sdk.SchemaResponse
if _, err := c.GetJSON(context.Background(), "/user/schema", &res); err != nil {
return res, err
}
return res, nil
}
1 change: 1 addition & 0 deletions sdk/cdsclient/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ type UserClient interface {
UserGetMe() (*sdk.AuthentifiedUser, error)
UserGetGroups(username string) (map[string][]sdk.Group, error)
UpdateFavorite(params sdk.FavoriteParams) (interface{}, error)
UserGetSchema() (sdk.SchemaResponse, error)
}

// WorkerClient exposes workers functions
Expand Down
24 changes: 12 additions & 12 deletions sdk/exportentities/step.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,18 +328,18 @@ type Step struct {
AlwaysExecuted *bool `json:"always_executed,omitempty" yaml:"always_executed,omitempty"`
// step specific data, only one option should be set
StepCustom `json:"-" yaml:",inline"`
Script interface{} `json:"script,omitempty" yaml:"script,omitempty" jsonschema:"-" jsonschema_description:"Script.\nhttps://ovh.github.io/cds/docs/actions/builtin-script"`
Coverage *StepCoverage `json:"coverage,omitempty" yaml:"coverage,omitempty" jsonschema_description:"Parse coverage report.\nhttps://ovh.github.io/cds/docs/actions/builtin-coverage"`
ArtifactDownload *StepArtifactDownload `json:"artifactDownload,omitempty" yaml:"artifactDownload,omitempty" jsonschema_description:"Download artifacts in workspace.\nhttps://ovh.github.io/cds/docs/actions/builtin-artifact-download"`
ArtifactUpload *StepArtifactUpload `json:"artifactUpload,omitempty" yaml:"artifactUpload,omitempty" jsonschema_description:"Upload artifacts from workspace.\nhttps://ovh.github.io/cds/docs/actions/builtin-artifact-upload"`
ServeStaticFiles *StepServeStaticFiles `json:"serveStaticFiles,omitempty" yaml:"serveStaticFiles,omitempty" jsonschema_description:"Serve static files.\nhttps://ovh.github.io/cds/docs/actions/builtin-serve-static-files"`
GitClone *StepGitClone `json:"gitClone,omitempty" yaml:"gitClone,omitempty" jsonschema_description:"Clone a git repository.\nhttps://ovh.github.io/cds/docs/actions/builtin-gitclone"`
GitTag *StepGitTag `json:"gitTag,omitempty" yaml:"gitTag,omitempty" jsonschema_description:"Create a git tag.\nhttps://ovh.github.io/cds/docs/actions/builtin-gittag"`
Release *StepRelease `json:"release,omitempty" yaml:"release,omitempty" jsonschema_description:"Release an application.\nhttps://ovh.github.io/cds/docs/actions/builtin-release"`
JUnitReport *StepJUnitReport `json:"jUnitReport,omitempty" yaml:"jUnitReport,omitempty" jsonschema_description:"Parse JUnit report.\nhttps://ovh.github.io/cds/docs/actions/builtin-junit"`
Checkout *StepCheckout `json:"checkout,omitempty" yaml:"checkout,omitempty" jsonschema_description:"Checkout repository for an application.\nhttps://ovh.github.io/cds/docs/actions/builtin-checkoutapplication"`
InstallKey *StepInstallKey `json:"installKey,omitempty" yaml:"installKey,omitempty" jsonschema_description:"Install a key (GPG, SSH) in your current workspace.\nhttps://ovh.github.io/cds/docs/actions/builtin-installkey"`
Deploy *StepDeploy `json:"deploy,omitempty" yaml:"deploy,omitempty" jsonschema_description:"Deploy an application.\nhttps://ovh.github.io/cds/docs/actions/builtin-deployapplication"`
Script interface{} `json:"script,omitempty" yaml:"script,omitempty" jsonschema:"oneof_type=string;array,oneof_required=actionScript" jsonschema_description:"Script.\nhttps://ovh.github.io/cds/docs/actions/builtin-script"`
Coverage *StepCoverage `json:"coverage,omitempty" yaml:"coverage,omitempty" jsonschema:"oneof_required=actionCoverage" jsonschema_description:"Parse coverage report.\nhttps://ovh.github.io/cds/docs/actions/builtin-coverage"`
ArtifactDownload *StepArtifactDownload `json:"artifactDownload,omitempty" yaml:"artifactDownload,omitempty" jsonschema:"oneof_required=actionArtifactDownload" jsonschema_description:"Download artifacts in workspace.\nhttps://ovh.github.io/cds/docs/actions/builtin-artifact-download"`
ArtifactUpload *StepArtifactUpload `json:"artifactUpload,omitempty" yaml:"artifactUpload,omitempty" jsonschema:"oneof_required=actionArtifactUpload" jsonschema_description:"Upload artifacts from workspace.\nhttps://ovh.github.io/cds/docs/actions/builtin-artifact-upload"`
ServeStaticFiles *StepServeStaticFiles `json:"serveStaticFiles,omitempty" yaml:"serveStaticFiles,omitempty" jsonschema:"oneof_required=actionServeStaticFiles" jsonschema_description:"Serve static files.\nhttps://ovh.github.io/cds/docs/actions/builtin-serve-static-files"`
GitClone *StepGitClone `json:"gitClone,omitempty" yaml:"gitClone,omitempty" jsonschema:"oneof_required=actionGitClone" jsonschema_description:"Clone a git repository.\nhttps://ovh.github.io/cds/docs/actions/builtin-gitclone"`
GitTag *StepGitTag `json:"gitTag,omitempty" yaml:"gitTag,omitempty" jsonschema:"oneof_required=actionGitTag" jsonschema_description:"Create a git tag.\nhttps://ovh.github.io/cds/docs/actions/builtin-gittag"`
Release *StepRelease `json:"release,omitempty" yaml:"release,omitempty" jsonschema:"oneof_required=actionRelease" jsonschema_description:"Release an application.\nhttps://ovh.github.io/cds/docs/actions/builtin-release"`
JUnitReport *StepJUnitReport `json:"jUnitReport,omitempty" yaml:"jUnitReport,omitempty" jsonschema:"oneof_required=actionJUNit" jsonschema_description:"Parse JUnit report.\nhttps://ovh.github.io/cds/docs/actions/builtin-junit"`
Checkout *StepCheckout `json:"checkout,omitempty" yaml:"checkout,omitempty" jsonschema:"oneof_required=actionCheckout" jsonschema_description:"Checkout repository for an application.\nhttps://ovh.github.io/cds/docs/actions/builtin-checkoutapplication"`
InstallKey *StepInstallKey `json:"installKey,omitempty" yaml:"installKey,omitempty" jsonschema:"oneof_required=actionInstallKey" jsonschema_description:"Install a key (GPG, SSH) in your current workspace.\nhttps://ovh.github.io/cds/docs/actions/builtin-installkey"`
Deploy *StepDeploy `json:"deploy,omitempty" yaml:"deploy,omitempty" jsonschema:"oneof_required=actionDeploy" jsonschema_description:"Deploy an application.\nhttps://ovh.github.io/cds/docs/actions/builtin-deployapplication"`
}

// MarshalJSON custom marshal json impl to inline custom step.
Expand Down
6 changes: 0 additions & 6 deletions sdk/exportentities/workflow.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ type Workflow struct {
Workflow map[string]NodeEntry `json:"workflow,omitempty" yaml:"workflow,omitempty" jsonschema_description:"Workflow nodes list."`
Hooks map[string][]HookEntry `json:"hooks,omitempty" yaml:"hooks,omitempty" jsonschema_description:"Workflow hooks list."`
// this will be filled for simple workflows
DependsOn []string `json:"depends_on,omitempty" yaml:"depends_on,omitempty" jsonschema_description:"Names of the parent nodes, can be pipelines, forks or joins."`
OneAtATime *bool `json:"one_at_a_time,omitempty" yaml:"one_at_a_time,omitempty" jsonschema_description:"Set to true if you want to limit the execution of this node to one at a time."`
Conditions *sdk.WorkflowNodeConditions `json:"conditions,omitempty" yaml:"conditions,omitempty" jsonschema_description:"Conditions to run this node.\nhttps://ovh.github.io/cds/docs/concepts/workflow/run-conditions."`
When []string `json:"when,omitempty" yaml:"when,omitempty" jsonschema_description:"Set manual and status condition (ex: 'success')."` //This is used only for manual and success condition
Expand Down Expand Up @@ -319,7 +318,6 @@ func NewWorkflow(ctx context.Context, w sdk.Workflow, opts ...WorkflowOptions) (
exportedWorkflow.PipelineName = entry.PipelineName
exportedWorkflow.EnvironmentName = entry.EnvironmentName
exportedWorkflow.ProjectIntegrationName = entry.ProjectIntegrationName
exportedWorkflow.DependsOn = entry.DependsOn
exportedWorkflow.OneAtATime = entry.OneAtATime
if entry.Conditions != nil && (len(entry.Conditions.PlainConditions) > 0 || entry.Conditions.LuaScript != "") {
exportedWorkflow.When = entry.When
Expand Down Expand Up @@ -418,7 +416,6 @@ func (w Workflow) Entries() map[string]NodeEntry {
ProjectIntegrationName: w.ProjectIntegrationName,
PipelineName: w.PipelineName,
Conditions: w.Conditions,
DependsOn: w.DependsOn,
When: w.When,
Payload: w.Payload,
Parameters: w.Parameters,
Expand Down Expand Up @@ -451,9 +448,6 @@ func (w Workflow) CheckValidity() error {
if len(w.When) != 0 {
mError.Append(fmt.Errorf("Error: wrong usage: when not allowed here"))
}
if len(w.DependsOn) != 0 {
mError.Append(fmt.Errorf("Error: wrong usage: depends_on not allowed here"))
}
if len(w.PipelineHooks) != 0 {
mError.Append(fmt.Errorf("Error: wrong usage: pipeline_hooks not allowed here"))
}
Expand Down
Loading