2021-12-09 15:34:37 +00:00
|
|
|
local droneStatus = ['success', 'failure'];
|
|
|
|
|
2021-12-10 04:03:53 +00:00
|
|
|
local ci = {
|
|
|
|
pipeline:: {
|
|
|
|
new()::
|
|
|
|
self.withKind("pipeline"),
|
|
|
|
|
|
|
|
withName(name)::
|
|
|
|
self + { name: name },
|
|
|
|
|
|
|
|
withKind(kind)::
|
|
|
|
self + { kind: kind },
|
|
|
|
|
|
|
|
withType(type)::
|
|
|
|
self + { type: type },
|
|
|
|
|
|
|
|
withNode(node)::
|
|
|
|
self + { node: node },
|
|
|
|
|
|
|
|
withTrigger(trigger)::
|
|
|
|
self + { trigger: trigger },
|
|
|
|
|
|
|
|
withDependsOn(n)::
|
|
|
|
self + { depends_on: n },
|
|
|
|
|
|
|
|
withNodeSelector(ns)::
|
|
|
|
self + { node_selector: ns },
|
|
|
|
|
|
|
|
withSteps(steps)::
|
|
|
|
self + if std.type(steps) == 'array'
|
|
|
|
then { steps: steps }
|
|
|
|
else { steps: [steps] },
|
|
|
|
|
|
|
|
step:: {
|
|
|
|
new(name='', image='')::
|
|
|
|
self.withName(name).withImage(image).withPullIfNotExists(),
|
|
|
|
|
|
|
|
withName(name)::
|
|
|
|
self + { name: name },
|
|
|
|
|
|
|
|
withImage(image)::
|
|
|
|
self + if image != '' then { image: image } else {},
|
|
|
|
|
|
|
|
withAlwaysPull()::
|
|
|
|
self + { pull: 'always' },
|
|
|
|
|
|
|
|
withPullIfNotExists()::
|
|
|
|
self + { pull: 'if-not-exists' },
|
|
|
|
|
|
|
|
withCommands(commands)::
|
|
|
|
self + if std.type(commands) == 'array'
|
|
|
|
then { commands: commands }
|
|
|
|
else { commands: [commands] },
|
|
|
|
|
|
|
|
withTrigger(trigger)::
|
|
|
|
self + { trigger: trigger }, // TODO: this is duplicated in pipeline object
|
|
|
|
|
|
|
|
withEnv(envs)::
|
|
|
|
self + { environment+: envs },
|
|
|
|
|
|
|
|
withRuntimeEnvVar(envs)::
|
|
|
|
local existingCmds = if std.objectHas(self, "commands") then self.commands else [];
|
|
|
|
self + {
|
|
|
|
commands: std.map(function (i) std.format('export %s="%s"', [i, envs[i]]),
|
|
|
|
std.objectFields(envs)) + existingCmds
|
|
|
|
},
|
|
|
|
|
|
|
|
withWhen(when)::
|
|
|
|
self + { when: when },
|
|
|
|
|
|
|
|
withSettings(settings)::
|
|
|
|
self + { settings: settings },
|
|
|
|
},
|
|
|
|
|
|
|
|
when:: {
|
|
|
|
new()::
|
|
|
|
self + {},
|
|
|
|
|
|
|
|
withBranch(branch)::
|
|
|
|
self + if std.type(branch) == 'array'
|
|
|
|
then { branch: branch }
|
|
|
|
else { branch: [branch] },
|
|
|
|
|
|
|
|
withEvent(e)::
|
|
|
|
self + if std.type(e) == 'array'
|
|
|
|
then { event: e }
|
|
|
|
else { event: [e] },
|
|
|
|
|
|
|
|
withStatus(s)::
|
|
|
|
self + if std.type(s) == 'array'
|
|
|
|
then { status: s }
|
|
|
|
else { status: [s] },
|
|
|
|
|
|
|
|
withStatusAll()::
|
|
|
|
self.withStatus(droneStatus),
|
|
|
|
},
|
2021-12-09 15:34:37 +00:00
|
|
|
},
|
2021-12-10 04:03:53 +00:00
|
|
|
|
|
|
|
trigger:: {
|
|
|
|
new()::
|
|
|
|
self + {},
|
|
|
|
|
|
|
|
withBranch(branch)::
|
|
|
|
self + if std.type(branch) == 'array'
|
|
|
|
then { branch: branch }
|
|
|
|
else { branch: [branch] },
|
|
|
|
|
|
|
|
withEvent(e)::
|
|
|
|
self + if std.type(e) == 'array'
|
|
|
|
then { event: e }
|
|
|
|
else { event: [e] },
|
|
|
|
|
|
|
|
withStatus(s)::
|
|
|
|
self + if std.type(s) == 'array'
|
|
|
|
then { status: s }
|
|
|
|
else { status: [s] },
|
|
|
|
|
|
|
|
withStatusAll()::
|
|
|
|
self.withStatus(droneStatus),
|
2021-12-09 15:34:37 +00:00
|
|
|
},
|
|
|
|
|
2021-12-10 04:03:53 +00:00
|
|
|
env_from_secret(dict):: {
|
|
|
|
[key]: {
|
|
|
|
from_secret: dict[key],
|
|
|
|
}
|
|
|
|
for key in std.objectFields(dict)
|
|
|
|
},
|
2021-12-09 15:34:37 +00:00
|
|
|
|
2021-12-10 04:03:53 +00:00
|
|
|
promoteStep(env,
|
|
|
|
secret_name_drone_token="drone_token",
|
|
|
|
image="docker.nexus.home.rekahsoft.ca/drone/cli:1.4-alpine")::
|
|
|
|
local dronePromoteCmd(env) = [
|
|
|
|
"export DRONE_SERVER=\"${DRONE_SYSTEM_PROTO}://${DRONE_SYSTEM_HOST}\"",
|
|
|
|
"export DRONE_TOKEN",
|
|
|
|
std.format('DRONE_PROMOTED_PIPELINE_ID=$(drone build promote --format \'{{ .Number }}\' "$DRONE_REPO" "$DRONE_BUILD_NUMBER" "%s")', env),
|
|
|
|
'while status="$(drone build info --format \'{{ .Status }}\' $DRONE_REPO $DRONE_PROMOTED_PIPELINE_ID)"; do
|
|
|
|
case "$status" in
|
|
|
|
pending|running)
|
|
|
|
sleep 30s
|
|
|
|
;;
|
|
|
|
success)
|
|
|
|
break
|
|
|
|
;;
|
|
|
|
failure|error|killed)
|
|
|
|
echo "Promoted job with id $DRONE_PROMOTED_PIPELINE_ID failed with status \'$status\'."
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
echo "Unknown pipeline status \'$status\'."
|
|
|
|
exit 1
|
|
|
|
esac
|
|
|
|
done',
|
|
|
|
];
|
2021-12-09 15:34:37 +00:00
|
|
|
|
2021-12-10 04:03:53 +00:00
|
|
|
ci.pipeline.step.new(std.format("promote-%s", env), image)
|
|
|
|
.withWhen(ci.pipeline.when.new()
|
|
|
|
.withBranch("master")
|
|
|
|
.withEvent("push"))
|
|
|
|
.withCommands(dronePromoteCmd(env))
|
|
|
|
.withEnv(ci.env_from_secret({
|
|
|
|
DRONE_TOKEN: "drone_token"
|
|
|
|
}))
|
2021-12-09 15:34:37 +00:00
|
|
|
};
|
|
|
|
|
2021-12-10 04:03:53 +00:00
|
|
|
local guix_pipeline(name) = ci.pipeline.new()
|
2021-12-09 15:34:37 +00:00
|
|
|
.withName(name)
|
|
|
|
.withType("docker")
|
|
|
|
.withNode({ "guix": "on"});
|
|
|
|
|
|
|
|
local guix_step(name,
|
|
|
|
commands,
|
|
|
|
image="docker.nexus.home.rekahsoft.ca/guix:latest") =
|
2021-12-10 04:03:53 +00:00
|
|
|
ci.pipeline.step.new(name, image).withPullIfNotExists().withCommands(commands);
|
2021-12-09 15:34:37 +00:00
|
|
|
|
|
|
|
local guix_step_time_machine(name,
|
|
|
|
commands,
|
|
|
|
cwd=".",
|
|
|
|
channels="channels.scm",
|
|
|
|
image="docker.nexus.home.rekahsoft.ca/guix:latest") =
|
2021-12-10 04:03:53 +00:00
|
|
|
ci.pipeline.step.new(name, image).withPullIfNotExists().withCommands(
|
2021-12-09 16:59:51 +00:00
|
|
|
// Conditionally change directory
|
2021-12-09 15:34:37 +00:00
|
|
|
(if cwd == "."
|
|
|
|
then [] else [std.format("cd %s", cwd)]) +
|
2021-12-09 16:59:51 +00:00
|
|
|
// Expand provide guix commands into executable shell
|
2021-12-09 15:34:37 +00:00
|
|
|
std.map(function(i) std.format("guix time-machine -C %s -- %s", [channels, i]),
|
|
|
|
if std.type(commands) == 'array' then commands else [commands]));
|
|
|
|
|
|
|
|
local deployStep(name, target=name, args=[]) = guix_step_time_machine(
|
|
|
|
name,
|
2021-12-09 17:16:24 +00:00
|
|
|
std.format('shell -m manifest.scm -- make %s ENV="${DRONE_DEPLOY_TO}" %s', [target, std.join(" ", args)]),
|
2021-12-09 15:34:37 +00:00
|
|
|
cwd="infra",
|
|
|
|
channels="../channels.scm")
|
2021-12-10 04:03:53 +00:00
|
|
|
.withEnv({ PLAN: "out.plan" } + ci.env_from_secret({
|
2021-12-09 15:34:37 +00:00
|
|
|
AWS_ACCESS_KEY_ID: "aws_access_key_id",
|
|
|
|
AWS_SECRET_ACCESS_KEY: "aws_secret_access_key",
|
|
|
|
}));
|
|
|
|
|
|
|
|
[
|
2021-12-10 04:03:53 +00:00
|
|
|
guix_pipeline("validate").withTrigger(ci.trigger.new().withEvent(["push", "pull_request", "tag"])).withSteps([
|
2021-12-09 15:34:37 +00:00
|
|
|
guix_step_time_machine("build", "build -f guix.scm"),
|
2021-12-10 04:03:53 +00:00
|
|
|
ci.promoteStep("staging"),
|
|
|
|
ci.promoteStep("production"),
|
2021-12-09 15:34:37 +00:00
|
|
|
]),
|
|
|
|
|
2021-12-10 04:03:53 +00:00
|
|
|
guix_pipeline("deploy").withTrigger(ci.trigger.new().withEvent("promote")).withSteps([
|
2021-12-09 15:34:37 +00:00
|
|
|
deployStep("init", "setup"),
|
2021-12-09 23:12:57 +00:00
|
|
|
deployStep("plan").withRuntimeEnvVar({
|
|
|
|
TF_VAR_site_static_files_dir: "$(guix time-machine -C channels.scm -- build -f guix.scm | grep -e '^.*-site$')"
|
|
|
|
}),
|
2021-12-09 15:34:37 +00:00
|
|
|
deployStep("deploy"),
|
|
|
|
])
|
|
|
|
]
|