grim/convey
Clone
Summary
Browse
Changes
Graph
ChangeLog the fixes from pr #25. Fixes #125, #126
2017-10-03, Gary Kramlich
674d936a6785
ChangeLog the fixes from pr #25. Fixes #125, #126
/*
* Convey
* Copyright 2016-2017 Gary Kramlich <grim@reaperworld.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package
stages
import
(
"fmt"
"strings"
"sync"
"github.com/aphistic/gomol"
"bitbucket.org/rw_grim/convey/environment"
"bitbucket.org/rw_grim/convey/logging"
"bitbucket.org/rw_grim/convey/state"
"bitbucket.org/rw_grim/convey/tasks"
"bitbucket.org/rw_grim/convey/yaml"
)
type
Stage
struct
{
Name
string
`yaml:"name"`
Enabled
bool
`yaml:"enabled"`
Always
bool
`yaml:"always"`
Run
string
`yaml:"run"`
Concurrent
bool
`yaml:"concurrent"`
Environment
yaml
.
StringOrSlice
`yaml:"environment"`
Tasks
yaml
.
StringOrSlice
`yaml:"tasks"`
}
func
(
s
*
Stage
)
UnmarshalYAML
(
unmarshal
func
(
interface
{})
error
)
error
{
type
rawStage
Stage
raw
:=
rawStage
{
Enabled
:
true
}
if
err
:=
unmarshal
(
&
raw
);
err
!=
nil
{
return
err
}
*
s
=
Stage
(
raw
)
// validate the run attribute
if
s
.
Run
==
""
{
// If the always attribute is set, convert it to run syntax
if
s
.
Always
{
s
.
Run
=
"always"
}
else
{
s
.
Run
=
"on-success"
}
}
else
{
s
.
Run
=
strings
.
ToLower
(
s
.
Run
)
}
// now validate the run attribute
switch
s
.
Run
{
case
"on-success"
:
case
"on-failure"
:
case
"always"
:
default
:
return
fmt
.
Errorf
(
"Invalid value '%s' for run attribute"
,
s
.
Run
)
}
// All good, return success
return
nil
}
func
(
s
*
Stage
)
Execute
(
path
string
,
logger
*
gomol
.
LogAdapter
,
taskMap
map
[
string
]
tasks
.
Task
,
env
[]
string
,
st
*
state
.
State
)
error
{
stageEnv
:=
environment
.
Merge
(
env
,
s
.
Environment
)
if
s
.
Concurrent
&&
!
st
.
ForceSequential
{
taskRes
:=
make
(
chan
error
)
stageRes
:=
make
(
chan
error
)
wg
:=
sync
.
WaitGroup
{}
// process all of the task results
go
func
(
taskRes
,
stageRes
chan
error
)
{
var
stageErr
error
for
err
:=
range
taskRes
{
if
err
!=
nil
&&
stageErr
==
nil
{
stageErr
=
err
}
}
stageRes
<-
stageErr
// now close the stageRes channel
close
(
stageRes
)
}(
taskRes
,
stageRes
)
// run all of the tasks in go routines
for
_
,
taskName
:=
range
s
.
Tasks
{
wg
.
Add
(
1
)
go
func
(
path
,
name
string
,
res
chan
error
)
{
defer
wg
.
Done
()
res
<-
s
.
runTask
(
path
,
name
,
stageEnv
,
taskMap
,
st
)
}(
path
,
taskName
,
taskRes
)
}
// block until the task wait group is done, then close the taskRes channel
wg
.
Wait
()
close
(
taskRes
)
// now return the result from the stageRes channel
return
<-
stageRes
}
else
{
// serial execution
for
_
,
taskName
:=
range
s
.
Tasks
{
err
:=
s
.
runTask
(
path
,
taskName
,
stageEnv
,
taskMap
,
st
)
if
err
!=
nil
{
return
err
}
}
}
return
nil
}
func
(
s
*
Stage
)
runTask
(
path
,
name
string
,
stageEnv
[]
string
,
taskMap
map
[
string
]
tasks
.
Task
,
st
*
state
.
State
)
error
{
absTaskName
:=
fmt
.
Sprintf
(
"%s/%s"
,
path
,
name
)
taskLogger
:=
logging
.
NewAdapter
(
fmt
.
Sprintf
(
"%s/%s"
,
path
,
name
))
taskLogger
.
Info
(
"starting"
)
task
,
found
:=
taskMap
[
name
]
if
!
found
{
taskLogger
.
Fatal
(
"failed, task not found"
)
return
fmt
.
Errorf
(
"task %s not found"
,
absTaskName
)
}
err
:=
task
.
Execute
(
absTaskName
,
taskLogger
,
stageEnv
,
st
)
if
err
!=
nil
{
taskLogger
.
Fatalf
(
"failed, %s"
,
err
)
return
err
}
taskLogger
.
Info
(
"finished"
)
return
nil
}
// ShouldRun will return True if a stage should be run based on the passed in
// error (from the plan) and whether or not the stage is enabled.
func
(
s
*
Stage
)
ShouldRun
(
err
error
)
bool
{
if
s
.
Enabled
==
false
{
return
false
}
if
s
.
Run
==
"always"
{
return
true
}
if
err
!=
nil
{
return
s
.
Run
==
"on-failure"
}
return
s
.
Run
==
"on-success"
}