is there a way to customize the Nexus UI Nexus UI? I need to add some links to the imprint page of our organisation... I am using the docker-nexus3 image and I am trying to find the location of the frontend's *.html or *.js files there... However, I am not able to find them anywhere.
I've manually searched for the file and also used the "find" and "grep" command inside the container, e.g.
find / -name *.js
find / -name *.html
and
find / -xdev -type f -print0 | xargs -0 grep -H "label-1154"
Thanks!
I strongly discourage you to continue on that path. You won't find any of those js/html files as the only ones that do exist will be dynamically generated by the java application in a tmp directory when it starts and will be trashed on each reboot.
Nexus has a branding capability that you can enable in Administration > System > Capabilities
. Once done, you can click on it, then on the settings
tab where you can enter content for a header and a footer. Both field accept html content.
Note that this capability used to be available for the OpenSource Version but is now reserved to the Pro version. Meanwhile, I still have it enabled on all my open source instance and the groovy script we use to automate this does not seem to fire any errors.
If you are interested in automating this, here is the groovy script to register in Nexus that you can find in an ansible role we use to install nexus (disclaimer: I'm the author).
import groovy.json.JsonSlurper
import org.sonatype.nexus.capability.CapabilityReference
import org.sonatype.nexus.capability.CapabilityType
import org.sonatype.nexus.internal.capability.DefaultCapabilityReference
import org.sonatype.nexus.internal.capability.DefaultCapabilityRegistry
parsed_args = new JsonSlurper().parseText(args)
parsed_args.capability_properties['headerEnabled'] = parsed_args.capability_properties['headerEnabled'].toString()
parsed_args.capability_properties['footerEnabled'] = parsed_args.capability_properties['footerEnabled'].toString()
def capabilityRegistry = container.lookup(DefaultCapabilityRegistry.class.getName())
def capabilityType = CapabilityType.capabilityType(parsed_args.capability_typeId)
DefaultCapabilityReference existing = capabilityRegistry.all.find { CapabilityReference capabilityReference ->
capabilityReference.context().descriptor().type() == capabilityType
}
if (existing) {
log.info(parsed_args.typeId + ' capability updated to: {}',
capabilityRegistry.update(existing.id(), Boolean.valueOf(parsed_args.get('capability_enabled', true)), existing.notes(), parsed_args.capability_properties).toString()
)
}
else {
log.info(parsed_args.typeId + ' capability created as: {}', capabilityRegistry.
add(capabilityType, Boolean.valueOf(parsed_args.get('capability_enabled', true)), 'configured through api', parsed_args.capability_properties).toString()
)
}
To enable branding with some content, here is an example json payload the script is expecting:
{
"capability_typeId": "rapture.branding",
"capability_enabled": true,
"capability_properties": {
"footerHtml": "Your footer content",
"headerHtml": "Your header content",
"footerEnabled": true,
"headerEnabled": true
}
With some extra work, it is possible to add the script and the configure payload to the image, then create an entry point script which will configure nexus with your defaults if not already initialized (on the same idea you can find in the official mysql or postgres images for example).
The global workflow is:
I have applied the above recipe to an image build we use on production which basically does the same thing but with much more scripts and a lot more data to pre-provision the instance (users, repositories, roles, permissions, content selectors....) if it starts from scratch. I unfortunately cannot share that entire work as is but below is a stripped down (not tested) version of the entrypoint for an example. Hope it can help.
entrypoint.sh
#!/usr/bin/bash
set -e
# Read or set default admin password
NEXUS_ADMIN_PASSWORD=${NEXUS_ADMIN_PASSWORD:-changeme}
# Set nexus REST api base url
nexus_rest_url="http://localhost:8081/service/rest"
call_api() {
method=$1
path=$2
params=$3
content_type=${4:-application/json}
password="${5:-${NEXUS_ADMIN_PASSWORD}}"
nexus_auth="admin:${password}"
if [ ! -z "${NEXUS_ENABLE_DEBUG_PROVISIONNING+x}" ]; then
echo curl -u "$nexus_auth" --write '\n%{http_code}\n' --fail --silent -H "accept: application/json" \
-H "Content-Type: ${content_type}" -X ${method} "${nexus_rest_url}${path}" ${params:+-d "$params"}
fi
if result=$(curl -u "$nexus_auth" --write '\n%{http_code}\n' --fail --silent -H "accept: application/json" \
-H "Content-Type: ${content_type}" -X ${method} "${nexus_rest_url}${path}" ${params:+-d "$params"}); then
if [ ! -z NEXUS_ENABLE_DEBUG_PROVISIONNING ]; then
echo "$result" | sed '$d'
fi
else
>&2 echo "Failure: code=$result"
exit 1
fi
}
# Helper function to read the content of groovy script and workaround needed escapes for json
load_script_content() {
script_name="$1"
sed -e ':a' -e 'N' -e '$!ba' -e 's/\\/\\\\/g' -e 's/\n/\\n /g' ${NEXUS_SCRIPTS}/${script_name}.groovy
}
# Helper function to upload new scripts in nexus
upload_script() {
script_name="$1"
script_content=$(load_script_content $script_name)
json_payload='{"name": "'"${script_name}"'", "content": "'"${script_content}"'", "type": "groovy"}'
echo "Uploading script $script_name"
call_api POST /v1/script "${json_payload}"
}
# Get a list of all nexus scripts to upload
list_nexus_scripts() {
script_list=$(find ${NEXUS_SCRIPTS} -name "*.groovy" -exec basename {} \;)
echo ${script_list//.groovy/}
}
# We only try to initialize nexus if we were called with the default command
if [ "$1" = 'start-nexus-repository-manager' ]; then
# Check if the current data folder is empty
# i.e we simply check if it contains the blobs directory
# If it is empty, we start nexus manually and initialize
# with the sent data
if [ ! -d /nexus-data/blobs ]; then
echo "Nexus data dir is empty. Starting initialization routines"
echo "Make sure /etc directory exists in ${NEXUS_DATA}"
mkdir -p ${NEXUS_DATA}/etc
echo "Allowing nexus to register groovy scripts"
echo "nexus.scripts.allowCreation=true" >> ${NEXUS_DATA}/etc/nexus.properties
echo "starting nexus for the first time"
$SONATYPE_DIR/nexus/bin/nexus start
echo "Waiting for nexus to fully start and be available (max 2mn)"
try_delay=5
max_time=120
try_counter=0
while ! ([ -f ${NEXUS_DATA}/log/nexus.log ] && grep -q "Started Sonatype Nexus OSS" "${NEXUS_DATA}/log/nexus.log"); do
(( try_counter = try_counter + 1 ))
if (( try_counter * try_delay > max_time )); then
echo -ne "\n"
echo "Error: nexus did not finish starting after 2mn. Stopping. Dumping nexus log file for further debugging"
cat "${NEXUS_DATA}/log/nexus.log"
exit 1
fi
echo -n "."
sleep $try_delay
done
echo -ne "\n"
echo "Nexus started."
# Get admin password from generated file
NEXUS_ADMIN_PASSWORD="$(cat ${NEXUS_DATA}/admin.password)"
# See the above functions. Set NEXUS_SCRIPT in your
# Dockerfile and upload the scripts there
echo "Uploading all defined scripts to nexus"
for script in $(list_nexus_scripts); do
upload_script $script
done
# Created from existing script call for your case
echo Configure branding
call_api POST /v1/script/create_repos_from_list/run @${NEXUS_SCRIPTS}/branding_payload.json
# Set NEXUS_DELETE_PROVIONNING_SCRIPTS to a non empty value to delete
if [ ! -z "${NEXUS_DELETE_PROVIONNING_SCRIPTS+x}" ]; then
echo "Deleting grooyy provisionning scripts in nexus"
for script in $(list_nexus_scripts); do
call_api DELETE "/v1/script/${script}"
done
fi
# Set NEXUS_DELETE_PROVIONNING_SCRIPTS to a non empty value to disable
if [ ! -z "${NEXUS_DISABLE_GROOVY_AFTER_PROVISIONNING+x}" ]; then
echo "Disabling further declaration of groovy scripts in nexus"
sed -i 's/\(nexus\.scripts\.allowCreation=\).*/\1false/' ${NEXUS_DATA}/etc/nexus.properties
fi
echo "Restarting nexus after initial provisionning"
$SONATYPE_DIR/nexus/bin/nexus stop
fi
fi
exec "$@"