mirror of
https://github.com/NixOS/nixpkgs.git
synced 2025-06-11 20:25:32 +03:00

After final improvements to the official formatter implementation, this commit now performs the first treewide reformat of Nix files using it. This is part of the implementation of RFC 166. Only "inactive" files are reformatted, meaning only files that aren't being touched by any PR with activity in the past 2 months. This is to avoid conflicts for PRs that might soon be merged. Later we can do a full treewide reformat to get the rest, which should not cause as many conflicts. A CI check has already been running for some time to ensure that new and already-formatted files are formatted, so the files being reformatted here should also stay formatted. This commit was automatically created and can be verified using nix-builda08b3a4d19
.tar.gz \ --argstr baseRevb32a094368
result/bin/apply-formatting $NIXPKGS_PATH
260 lines
9.1 KiB
Nix
260 lines
9.1 KiB
Nix
{
|
|
config,
|
|
lib,
|
|
pkgs,
|
|
...
|
|
}:
|
|
let
|
|
jenkinsCfg = config.services.jenkins;
|
|
cfg = config.services.jenkins.jobBuilder;
|
|
|
|
in
|
|
{
|
|
options = {
|
|
services.jenkins.jobBuilder = {
|
|
enable = lib.mkEnableOption ''
|
|
the Jenkins Job Builder (JJB) service. It
|
|
allows defining jobs for Jenkins in a declarative manner.
|
|
|
|
Jobs managed through the Jenkins WebUI (or by other means) are left
|
|
unchanged.
|
|
|
|
Note that it really is declarative configuration; if you remove a
|
|
previously defined job, the corresponding job directory will be
|
|
deleted.
|
|
|
|
Please see the Jenkins Job Builder documentation for more info:
|
|
<https://jenkins-job-builder.readthedocs.io/>
|
|
'';
|
|
|
|
accessUser = lib.mkOption {
|
|
default = "admin";
|
|
type = lib.types.str;
|
|
description = ''
|
|
User id in Jenkins used to reload config.
|
|
'';
|
|
};
|
|
|
|
accessToken = lib.mkOption {
|
|
default = "";
|
|
type = lib.types.str;
|
|
description = ''
|
|
User token in Jenkins used to reload config.
|
|
WARNING: This token will be world readable in the Nix store. To keep
|
|
it secret, use the {option}`accessTokenFile` option instead.
|
|
'';
|
|
};
|
|
|
|
accessTokenFile = lib.mkOption {
|
|
default = "${config.services.jenkins.home}/secrets/initialAdminPassword";
|
|
defaultText = lib.literalExpression ''"''${config.services.jenkins.home}/secrets/initialAdminPassword"'';
|
|
type = lib.types.str;
|
|
example = "/run/keys/jenkins-job-builder-access-token";
|
|
description = ''
|
|
File containing the API token for the {option}`accessUser`
|
|
user.
|
|
'';
|
|
};
|
|
|
|
yamlJobs = lib.mkOption {
|
|
default = "";
|
|
type = lib.types.lines;
|
|
example = ''
|
|
- job:
|
|
name: jenkins-job-test-1
|
|
builders:
|
|
- shell: echo 'Hello world!'
|
|
'';
|
|
description = ''
|
|
Job descriptions for Jenkins Job Builder in YAML format.
|
|
'';
|
|
};
|
|
|
|
jsonJobs = lib.mkOption {
|
|
default = [ ];
|
|
type = lib.types.listOf lib.types.str;
|
|
example = lib.literalExpression ''
|
|
[
|
|
'''
|
|
[ { "job":
|
|
{ "name": "jenkins-job-test-2",
|
|
"builders": [ "shell": "echo 'Hello world!'" ]
|
|
}
|
|
}
|
|
]
|
|
'''
|
|
]
|
|
'';
|
|
description = ''
|
|
Job descriptions for Jenkins Job Builder in JSON format.
|
|
'';
|
|
};
|
|
|
|
nixJobs = lib.mkOption {
|
|
default = [ ];
|
|
type = lib.types.listOf lib.types.attrs;
|
|
example = lib.literalExpression ''
|
|
[ { job =
|
|
{ name = "jenkins-job-test-3";
|
|
builders = [
|
|
{ shell = "echo 'Hello world!'"; }
|
|
];
|
|
};
|
|
}
|
|
]
|
|
'';
|
|
description = ''
|
|
Job descriptions for Jenkins Job Builder in Nix format.
|
|
|
|
This is a trivial wrapper around jsonJobs, using builtins.toJSON
|
|
behind the scene.
|
|
'';
|
|
};
|
|
};
|
|
};
|
|
|
|
config = lib.mkIf (jenkinsCfg.enable && cfg.enable) {
|
|
assertions = [
|
|
{
|
|
assertion =
|
|
if cfg.accessUser != "" then
|
|
(cfg.accessToken != "" && cfg.accessTokenFile == "")
|
|
|| (cfg.accessToken == "" && cfg.accessTokenFile != "")
|
|
else
|
|
true;
|
|
message = ''
|
|
One of accessToken and accessTokenFile options must be non-empty
|
|
strings, but not both. Current values:
|
|
services.jenkins.jobBuilder.accessToken = "${cfg.accessToken}"
|
|
services.jenkins.jobBuilder.accessTokenFile = "${cfg.accessTokenFile}"
|
|
'';
|
|
}
|
|
];
|
|
|
|
systemd.services.jenkins-job-builder = {
|
|
description = "Jenkins Job Builder Service";
|
|
# JJB can run either before or after jenkins. We chose after, so we can
|
|
# always use curl to notify (running) jenkins to reload its config.
|
|
after = [ "jenkins.service" ];
|
|
wantedBy = [ "multi-user.target" ];
|
|
|
|
path = with pkgs; [
|
|
jenkins-job-builder
|
|
curl
|
|
];
|
|
|
|
# Q: Why manipulate files directly instead of using "jenkins-jobs upload [...]"?
|
|
# A: Because this module is for administering a local jenkins install,
|
|
# and using local file copy allows us to not worry about
|
|
# authentication.
|
|
script =
|
|
let
|
|
yamlJobsFile = builtins.toFile "jobs.yaml" cfg.yamlJobs;
|
|
jsonJobsFiles = map (x: (builtins.toFile "jobs.json" x)) (
|
|
cfg.jsonJobs ++ [ (builtins.toJSON cfg.nixJobs) ]
|
|
);
|
|
jobBuilderOutputDir = "/run/jenkins-job-builder/output";
|
|
# Stamp file is placed in $JENKINS_HOME/jobs/$JOB_NAME/ to indicate
|
|
# ownership. Enables tracking and removal of stale jobs.
|
|
ownerStamp = ".config-xml-managed-by-nixos-jenkins-job-builder";
|
|
reloadScript = ''
|
|
echo "Asking Jenkins to reload config"
|
|
curl_opts="--silent --fail --show-error"
|
|
access_token_file=${
|
|
if cfg.accessTokenFile != "" then
|
|
cfg.accessTokenFile
|
|
else
|
|
"$RUNTIME_DIRECTORY/jenkins_access_token.txt"
|
|
}
|
|
if [ "${cfg.accessToken}" != "" ]; then
|
|
(umask 0077; printf "${cfg.accessToken}" >"$access_token_file")
|
|
fi
|
|
jenkins_url="http://${jenkinsCfg.listenAddress}:${toString jenkinsCfg.port}${jenkinsCfg.prefix}"
|
|
auth_file="$RUNTIME_DIRECTORY/jenkins_auth_file.txt"
|
|
trap 'rm -f "$auth_file"' EXIT
|
|
(umask 0077; printf "${cfg.accessUser}:@password_placeholder@" >"$auth_file")
|
|
"${pkgs.replace-secret}/bin/replace-secret" "@password_placeholder@" "$access_token_file" "$auth_file"
|
|
|
|
if ! "${pkgs.jenkins}/bin/jenkins-cli" -s "$jenkins_url" -auth "@$auth_file" reload-configuration; then
|
|
echo "error: failed to reload configuration"
|
|
exit 1
|
|
fi
|
|
'';
|
|
in
|
|
''
|
|
joinByString()
|
|
{
|
|
local separator="$1"
|
|
shift
|
|
local first="$1"
|
|
shift
|
|
printf "%s" "$first" "''${@/#/$separator}"
|
|
}
|
|
|
|
# Map a relative directory path in the output from
|
|
# jenkins-job-builder (jobname) to the layout expected by jenkins:
|
|
# each directory level gets prepended "jobs/".
|
|
getJenkinsJobDir()
|
|
{
|
|
IFS='/' read -ra input_dirs <<< "$1"
|
|
printf "jobs/"
|
|
joinByString "/jobs/" "''${input_dirs[@]}"
|
|
}
|
|
|
|
# The inverse of getJenkinsJobDir (remove the "jobs/" prefixes)
|
|
getJobname()
|
|
{
|
|
IFS='/' read -ra input_dirs <<< "$1"
|
|
local i=0
|
|
local nelem=''${#input_dirs[@]}
|
|
for e in "''${input_dirs[@]}"; do
|
|
if [ $((i % 2)) -eq 1 ]; then
|
|
printf "$e"
|
|
if [ $i -lt $(( nelem - 1 )) ]; then
|
|
printf "/"
|
|
fi
|
|
fi
|
|
i=$((i + 1))
|
|
done
|
|
}
|
|
|
|
rm -rf ${jobBuilderOutputDir}
|
|
cur_decl_jobs=/run/jenkins-job-builder/declarative-jobs
|
|
rm -f "$cur_decl_jobs"
|
|
|
|
# Create / update jobs
|
|
mkdir -p ${jobBuilderOutputDir}
|
|
for inputFile in ${yamlJobsFile} ${lib.concatStringsSep " " jsonJobsFiles}; do
|
|
HOME="${jenkinsCfg.home}" "${pkgs.jenkins-job-builder}/bin/jenkins-jobs" --ignore-cache test --config-xml -o "${jobBuilderOutputDir}" "$inputFile"
|
|
done
|
|
|
|
find "${jobBuilderOutputDir}" -type f -name config.xml | while read -r f; do echo "$(dirname "$f")"; done | sort | while read -r dir; do
|
|
jobname="$(realpath --relative-to="${jobBuilderOutputDir}" "$dir")"
|
|
jenkinsjobname=$(getJenkinsJobDir "$jobname")
|
|
jenkinsjobdir="${jenkinsCfg.home}/$jenkinsjobname"
|
|
echo "Creating / updating job \"$jobname\""
|
|
mkdir -p "$jenkinsjobdir"
|
|
touch "$jenkinsjobdir/${ownerStamp}"
|
|
cp "$dir"/config.xml "$jenkinsjobdir/config.xml"
|
|
echo "$jenkinsjobname" >> "$cur_decl_jobs"
|
|
done
|
|
|
|
# Remove stale jobs
|
|
find "${jenkinsCfg.home}" -type f -name "${ownerStamp}" | while read -r f; do echo "$(dirname "$f")"; done | sort --reverse | while read -r dir; do
|
|
jenkinsjobname="$(realpath --relative-to="${jenkinsCfg.home}" "$dir")"
|
|
grep --quiet --line-regexp "$jenkinsjobname" "$cur_decl_jobs" 2>/dev/null && continue
|
|
jobname=$(getJobname "$jenkinsjobname")
|
|
echo "Deleting stale job \"$jobname\""
|
|
jobdir="${jenkinsCfg.home}/$jenkinsjobname"
|
|
rm -rf "$jobdir"
|
|
done
|
|
''
|
|
+ (lib.optionalString (cfg.accessUser != "") reloadScript);
|
|
serviceConfig = {
|
|
Type = "oneshot";
|
|
User = jenkinsCfg.user;
|
|
RuntimeDirectory = "jenkins-job-builder";
|
|
};
|
|
};
|
|
};
|
|
}
|