runservice types: refactor unmarshal
* Don't use a complex UnmarshalJSON for RunConfigTask and ExecutorTask but introduce a Steps type as a slice of Step (where Step is an empty interface) and declare an UnmarshalJSON method on the Step type.
This commit is contained in:
parent
96c0fa9aea
commit
863277af2d
|
@ -196,7 +196,7 @@ func GenRunConfigTasks(uuid util.UUIDGenerator, c *config.Config, runName string
|
||||||
for _, ct := range cr.Tasks {
|
for _, ct := range cr.Tasks {
|
||||||
include := types.MatchWhen(whenFromConfigWhen(ct.When), branch, tag, ref)
|
include := types.MatchWhen(whenFromConfigWhen(ct.When), branch, tag, ref)
|
||||||
|
|
||||||
steps := make([]interface{}, len(ct.Steps))
|
steps := make(rstypes.Steps, len(ct.Steps))
|
||||||
for i, cpts := range ct.Steps {
|
for i, cpts := range ct.Steps {
|
||||||
steps[i] = stepFromConfigStep(cpts, variables)
|
steps[i] = stepFromConfigStep(cpts, variables)
|
||||||
}
|
}
|
||||||
|
|
|
@ -748,10 +748,10 @@ func TestGenRunConfig(t *testing.T) {
|
||||||
"ENV01": "ENV01",
|
"ENV01": "ENV01",
|
||||||
"ENVFROMVARIABLE01": "VARVALUE01",
|
"ENVFROMVARIABLE01": "VARVALUE01",
|
||||||
},
|
},
|
||||||
Steps: []interface{}{
|
Steps: rstypes.Steps{
|
||||||
&rstypes.RunStep{Step: rstypes.Step{Type: "run", Name: "command01"}, Command: "command01", Environment: map[string]string{}},
|
&rstypes.RunStep{BaseStep: rstypes.BaseStep{Type: "run", Name: "command01"}, Command: "command01", Environment: map[string]string{}},
|
||||||
&rstypes.RunStep{Step: rstypes.Step{Type: "run", Name: "name different than command"}, Command: "command02", Environment: map[string]string{}},
|
&rstypes.RunStep{BaseStep: rstypes.BaseStep{Type: "run", Name: "name different than command"}, Command: "command02", Environment: map[string]string{}},
|
||||||
&rstypes.RunStep{Step: rstypes.Step{Type: "run", Name: "command03"}, Command: "command03", Environment: map[string]string{"ENV01": "ENV01", "ENVFROMVARIABLE01": "VARVALUE01"}},
|
&rstypes.RunStep{BaseStep: rstypes.BaseStep{Type: "run", Name: "command03"}, Command: "command03", Environment: map[string]string{"ENV01": "ENV01", "ENVFROMVARIABLE01": "VARVALUE01"}},
|
||||||
},
|
},
|
||||||
Skip: true,
|
Skip: true,
|
||||||
},
|
},
|
||||||
|
@ -820,8 +820,8 @@ func TestGenRunConfig(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{
|
Steps: rstypes.Steps{
|
||||||
&rstypes.RunStep{Step: rstypes.Step{Type: "run", Name: "command01"}, Command: "command01", Environment: map[string]string{}},
|
&rstypes.RunStep{BaseStep: rstypes.BaseStep{Type: "run", Name: "command01"}, Command: "command01", Environment: map[string]string{}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -917,8 +917,8 @@ func TestGenRunConfig(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{
|
Steps: rstypes.Steps{
|
||||||
&rstypes.RunStep{Step: rstypes.Step{Type: "run", Name: "command01"}, Command: "command01", Environment: map[string]string{}},
|
&rstypes.RunStep{BaseStep: rstypes.BaseStep{Type: "run", Name: "command01"}, Command: "command01", Environment: map[string]string{}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -46,7 +46,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
inuuid("task02"): &types.RunConfigTask{
|
inuuid("task02"): &types.RunConfigTask{
|
||||||
|
@ -59,7 +59,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
inuuid("task03"): &types.RunConfigTask{
|
inuuid("task03"): &types.RunConfigTask{
|
||||||
|
@ -70,7 +70,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
inuuid("task04"): &types.RunConfigTask{
|
inuuid("task04"): &types.RunConfigTask{
|
||||||
|
@ -80,7 +80,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
inuuid("task05"): &types.RunConfigTask{
|
inuuid("task05"): &types.RunConfigTask{
|
||||||
|
@ -94,7 +94,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -111,7 +111,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
outuuid("task02"): &types.RunConfigTask{
|
outuuid("task02"): &types.RunConfigTask{
|
||||||
|
@ -124,7 +124,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
outuuid("task03"): &types.RunConfigTask{
|
outuuid("task03"): &types.RunConfigTask{
|
||||||
|
@ -135,7 +135,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
outuuid("task04"): &types.RunConfigTask{
|
outuuid("task04"): &types.RunConfigTask{
|
||||||
|
@ -145,7 +145,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
outuuid("task05"): &types.RunConfigTask{
|
outuuid("task05"): &types.RunConfigTask{
|
||||||
|
@ -159,7 +159,7 @@ func TestRecreateRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,7 +35,7 @@ func TestAdvanceRunTasks(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
"task02": &types.RunConfigTask{
|
"task02": &types.RunConfigTask{
|
||||||
|
@ -48,7 +48,7 @@ func TestAdvanceRunTasks(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
"task03": &types.RunConfigTask{
|
"task03": &types.RunConfigTask{
|
||||||
|
@ -59,7 +59,7 @@ func TestAdvanceRunTasks(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
"task04": &types.RunConfigTask{
|
"task04": &types.RunConfigTask{
|
||||||
|
@ -69,7 +69,7 @@ func TestAdvanceRunTasks(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
"task05": &types.RunConfigTask{
|
"task05": &types.RunConfigTask{
|
||||||
|
@ -83,7 +83,7 @@ func TestAdvanceRunTasks(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -383,7 +383,7 @@ func TestGetTasksToRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
"task02": &types.RunConfigTask{
|
"task02": &types.RunConfigTask{
|
||||||
|
@ -396,7 +396,7 @@ func TestGetTasksToRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
"task03": &types.RunConfigTask{
|
"task03": &types.RunConfigTask{
|
||||||
|
@ -407,7 +407,7 @@ func TestGetTasksToRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
"task04": &types.RunConfigTask{
|
"task04": &types.RunConfigTask{
|
||||||
|
@ -417,7 +417,7 @@ func TestGetTasksToRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
"task05": &types.RunConfigTask{
|
"task05": &types.RunConfigTask{
|
||||||
|
@ -431,7 +431,7 @@ func TestGetTasksToRun(t *testing.T) {
|
||||||
Containers: []*types.Container{{Image: "image01"}},
|
Containers: []*types.Container{{Image: "image01"}},
|
||||||
},
|
},
|
||||||
Environment: map[string]string{},
|
Environment: map[string]string{},
|
||||||
Steps: []interface{}{},
|
Steps: types.Steps{},
|
||||||
Skip: false,
|
Skip: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -326,7 +326,7 @@ type RunConfigTask struct {
|
||||||
WorkingDir string `json:"working_dir,omitempty"`
|
WorkingDir string `json:"working_dir,omitempty"`
|
||||||
Shell string `json:"shell,omitempty"`
|
Shell string `json:"shell,omitempty"`
|
||||||
User string `json:"user,omitempty"`
|
User string `json:"user,omitempty"`
|
||||||
Steps []interface{} `json:"steps,omitempty"`
|
Steps Steps `json:"steps,omitempty"`
|
||||||
IgnoreFailure bool `json:"ignore_failure,omitempty"`
|
IgnoreFailure bool `json:"ignore_failure,omitempty"`
|
||||||
NeedsApproval bool `json:"needs_approval,omitempty"`
|
NeedsApproval bool `json:"needs_approval,omitempty"`
|
||||||
Skip bool `json:"skip,omitempty"`
|
Skip bool `json:"skip,omitempty"`
|
||||||
|
@ -378,75 +378,17 @@ type Runtime struct {
|
||||||
Containers []*Container `json:"containers,omitempty"`
|
Containers []*Container `json:"containers,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (rct *RunConfigTask) UnmarshalJSON(b []byte) error {
|
type Step interface{}
|
||||||
type rctask RunConfigTask
|
|
||||||
|
|
||||||
type task struct {
|
type Steps []Step
|
||||||
Steps []json.RawMessage `json:"steps,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
rctt := (*rctask)(rct)
|
type BaseStep struct {
|
||||||
if err := json.Unmarshal(b, &rctt); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var st task
|
|
||||||
if err := json.Unmarshal(b, &st); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
steps := make([]interface{}, len(st.Steps))
|
|
||||||
for i, step := range st.Steps {
|
|
||||||
var bs Step
|
|
||||||
if err := json.Unmarshal(step, &bs); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
switch bs.Type {
|
|
||||||
case "run":
|
|
||||||
var s RunStep
|
|
||||||
if err := json.Unmarshal(step, &s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
steps[i] = &s
|
|
||||||
case "save_to_workspace":
|
|
||||||
var s SaveToWorkspaceStep
|
|
||||||
if err := json.Unmarshal(step, &s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
steps[i] = &s
|
|
||||||
case "restore_workspace":
|
|
||||||
var s RestoreWorkspaceStep
|
|
||||||
if err := json.Unmarshal(step, &s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
steps[i] = &s
|
|
||||||
case "save_cache":
|
|
||||||
var s SaveCacheStep
|
|
||||||
if err := json.Unmarshal(step, &s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
steps[i] = &s
|
|
||||||
case "restore_cache":
|
|
||||||
var s RestoreCacheStep
|
|
||||||
if err := json.Unmarshal(step, &s); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
steps[i] = &s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
rct.Steps = steps
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type Step struct {
|
|
||||||
Type string `json:"type,omitempty"`
|
Type string `json:"type,omitempty"`
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RunStep struct {
|
type RunStep struct {
|
||||||
Step
|
BaseStep
|
||||||
Command string `json:"command,omitempty"`
|
Command string `json:"command,omitempty"`
|
||||||
Environment map[string]string `json:"environment,omitempty"`
|
Environment map[string]string `json:"environment,omitempty"`
|
||||||
WorkingDir string `json:"working_dir,omitempty"`
|
WorkingDir string `json:"working_dir,omitempty"`
|
||||||
|
@ -461,23 +403,23 @@ type SaveContent struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type SaveToWorkspaceStep struct {
|
type SaveToWorkspaceStep struct {
|
||||||
Step
|
BaseStep
|
||||||
Contents []SaveContent `json:"contents,omitempty"`
|
Contents []SaveContent `json:"contents,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RestoreWorkspaceStep struct {
|
type RestoreWorkspaceStep struct {
|
||||||
Step
|
BaseStep
|
||||||
DestDir string `json:"dest_dir,omitempty"`
|
DestDir string `json:"dest_dir,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type SaveCacheStep struct {
|
type SaveCacheStep struct {
|
||||||
Step
|
BaseStep
|
||||||
Key string `json:"key,omitempty"`
|
Key string `json:"key,omitempty"`
|
||||||
Contents []SaveContent `json:"contents,omitempty"`
|
Contents []SaveContent `json:"contents,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type RestoreCacheStep struct {
|
type RestoreCacheStep struct {
|
||||||
Step
|
BaseStep
|
||||||
Keys []string `json:"keys,omitempty"`
|
Keys []string `json:"keys,omitempty"`
|
||||||
DestDir string `json:"dest_dir,omitempty"`
|
DestDir string `json:"dest_dir,omitempty"`
|
||||||
}
|
}
|
||||||
|
@ -512,7 +454,7 @@ type ExecutorTask struct {
|
||||||
|
|
||||||
DockerRegistriesAuth map[string]DockerRegistryAuth `json:"docker_registries_auth"`
|
DockerRegistriesAuth map[string]DockerRegistryAuth `json:"docker_registries_auth"`
|
||||||
|
|
||||||
Steps []interface{} `json:"steps,omitempty"`
|
Steps Steps `json:"steps,omitempty"`
|
||||||
|
|
||||||
Status ExecutorTaskStatus `json:"status,omitempty"`
|
Status ExecutorTaskStatus `json:"status,omitempty"`
|
||||||
SetupError string `fail_reason:"setup_error,omitempty"`
|
SetupError string `fail_reason:"setup_error,omitempty"`
|
||||||
|
@ -562,26 +504,17 @@ type WorkspaceOperation struct {
|
||||||
Overwrite bool `json:"overwrite,omitempty"`
|
Overwrite bool `json:"overwrite,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (et *ExecutorTask) UnmarshalJSON(b []byte) error {
|
func (et *Steps) UnmarshalJSON(b []byte) error {
|
||||||
type etask ExecutorTask
|
type rawSteps []json.RawMessage
|
||||||
|
|
||||||
type task struct {
|
var rs rawSteps
|
||||||
Steps []json.RawMessage `json:"steps,omitempty"`
|
if err := json.Unmarshal(b, &rs); err != nil {
|
||||||
}
|
|
||||||
|
|
||||||
ett := (*etask)(et)
|
|
||||||
if err := json.Unmarshal(b, &ett); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var st task
|
steps := make(Steps, len(rs))
|
||||||
if err := json.Unmarshal(b, &st); err != nil {
|
for i, step := range rs {
|
||||||
return err
|
var bs BaseStep
|
||||||
}
|
|
||||||
|
|
||||||
steps := make([]interface{}, len(ett.Steps))
|
|
||||||
for i, step := range st.Steps {
|
|
||||||
var bs Step
|
|
||||||
if err := json.Unmarshal(step, &bs); err != nil {
|
if err := json.Unmarshal(step, &bs); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -619,7 +552,7 @@ func (et *ExecutorTask) UnmarshalJSON(b []byte) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
et.Steps = steps
|
*et = steps
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue