From 9cbf0d47dd420a64f69c5c4d2a48a150dbd08fab Mon Sep 17 00:00:00 2001 From: M3dinar Date: Wed, 22 Jul 2026 15:03:03 +0200 Subject: [PATCH 01/23] Updated Ubuntu base image to 24.04 (noble) Removed helix-swarm Updated perforce to 2026.1 --- helix-p4d/Dockerfile | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/helix-p4d/Dockerfile b/helix-p4d/Dockerfile index ce6b520..4975d66 100644 --- a/helix-p4d/Dockerfile +++ b/helix-p4d/Dockerfile @@ -1,27 +1,34 @@ # -------------------------------------------------------------------------------- # Docker configuration for P4D # -------------------------------------------------------------------------------- - -FROM ubuntu:focal +# Ubuntu noble and 24.04 are the same, but noble is the codename for 24.04 +FROM ubuntu:24.04 LABEL vendor="Sourcegraph" LABEL maintainer="Joe Chen (joe@sourcegraph.com)" -# Update Ubuntu and add Perforce Package Source RUN apt-get update && \ - apt-get install -y wget gnupg2 && \ - wget -qO - https://package.perforce.com/perforce.pubkey | apt-key add - && \ - echo "deb http://package.perforce.com/apt/ubuntu focal release" > /etc/apt/sources.list.d/perforce.list && \ - apt-get update + apt-get install -y wget gnupg2 # -------------------------------------------------------------------------------- # Docker BUILD # -------------------------------------------------------------------------------- # Create perforce user and install Perforce Server -# Do in-page search over https://package.perforce.com/apt/ubuntu/dists/focal/release/binary-amd64/Packages -# for both "Package: helix-p4d" and "Package: helix-swarm-triggers". -RUN apt-get update && apt-get install -y helix-p4d=2024.1-2625008~focal helix-swarm-triggers=2024.3-2628402~focal +# Do in-page search over https://package.perforce.com/apt/ubuntu/dists/noble/release/binary-amd64/Packages +# for "Package: helix-p4d" +# Update Ubuntu and add Perforce Package Source +RUN apt-get update && apt-get install -y wget gnupg && \ + wget -qO - https://package.perforce.com/perforce.pubkey | gpg --dearmor -o /etc/apt/keyrings/perforce.gpg && \ + echo "deb [signed-by=/etc/apt/keyrings/perforce.gpg] http://package.perforce.com/apt/ubuntu noble release" > /etc/apt/sources.list.d/perforce.list && \ + apt-get update && \ + apt-get install -y helix-p4d=2026.1-2951233~noble + +RUN apt-get remove -y wget gnupg2 && \ + apt-get autoremove -y && \ + apt-get clean -y && \ + rm -rf /var/lib/apt/lists/* + # Add external files COPY files/restore.sh /usr/local/bin/restore.sh COPY files/setup.sh /usr/local/bin/setup.sh From 2dc7d674cb67860d84ec30f50b22f8ebcf388f20 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Wed, 22 Jul 2026 15:18:08 +0200 Subject: [PATCH 02/23] Removed NAME env variable Fixed log target --- README.md | 29 ++++++++++++++++++++++------- helix-p4d/Dockerfile | 8 +++----- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index f15d40a..fda6fcd 100644 --- a/README.md +++ b/README.md @@ -21,24 +21,23 @@ To have a disposable Perforce Helix core server running, simply do: ```sh docker run --rm \ --publish 1666:1666 \ - sourcegraph/helix-p4d:2023.1 + sourcegraph/helix-p4d:latest ``` The above command makes the server avaialble locally at `:1666`, with a default super user `admin` and its password `pass12349ers`. +#### Environment variables All available options and their default values: ```sh -NAME=perforce-server P4HOME=/p4 -P4NAME=master +P4NAME=perforce-server P4TCP=1666 P4PORT=1666 P4USER=admin P4PASSWD=pass12349ers P4CASE=-C0 P4CHARSET=utf8 -JNL_PREFIX=perforce-server ``` Use the `--env` flag to override default: @@ -48,12 +47,13 @@ docker run --rm \ --publish 1666:1666 \ --env P4USER=amy \ --env P4PASSWD=securepassword \ - sourcegraph/helix-p4d:2023.1 + sourcegraph/helix-p4d:latest ``` > [!WARNING] > Please be noted that although the server survives over restarts (i.e. data are kept), but it may break if you change the options after the initial bootstrap (i.e. the very first run of the image, at when options are getting hard-coded to the Perforce Helix core server own configuration). +#### Volumes To start a long-running production container, do remember to volume the data directory (`P4HOME`) and replace the `--rm` flag with `-d` (detach): ```sh @@ -61,7 +61,7 @@ docker run -d \ --publish 1666:1666 \ --env P4PASSWD=securepassword \ --volume ~/.helix-p4d-home:/p4 \ - sourcegraph/helix-p4d:2023.1 + sourcegraph/helix-p4d:latest ``` Now you have a running server, please read our handbook for [how to set up the client side](https://handbook.sourcegraph.com/departments/technical-success/support/process/p4-enablement/). @@ -93,4 +93,19 @@ docker run --rm \ ## Credits -This repository is heavily inspired by https://github.com/p4paul/helix-docker and https://github.com/ambakshi/docker-perforce. +This repository is heavily inspired by https://github.com/p4paul/helix-docker and https://github.com/ambakshi/docker-perforce + +## Fork + +The fork was done to allow some changes +- Update of the dependancies + - Ubuntu focal to noble (no support for racoon ATM) + - Helix perforce to 2026.1 +- Removed helix swarm +- Changed the whole restore checkpoint logic +- Improvements + - Unified folder name + - Unified the use of the setup in each case to configure and start the server + - Use of p4dctl +- Fixes + - Charset when there is no one selected diff --git a/helix-p4d/Dockerfile b/helix-p4d/Dockerfile index 4975d66..adae737 100644 --- a/helix-p4d/Dockerfile +++ b/helix-p4d/Dockerfile @@ -46,8 +46,7 @@ RUN \ # -------------------------------------------------------------------------------- # Default Environment -ARG NAME=perforce-server -ARG P4NAME=master +ARG P4NAME=perforce-server ARG P4TCP=1666 ARG P4USER=admin ARG P4PASSWD=pass12349ers @@ -55,8 +54,7 @@ ARG P4CASE=-C0 ARG P4CHARSET=utf8 # Dynamic Environment -ENV NAME=$NAME \ - P4NAME=$P4NAME \ +ENV P4NAME=$P4NAME \ P4TCP=$P4TCP \ P4PORT=$P4TCP \ P4USER=$P4USER \ @@ -83,7 +81,7 @@ VOLUME $P4HOME ENTRYPOINT \ init.sh && \ - /usr/bin/tail -F $P4ROOT/logs/log + /usr/bin/tail -F $P4HOME/logs/log HEALTHCHECK \ --interval=2m \ From 6a1f677c173c4e50c264b0b799cdc3dc9c71a744 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Wed, 22 Jul 2026 16:06:47 +0200 Subject: [PATCH 03/23] Setup is called at start or after restoring a checkpoint (all the time) Check the charset value Use of p4dctl for the services --- helix-p4d/files/init.sh | 14 +++++++++----- helix-p4d/files/setup.sh | 28 ++++++++++++++++++---------- 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/helix-p4d/files/init.sh b/helix-p4d/files/init.sh index 405913c..f5ab561 100644 --- a/helix-p4d/files/init.sh +++ b/helix-p4d/files/init.sh @@ -10,18 +10,22 @@ if [ -L "$P4CKP/latest" ]; then echo "Restoring checkpoint..." restore.sh rm "$P4CKP/latest" -else - echo "Create empty or start existing server..." - setup.sh fi +echo "Configuring the server..." +setup.sh + +# Start the server +echo "Perforce Server starting..." +p4dctl start -t p4d "$P4NAME" + +# Retrieving server information to be displayed in the logs p4 login < /dev/null; do sleep 1; done -echo "Perforce Server [RUNNING]" ## Remove all triggers echo "Triggers:" | p4 triggers -i diff --git a/helix-p4d/files/setup.sh b/helix-p4d/files/setup.sh index 615b6d0..2eadfe7 100644 --- a/helix-p4d/files/setup.sh +++ b/helix-p4d/files/setup.sh @@ -1,19 +1,27 @@ #!/bin/bash -if [ ! -d "$P4ROOT/etc" ]; then - echo >&2 "First time installation, copying configuration from /etc/perforce to $P4ROOT/etc and relinking" - mkdir -p "$P4ROOT/etc" - cp -r /etc/perforce/* "$P4ROOT/etc/" -fi +opts=() -mv /etc/perforce /etc/perforce.orig -ln -s "$P4ROOT/etc" /etc/perforce +# Check P4CHARSET environment variable +if [ -z "${P4CHARSET:-}" ]; then + echo "Error: P4CHARSET environment variable is not set." + exit 255 +fi +if [ "${P4CHARSET:-}" != "none" && "${P4CHARSET:-}" != "utf8" ]; then + echo "Error: P4CHARSET value unknown, expected 'none' or 'utf8'." + exit 255 +fi -if ! p4dctl list 2>/dev/null | grep -q "$NAME"; then - /opt/perforce/sbin/configure-helix-p4d.sh "$NAME" -n -p "$P4PORT" -r "$P4ROOT" -u "$P4USER" -P "${P4PASSWD}" --case "$P4CASE" --unicode +# If P4CHARSET is set to "none", do not pass --unicode. Otherwise include it. +if [ "${P4CHARSET:-}" != "none" ]; then + opts+=(--unicode) fi +# Run the container and get a terminal into it so you can cat the file to get the list of option (No known web documentation) +/opt/perforce/sbin/configure-helix-p4d.sh "$P4NAME" -n -p "$P4PORT" -r "$P4HOME" -u "$P4USER" -P "${P4PASSWD}" --case="$P4CASE" "${opts[@]}" + p4 configure set $P4NAME#server.depot.root=$P4DEPOTS p4 configure set $P4NAME#journalPrefix=$P4CKP/$JNL_PREFIX -p4dctl start -t p4d "$NAME" +# Stopping the server so the previous configuration are taken into account +p4dctl stop -t p4d "$P4NAME" \ No newline at end of file From bd57ea6c3b9ef03562b033f5203c5fd7d9b5a7c8 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Wed, 22 Jul 2026 16:13:10 +0200 Subject: [PATCH 04/23] Refacto restore from checkpoint --- README.md | 9 +++++++++ helix-p4d/files/latest_checkpoint.sh | 16 ---------------- helix-p4d/files/restore.sh | 24 ++++++++++-------------- 3 files changed, 19 insertions(+), 30 deletions(-) delete mode 100644 helix-p4d/files/latest_checkpoint.sh diff --git a/README.md b/README.md index fda6fcd..a724d49 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,9 @@ docker run --rm \ > [!WARNING] > Please be noted that although the server survives over restarts (i.e. data are kept), but it may break if you change the options after the initial bootstrap (i.e. the very first run of the image, at when options are getting hard-coded to the Perforce Helix core server own configuration). +`P4CASE` : `-C0` means Unix-style and `-C1` Windows-style (only these 2 values are valid) +`P4CHARSET` : `none` and `utf8` are the only valid values + #### Volumes To start a long-running production container, do remember to volume the data directory (`P4HOME`) and replace the `--rm` flag with `-d` (detach): @@ -91,6 +94,12 @@ docker run --rm \ sourcegraph/helix-p4d:2023.1 ``` +### Restore from a checkpoint +With a journal and checkpoint, generate a gz file +Put them in the folder `/p4/checkpoints/` (`$P4CKP`) +Create a simlink to the gz file named latest in the folder `$P4CKP` +Run the container, it will generate the DB from the checkpoint and remove the sym link. The gz can be removed once you're good with it. + ## Credits This repository is heavily inspired by https://github.com/p4paul/helix-docker and https://github.com/ambakshi/docker-perforce diff --git a/helix-p4d/files/latest_checkpoint.sh b/helix-p4d/files/latest_checkpoint.sh deleted file mode 100644 index 5466195..0000000 --- a/helix-p4d/files/latest_checkpoint.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/bin/bash - -## Find latest checkpoint -unset -v latest -for file in "$P4CKP"/"$JNL_PREFIX".ckp.*.gz; do - [[ $file -nt $latest ]] && latest=$file -done - -## If file exists update symlink -if [ "$latest" ]; then - echo "Updating latest symlink to: $latest" - ln -f -s "$latest" "$P4CKP/latest" -else - echo "Error: Unable to find a checkpoint" - exit 255 -fi diff --git a/helix-p4d/files/restore.sh b/helix-p4d/files/restore.sh index c132cff..f9f67d6 100644 --- a/helix-p4d/files/restore.sh +++ b/helix-p4d/files/restore.sh @@ -1,20 +1,20 @@ #!/bin/bash -## Test for latest link -if [ ! -L "$P4CKP/latest" ]; then - echo "Link not found - looking for checkpoint" - /usr/local/bin/latest_checkpoint.sh -fi - ## Test Checkpoint exists if [ ! -L "$P4CKP/latest" ]; then echo "Error: Checkpoint for link $P4CKP/latest not found." exit 255 fi -## Stop Perforce -#p4 admin stop -#until ! p4 info -s 2> /dev/null; do sleep 1; done +## Check P4CASE environment variable +if [ -z "${P4CASE:-}" ]; then + echo "Error: P4CASE environment variable is not set." + exit 255 +fi +if [ "${P4CASE:-}" != "-C0" ] && [ "${P4CASE:-}" != "-C1" ]; then + echo "Error: P4CASE must be set to -C0 (Unix-style) or -C1 (Windows-style)." + exit 255 +fi ## Remove current data base rm -rf $P4ROOT/* @@ -23,13 +23,9 @@ rm -rf $P4ROOT/* echo $P4NAME > $P4ROOT/server.id ## Restore and Upgrade Checkpoint +echo "Restoring checkpoint..." p4d $P4CASE -r $P4ROOT -jr -z $P4CKP/latest p4d $P4CASE -r $P4ROOT -xu ## Set key environment variables p4d $P4CASE -r $P4ROOT "-cset security=2" -p4d $P4CASE -r $P4ROOT "-cset ${P4NAME}#server.depot.root=${P4DEPOTS}" -p4d $P4CASE -r $P4ROOT "-cset ${P4NAME}#journalPrefix=${P4CKP}/${JNL_PREFIX}" - -## Start Perforce -p4d $P4CASE -r$P4ROOT -p$P4TCP -L$P4LOG -J$P4JOURNAL -d From ac24ca6b5d8a60290fad2ca7da0de576e3c3fef2 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sun, 26 Jul 2026 15:22:39 +0200 Subject: [PATCH 05/23] Added information about env variable JNL_PREFIX --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a724d49..4230d4b 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,7 @@ docker run --rm \ `P4CASE` : `-C0` means Unix-style and `-C1` Windows-style (only these 2 values are valid) `P4CHARSET` : `none` and `utf8` are the only valid values +`JNL_PREFIX` : prefix for the perforce journal file #### Volumes To start a long-running production container, do remember to volume the data directory (`P4HOME`) and replace the `--rm` flag with `-d` (detach): From 9ae3ac842024413adbe51ff3a5cf9027c42d9d1f Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sun, 26 Jul 2026 15:25:04 +0200 Subject: [PATCH 06/23] Changed helix-p4d with the latest available --- helix-p4d/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helix-p4d/Dockerfile b/helix-p4d/Dockerfile index adae737..1d04f48 100644 --- a/helix-p4d/Dockerfile +++ b/helix-p4d/Dockerfile @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y wget gnupg && \ wget -qO - https://package.perforce.com/perforce.pubkey | gpg --dearmor -o /etc/apt/keyrings/perforce.gpg && \ echo "deb [signed-by=/etc/apt/keyrings/perforce.gpg] http://package.perforce.com/apt/ubuntu noble release" > /etc/apt/sources.list.d/perforce.list && \ apt-get update && \ - apt-get install -y helix-p4d=2026.1-2951233~noble + apt-get install -y helix-p4d=2026.1-2972966~noble RUN apt-get remove -y wget gnupg2 && \ apt-get autoremove -y && \ From 548aab70615a9ca8091dc723eab233609a897346 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sun, 26 Jul 2026 15:25:44 +0200 Subject: [PATCH 07/23] Fixed remaining issue in the build due after removed files in previous work --- helix-p4d/Dockerfile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/helix-p4d/Dockerfile b/helix-p4d/Dockerfile index 1d04f48..36c57d2 100644 --- a/helix-p4d/Dockerfile +++ b/helix-p4d/Dockerfile @@ -33,13 +33,11 @@ RUN apt-get remove -y wget gnupg2 && \ COPY files/restore.sh /usr/local/bin/restore.sh COPY files/setup.sh /usr/local/bin/setup.sh COPY files/init.sh /usr/local/bin/init.sh -COPY files/latest_checkpoint.sh /usr/local/bin/latest_checkpoint.sh RUN \ chmod +x /usr/local/bin/restore.sh && \ chmod +x /usr/local/bin/setup.sh && \ - chmod +x /usr/local/bin/init.sh && \ - chmod +x /usr/local/bin/latest_checkpoint.sh + chmod +x /usr/local/bin/init.sh # -------------------------------------------------------------------------------- # Docker ENVIRONMENT From 4757b46458e2fd2330ccb60b4a3504d672007287 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sun, 26 Jul 2026 15:28:18 +0200 Subject: [PATCH 08/23] Removed trigger (not working) --- helix-p4d/files/init.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/helix-p4d/files/init.sh b/helix-p4d/files/init.sh index f5ab561..8696a3b 100644 --- a/helix-p4d/files/init.sh +++ b/helix-p4d/files/init.sh @@ -26,6 +26,3 @@ EOF echo "Perforce Server [RUNNING] with the following configuration" until p4 info -s 2> /dev/null; do sleep 1; done - -## Remove all triggers -echo "Triggers:" | p4 triggers -i From 79adbf9fb2e60d59092d41dff45b29a77547e6fc Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sun, 26 Jul 2026 15:30:35 +0200 Subject: [PATCH 09/23] Added prefix to logs Setup is only run after a restore (new install will not work) Added helper for configure-helix-p4d.sh Added conversion for case option between setup and restore --- helix-p4d/files/init.sh | 15 ++++++----- helix-p4d/files/restore.sh | 8 +++--- helix-p4d/files/setup.sh | 53 ++++++++++++++++++++++++++++++++++---- 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/helix-p4d/files/init.sh b/helix-p4d/files/init.sh index 8696a3b..b830f2b 100644 --- a/helix-p4d/files/init.sh +++ b/helix-p4d/files/init.sh @@ -7,16 +7,19 @@ mkdir -p "$P4CKP" # Restore checkpoint if symlink latest exists if [ -L "$P4CKP/latest" ]; then - echo "Restoring checkpoint..." + echo "[INFO] Restoring checkpoint..." restore.sh rm "$P4CKP/latest" -fi + echo "[INFO] Server restored" -echo "Configuring the server..." -setup.sh + echo "[INFO] Configuring the server..." + setup.sh + echo "[INFO] Server configured, restart required" + exit 0 +fi # Start the server -echo "Perforce Server starting..." +echo "[INFO] Starting Server..." p4dctl start -t p4d "$P4NAME" # Retrieving server information to be displayed in the logs @@ -24,5 +27,5 @@ p4 login < /dev/null; do sleep 1; done diff --git a/helix-p4d/files/restore.sh b/helix-p4d/files/restore.sh index f9f67d6..daf6beb 100644 --- a/helix-p4d/files/restore.sh +++ b/helix-p4d/files/restore.sh @@ -2,17 +2,17 @@ ## Test Checkpoint exists if [ ! -L "$P4CKP/latest" ]; then - echo "Error: Checkpoint for link $P4CKP/latest not found." + echo "[ERROR] Checkpoint for link $P4CKP/latest not found." exit 255 fi ## Check P4CASE environment variable if [ -z "${P4CASE:-}" ]; then - echo "Error: P4CASE environment variable is not set." + echo "[ERROR] P4CASE environment variable is not set." exit 255 fi if [ "${P4CASE:-}" != "-C0" ] && [ "${P4CASE:-}" != "-C1" ]; then - echo "Error: P4CASE must be set to -C0 (Unix-style) or -C1 (Windows-style)." + echo "[ERROR] P4CASE must be set to -C0 (Unix-style) or -C1 (Windows-style)." exit 255 fi @@ -23,7 +23,7 @@ rm -rf $P4ROOT/* echo $P4NAME > $P4ROOT/server.id ## Restore and Upgrade Checkpoint -echo "Restoring checkpoint..." +echo "[INFO] Restoring checkpoint with option $P4CASE" p4d $P4CASE -r $P4ROOT -jr -z $P4CKP/latest p4d $P4CASE -r $P4ROOT -xu diff --git a/helix-p4d/files/setup.sh b/helix-p4d/files/setup.sh index 2eadfe7..1113ef1 100644 --- a/helix-p4d/files/setup.sh +++ b/helix-p4d/files/setup.sh @@ -4,11 +4,11 @@ opts=() # Check P4CHARSET environment variable if [ -z "${P4CHARSET:-}" ]; then - echo "Error: P4CHARSET environment variable is not set." + echo "[ERROR] P4CHARSET environment variable is not set." exit 255 fi -if [ "${P4CHARSET:-}" != "none" && "${P4CHARSET:-}" != "utf8" ]; then - echo "Error: P4CHARSET value unknown, expected 'none' or 'utf8'." +if [ "${P4CHARSET:-}" != "none" ] && [ "${P4CHARSET:-}" != "utf8" ]; then + echo "[ERROR] P4CHARSET value unknown, expected 'none' or 'utf8'." exit 255 fi @@ -17,9 +17,52 @@ if [ "${P4CHARSET:-}" != "none" ]; then opts+=(--unicode) fi -# Run the container and get a terminal into it so you can cat the file to get the list of option (No known web documentation) -/opt/perforce/sbin/configure-helix-p4d.sh "$P4NAME" -n -p "$P4PORT" -r "$P4HOME" -u "$P4USER" -P "${P4PASSWD}" --case="$P4CASE" "${opts[@]}" +## Check P4CASE environment variable +if [ -z "${P4CASE:-}" ]; then + echo "[ERROR] P4CASE environment variable is not set." + exit 255 +fi +if [ "${P4CASE:-}" != "-C0" ] && [ "${P4CASE:-}" != "-C1" ]; then + echo "[ERROR] P4CASE must be set to -C0 (Unix-style) or -C1 (Windows-style)." + exit 255 +fi +if [ "${P4CASE:-}" == "-C1" ]; then + opts+=(--case=1) +else + opts+=(--case=0) +fi + +# Script to configure the server with the given param so a p4dctl is created. +# Helper of the script available in it +#------------------------------------------------------------------------------- +# Configuration script for P4 Server +# Copyright 2025, Perforce Software Inc. All rights reserved. +# +# Synopsis: +# +# configure-p4d.sh [service-name] [options] +# +# Where options are: +# +# -n - Use the following flags in non-interactive mode +# -p - Set P4 Server's address +# -r - Set P4 Server's root directory +# -u - P4 super-user login name +# -P - P4 super-user password +# --unicode - Enable unicode mode on server +# --case - Case-sensitivity (0=sensitive[default],1=insensitive) +# +# Password is only needed on initial configuration when the super-user +# account is created. If reconfiguring an existing Perforce Server, the +# super-user name and password are left alone. +# +# Unicode mode is disabled by default. Specify --unicode if you +# want it. This will change in a future release. +# +#------------------------------------------------------------------------------- +/opt/perforce/sbin/configure-helix-p4d.sh "$P4NAME" -n -p "$P4PORT" -r "$P4HOME" -u "$P4USER" -P "${P4PASSWD}" "${opts[@]}" +echo "[INFO] Configuring server settings..." p4 configure set $P4NAME#server.depot.root=$P4DEPOTS p4 configure set $P4NAME#journalPrefix=$P4CKP/$JNL_PREFIX From 8c5f524be0819e0115cd6f449f41e8c6d50903f0 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Thu, 30 Jul 2026 07:56:39 +0200 Subject: [PATCH 10/23] Added fresh install if no p4dctl services was found --- helix-p4d/files/init.sh | 7 +++++++ helix-p4d/files/setup.sh | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/helix-p4d/files/init.sh b/helix-p4d/files/init.sh index b830f2b..3186759 100644 --- a/helix-p4d/files/init.sh +++ b/helix-p4d/files/init.sh @@ -18,6 +18,13 @@ if [ -L "$P4CKP/latest" ]; then exit 0 fi +# Configure the server on a fresh install when no instance is registered +# Header of p4dctl list and the message when there is no instance are ouput to stderr. +if [ -z "$(p4dctl list 2>/dev/null)" ]; then + echo "[INFO] No existing server configuration detected. Running setup..." + setup.sh +fi + # Start the server echo "[INFO] Starting Server..." p4dctl start -t p4d "$P4NAME" diff --git a/helix-p4d/files/setup.sh b/helix-p4d/files/setup.sh index 1113ef1..5875641 100644 --- a/helix-p4d/files/setup.sh +++ b/helix-p4d/files/setup.sh @@ -50,7 +50,7 @@ fi # -u - P4 super-user login name # -P - P4 super-user password # --unicode - Enable unicode mode on server -# --case - Case-sensitivity (0=sensitive[default],1=insensitive) +# --case - Case-sensitivity (0=sensitive[default],1=insensitive) # # Password is only needed on initial configuration when the super-user # account is created. If reconfiguring an existing Perforce Server, the From 3017b920a39b7d2d27bf303d6a64998163969677 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Thu, 30 Jul 2026 08:17:46 +0200 Subject: [PATCH 11/23] Removed configuration setting during restore process Added security to 2 when creating a setup Changed printing server configuration instead of client information --- helix-p4d/files/init.sh | 7 +------ helix-p4d/files/restore.sh | 3 --- helix-p4d/files/setup.sh | 8 +++++++- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/helix-p4d/files/init.sh b/helix-p4d/files/init.sh index 3186759..6454a9e 100644 --- a/helix-p4d/files/init.sh +++ b/helix-p4d/files/init.sh @@ -29,10 +29,5 @@ fi echo "[INFO] Starting Server..." p4dctl start -t p4d "$P4NAME" -# Retrieving server information to be displayed in the logs -p4 login < /dev/null; do sleep 1; done +until p4 configure show -s 2> /dev/null; do sleep 1; done diff --git a/helix-p4d/files/restore.sh b/helix-p4d/files/restore.sh index daf6beb..3924535 100644 --- a/helix-p4d/files/restore.sh +++ b/helix-p4d/files/restore.sh @@ -26,6 +26,3 @@ echo $P4NAME > $P4ROOT/server.id echo "[INFO] Restoring checkpoint with option $P4CASE" p4d $P4CASE -r $P4ROOT -jr -z $P4CKP/latest p4d $P4CASE -r $P4ROOT -xu - -## Set key environment variables -p4d $P4CASE -r $P4ROOT "-cset security=2" diff --git a/helix-p4d/files/setup.sh b/helix-p4d/files/setup.sh index 5875641..ff67f63 100644 --- a/helix-p4d/files/setup.sh +++ b/helix-p4d/files/setup.sh @@ -62,9 +62,15 @@ fi #------------------------------------------------------------------------------- /opt/perforce/sbin/configure-helix-p4d.sh "$P4NAME" -n -p "$P4PORT" -r "$P4HOME" -u "$P4USER" -P "${P4PASSWD}" "${opts[@]}" +# Server configuration is set to default security 4, so we need to get a ticket with p4 login to change configuration settings. +p4 login < Date: Thu, 30 Jul 2026 08:25:10 +0200 Subject: [PATCH 12/23] Updated README.md to inform the default server configuration set by the container --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 4230d4b..acb3fcc 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,12 @@ This repository contains a collection of source files for building Docker images This directory contains the source files for building a Perforce Helix core server Docker image. The published Docker images are available as [`sourcegraph/helix-p4d` on Docker Hub](https://hub.docker.com/r/sourcegraph/helix-p4d). +### Default server configuration + +- `security` : 2 instead of 4 +- `server.depots.root` : `P4DEPOTS` +- `journalPrefix` : `P4CKP/JNL_PREFIX` + ### Build the docker image The `helix-p4d/build.sh` script will build the docker image for you. If you don't provide a tag to the script it will tag the image as `sourcegraph/helix-p4d:latest` From a460b9e460d0bfff9968c67c005032afefe25b36 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Thu, 30 Jul 2026 08:46:58 +0200 Subject: [PATCH 13/23] Show triggers when the server is configured Removed triggers when the server is configured --- README.md | 1 + helix-p4d/files/init.sh | 3 ++- helix-p4d/files/setup.sh | 6 ++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index acb3fcc..12d02ea 100644 --- a/README.md +++ b/README.md @@ -106,6 +106,7 @@ With a journal and checkpoint, generate a gz file Put them in the folder `/p4/checkpoints/` (`$P4CKP`) Create a simlink to the gz file named latest in the folder `$P4CKP` Run the container, it will generate the DB from the checkpoint and remove the sym link. The gz can be removed once you're good with it. +Triggers are removed. ## Credits diff --git a/helix-p4d/files/init.sh b/helix-p4d/files/init.sh index 6454a9e..b017036 100644 --- a/helix-p4d/files/init.sh +++ b/helix-p4d/files/init.sh @@ -30,4 +30,5 @@ echo "[INFO] Starting Server..." p4dctl start -t p4d "$P4NAME" echo "[INFO] Server [RUNNING] with the following configuration" -until p4 configure show -s 2> /dev/null; do sleep 1; done +until p4 info -s 2> /dev/null; do sleep 1; done +until p4 configure show 2> /dev/null; do sleep 1; done diff --git a/helix-p4d/files/setup.sh b/helix-p4d/files/setup.sh index ff67f63..0b04101 100644 --- a/helix-p4d/files/setup.sh +++ b/helix-p4d/files/setup.sh @@ -72,5 +72,11 @@ p4 configure set $P4NAME#security=2 p4 configure set $P4NAME#server.depot.root=$P4DEPOTS p4 configure set $P4NAME#journalPrefix=$P4CKP/$JNL_PREFIX +# In the case where we restore a checkpoint, we must ensure that triggers are removed +echo "[INFO] Existing triggers :" +p4 triggers -o +echo "[INFO] Removing triggers ..." +echo "Triggers:" | p4 triggers -i + # Stopping the server so the new configuration is taken into account p4dctl stop -t p4d "$P4NAME" \ No newline at end of file From 4de960a95058d158462a8553040328d90197c457 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sat, 15 Aug 2026 21:14:10 +0200 Subject: [PATCH 14/23] Added workflow to check image build --- .github/workflow/docker-build-check.yml | 34 +++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 .github/workflow/docker-build-check.yml diff --git a/.github/workflow/docker-build-check.yml b/.github/workflow/docker-build-check.yml new file mode 100644 index 0000000..2f4c2d3 --- /dev/null +++ b/.github/workflow/docker-build-check.yml @@ -0,0 +1,34 @@ +name: Docker Build Check + +on: + pull_request: + branches: [main] + paths: + - 'helix-p4d/**' + - '.github/workflows/docker-build-check.yml' + +# Cancel any in-progress runs of this workflow for the same pull request number +concurrency: + group: docker-build-check-${{ github.event.pull_request.number }} + cancel-in-progress: true + +jobs: + build: + name: Build helix-p4d image + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Build image (no push) + uses: docker/build-push-action@v6 + with: + context: ./helix-p4d + platforms: linux/amd64 + push: false + tags: helix-p4d:ci-${{ github.sha }} + cache-from: type=gha + cache-to: type=gha,mode=max \ No newline at end of file From 0da29822693f65e5ae65c6ec82628cb4caef0d4e Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sat, 15 Aug 2026 21:18:02 +0200 Subject: [PATCH 15/23] Fix workflow into workflows folder --- .github/{workflow => workflows}/docker-build-check.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{workflow => workflows}/docker-build-check.yml (100%) diff --git a/.github/workflow/docker-build-check.yml b/.github/workflows/docker-build-check.yml similarity index 100% rename from .github/workflow/docker-build-check.yml rename to .github/workflows/docker-build-check.yml From 291b540f951ce1e7580429a5f113979078e71b36 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sat, 15 Aug 2026 21:32:20 +0200 Subject: [PATCH 16/23] Update version for node.js 24 --- .github/workflows/docker-build-check.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docker-build-check.yml b/.github/workflows/docker-build-check.yml index 2f4c2d3..d9d97cc 100644 --- a/.github/workflows/docker-build-check.yml +++ b/.github/workflows/docker-build-check.yml @@ -18,13 +18,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Build image (no push) - uses: docker/build-push-action@v6 + uses: docker/build-push-action@v7 with: context: ./helix-p4d platforms: linux/amd64 From ab365bba636c262325fd6fb144c1f11ab5db01f4 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sat, 15 Aug 2026 21:55:59 +0200 Subject: [PATCH 17/23] Added workflow to check if new perforce version is available --- .../p4d-version/get-current-version.sh | 16 +++++ .../scripts/p4d-version/get-latest-version.sh | 34 +++++++++ .github/scripts/p4d-version/sync-issue.sh | 69 +++++++++++++++++++ .github/workflows/check-p4d-version.yml | 39 +++++++++++ 4 files changed, 158 insertions(+) create mode 100755 .github/scripts/p4d-version/get-current-version.sh create mode 100755 .github/scripts/p4d-version/get-latest-version.sh create mode 100755 .github/scripts/p4d-version/sync-issue.sh create mode 100644 .github/workflows/check-p4d-version.yml diff --git a/.github/scripts/p4d-version/get-current-version.sh b/.github/scripts/p4d-version/get-current-version.sh new file mode 100755 index 0000000..52ff214 --- /dev/null +++ b/.github/scripts/p4d-version/get-current-version.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +# Extracts the helix-p4d version currently pinned in helix-p4d/Dockerfile +# and exposes it as the "version" step output. +set -euo pipefail + +DOCKERFILE="helix-p4d/Dockerfile" + +VERSION=$(grep -oP 'helix-p4d=\K[^ \\]+' "$DOCKERFILE" | head -1) + +if [[ -z "$VERSION" ]]; then + echo "Could not find a pinned helix-p4d version in $DOCKERFILE" >&2 + exit 1 +fi + +echo "version=$VERSION" >> "$GITHUB_OUTPUT" +echo "Currently pinned version: $VERSION" diff --git a/.github/scripts/p4d-version/get-latest-version.sh b/.github/scripts/p4d-version/get-latest-version.sh new file mode 100755 index 0000000..0929a73 --- /dev/null +++ b/.github/scripts/p4d-version/get-latest-version.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +# Downloads the Perforce APT "Packages" index and extracts the latest +# available helix-p4d version, exposed as the "version" step output. +set -euo pipefail + +PACKAGES_URL="https://package.perforce.com/apt/ubuntu/dists/noble/release/binary-amd64/Packages" + +TMP_FILE=$(mktemp) +trap 'rm -f "$TMP_FILE"' EXIT + +curl -fsSL "$PACKAGES_URL" -o "$TMP_FILE" + +# Debian control file format: records are separated by a blank line. +# We keep records where "Package: helix-p4d" is an exact match (so +# "helix-p4d-doc" etc. are excluded), then read their Version field. +# If several versions are listed, keep the highest one (version sort). +LATEST_VERSION=$(awk -v RS='' -F'\n' ' + { + pkg=""; ver=""; + for (i = 1; i <= NF; i++) { + if ($i == "Package: helix-p4d") pkg=$i; + if ($i ~ /^Version: /) { ver=$i; sub(/^Version: /, "", ver) } + } + if (pkg != "") print ver + } +' "$TMP_FILE" | sort -V | tail -1) + +if [[ -z "$LATEST_VERSION" ]]; then + echo "Could not find the helix-p4d package in the Perforce feed" >&2 + exit 1 +fi + +echo "version=$LATEST_VERSION" >> "$GITHUB_OUTPUT" +echo "Latest available version: $LATEST_VERSION" diff --git a/.github/scripts/p4d-version/sync-issue.sh b/.github/scripts/p4d-version/sync-issue.sh new file mode 100755 index 0000000..272a7d7 --- /dev/null +++ b/.github/scripts/p4d-version/sync-issue.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +# Creates (or updates) a GitHub issue tracking the fact that a newer +# helix-p4d version is available than the one pinned in the Dockerfile. +# +# Requires the following environment variables: +# GH_TOKEN - token used by the gh CLI +# REPO - "owner/repo" +# CURRENT_VERSION - version currently pinned in the Dockerfile +# LATEST_VERSION - version currently available from Perforce +set -euo pipefail + +: "${GH_TOKEN:?GH_TOKEN is required}" +: "${REPO:?REPO is required}" +: "${CURRENT_VERSION:?CURRENT_VERSION is required}" +: "${LATEST_VERSION:?LATEST_VERSION is required}" + +LABEL="p4d-update" + +# Make sure the label exists (no-op if it already does) +gh label create "$LABEL" \ + --color "FBCA04" \ + --description "A newer helix-p4d version is available from Perforce" \ + --force || true + +# Look for an already-open issue carrying this label +EXISTING_ISSUE=$(gh issue list \ + --repo "$REPO" \ + --label "$LABEL" \ + --state open \ + --json number,title,body \ + --jq '.[0]') + +if [[ -z "$EXISTING_ISSUE" || "$EXISTING_ISSUE" == "null" ]]; then + echo "No open issue found, creating a new one." + ISSUE_BODY=$(printf '%s\n' \ + "A newer version of the \`helix-p4d\` package is available from the Perforce repository." \ + "" \ + "- Version currently pinned in \`helix-p4d/Dockerfile\`: \`$CURRENT_VERSION\`" \ + "- Available version: \`$LATEST_VERSION\`" \ + "" \ + "The \`apt-get install\` line in the Dockerfile should be updated accordingly (also double-check the \`helix-swarm-triggers\` version if relevant)." \ + "" \ + "Source: https://package.perforce.com/apt/ubuntu/dists/noble/release/binary-amd64/Packages" \ + "" \ + "_This issue was created automatically by the \`check-p4d-version.yml\` workflow._") + + gh issue create \ + --repo "$REPO" \ + --title "helix-p4d: newer version available ($LATEST_VERSION)" \ + --label "$LABEL" \ + --body "$ISSUE_BODY" + exit 0 +fi + +ISSUE_NUMBER=$(echo "$EXISTING_ISSUE" | jq -r '.number') +ISSUE_TEXT=$(echo "$EXISTING_ISSUE" | jq -r '.title + "\n" + .body') + +# Also check existing comments so the same version isn't posted twice +ALREADY_MENTIONED=$(gh issue view "$ISSUE_NUMBER" --repo "$REPO" --json comments --jq '.comments[].body' | grep -F "$LATEST_VERSION" || true) + +if echo "$ISSUE_TEXT" | grep -qF "$LATEST_VERSION" || [[ -n "$ALREADY_MENTIONED" ]]; then + echo "Version $LATEST_VERSION is already mentioned on issue #$ISSUE_NUMBER, nothing to do." + exit 0 +fi + +echo "Issue #$ISSUE_NUMBER is already open for an earlier version, adding a comment." +gh issue comment "$ISSUE_NUMBER" \ + --repo "$REPO" \ + --body "Update: an even newer version is now available: \`$LATEST_VERSION\` (currently pinned version: \`$CURRENT_VERSION\`)." diff --git a/.github/workflows/check-p4d-version.yml b/.github/workflows/check-p4d-version.yml new file mode 100644 index 0000000..935d221 --- /dev/null +++ b/.github/workflows/check-p4d-version.yml @@ -0,0 +1,39 @@ +name: Check helix-p4d Version + +on: + schedule: + # Every Sunday at 20:00 UTC + - cron: '0 20 * * 0' + workflow_dispatch: {} + +permissions: + issues: write + contents: read + +jobs: + check-version: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Extract current pinned version from Dockerfile + id: current + run: bash .github/scripts/p4d-version/get-current-version.sh + + - name: Fetch latest available version from Perforce repo + id: latest + run: bash .github/scripts/p4d-version/get-latest-version.sh + + - name: Compare versions and manage issue + if: steps.current.outputs.version != steps.latest.outputs.version + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CURRENT_VERSION: ${{ steps.current.outputs.version }} + LATEST_VERSION: ${{ steps.latest.outputs.version }} + REPO: ${{ github.repository }} + run: bash .github/scripts/p4d-version/sync-issue.sh + + - name: No update needed + if: steps.current.outputs.version == steps.latest.outputs.version + run: echo "Pinned version (${{ steps.current.outputs.version }}) is already up to date, nothing to do." From 0110d022137c1fdcd33373d536890d3db50ca208 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sat, 15 Aug 2026 22:17:06 +0200 Subject: [PATCH 18/23] Fix for check to run even if change are done outside the working directory --- .github/workflows/docker-build-check.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/docker-build-check.yml b/.github/workflows/docker-build-check.yml index d9d97cc..fc8c232 100644 --- a/.github/workflows/docker-build-check.yml +++ b/.github/workflows/docker-build-check.yml @@ -3,9 +3,6 @@ name: Docker Build Check on: pull_request: branches: [main] - paths: - - 'helix-p4d/**' - - '.github/workflows/docker-build-check.yml' # Cancel any in-progress runs of this workflow for the same pull request number concurrency: From e3c733db3ae8d1bdf06f75348991a1b2c270c1f0 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Sat, 15 Aug 2026 22:22:19 +0200 Subject: [PATCH 19/23] Update workflow to use nodejs 24 instead of 20 --- .github/workflows/check-p4d-version.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/check-p4d-version.yml b/.github/workflows/check-p4d-version.yml index 935d221..c39466d 100644 --- a/.github/workflows/check-p4d-version.yml +++ b/.github/workflows/check-p4d-version.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v7 - name: Extract current pinned version from Dockerfile id: current From a3bc1d83f9e13be6ababc40f32a203a0f4838eff Mon Sep 17 00:00:00 2001 From: M3dinar Date: Mon, 17 Aug 2026 11:56:47 +0200 Subject: [PATCH 20/23] Added workflow release --- .github/scripts/release/create-release-tag.sh | 44 ++++++++++++++ .../scripts/release/validate-and-parse-tag.sh | 59 +++++++++++++++++++ .github/workflows/create-release-tag.yml | 22 +++++++ .github/workflows/release.yml | 50 ++++++++++++++++ README.md | 44 +++++++++++--- helix-p4d/Dockerfile | 5 +- helix-p4d/build.sh | 4 +- 7 files changed, 216 insertions(+), 12 deletions(-) create mode 100644 .github/scripts/release/create-release-tag.sh create mode 100644 .github/scripts/release/validate-and-parse-tag.sh create mode 100644 .github/workflows/create-release-tag.yml create mode 100644 .github/workflows/release.yml diff --git a/.github/scripts/release/create-release-tag.sh b/.github/scripts/release/create-release-tag.sh new file mode 100644 index 0000000..fd74345 --- /dev/null +++ b/.github/scripts/release/create-release-tag.sh @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# Reads the helix-p4d version pinned in the Dockerfile at the current +# commit (main), looks at existing git tags to find the next available +# release number (rX), then creates and pushes an immutable annotated +# tag "-rX" pointing at the current commit. +# +# This tag is what triggers the actual build+push workflow (release.yml). +# Because each rX gets its own dedicated, never-moved git tag, it is +# always possible to trace back which exact commit a given release was +# built from, e.g. `git show 2026.1-2972966-r1`. +set -euo pipefail + +DOCKERFILE="helix-p4d/Dockerfile" + +PERFORCE_VERSION=$(grep -oP 'helix-p4d=\K[^ \\]+' "$DOCKERFILE" | head -1 | sed 's/~.*//') +if [[ -z "$PERFORCE_VERSION" ]]; then + echo "Could not find a pinned helix-p4d version in $DOCKERFILE" >&2 + exit 1 +fi +echo "Perforce version pinned in Dockerfile: $PERFORCE_VERSION" + +git fetch origin --tags --force + +LAST_R=$( (git tag -l "${PERFORCE_VERSION}-r*" \ + | grep -E "^${PERFORCE_VERSION}-r[0-9]+$" \ + | sed -E "s/^${PERFORCE_VERSION}-r([0-9]+)$/\1/" \ + | sort -n | tail -1) || true) + +if [[ -z "$LAST_R" ]]; then + NEXT_R=1 +else + NEXT_R=$((LAST_R + 1)) +fi + +NEW_TAG="${PERFORCE_VERSION}-r${NEXT_R}" +echo "Next release tag: $NEW_TAG" + +git config user.name "github-actions[bot]" +git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + +git tag -a "$NEW_TAG" -m "Release $NEW_TAG" +git push origin "$NEW_TAG" + +echo "Pushed tag $NEW_TAG. This will trigger the release workflow." diff --git a/.github/scripts/release/validate-and-parse-tag.sh b/.github/scripts/release/validate-and-parse-tag.sh new file mode 100644 index 0000000..3410554 --- /dev/null +++ b/.github/scripts/release/validate-and-parse-tag.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# Validates the git tag that triggered this workflow (normally created by +# the "Create Release Tag" workflow) and extracts version info from it. +# Expected format: .--r, e.g. 2026.1-2972966-r2 +# +# Also checks, as defense in depth in case a tag was ever pushed manually +# instead of through the "Create Release Tag" workflow: +# - the tagged commit is an ancestor of main +# - the Perforce version embedded in the tag matches what's pinned in +# the Dockerfile at that commit +# +# Exposes: perforce_version, short_version, release_number, image_name, +# tags (multiline list of docker tags to build & push) +set -euo pipefail + +TAG="${GITHUB_REF_NAME:?GITHUB_REF_NAME is required}" +DOCKERFILE="helix-p4d/Dockerfile" + +if [[ ! "$TAG" =~ ^(([0-9]{4}\.[0-9]+)-([0-9]+))-r([0-9]+)$ ]]; then + echo "Tag '$TAG' does not match the expected .--r format (e.g. 2026.1-2972966-r2)" >&2 + exit 1 +fi + +PERFORCE_VERSION="${BASH_REMATCH[1]}" +SHORT_VERSION="${BASH_REMATCH[2]}" +RELEASE_NUMBER="${BASH_REMATCH[4]}" + +echo "Tag: $TAG" +echo "Perforce version: $PERFORCE_VERSION" +echo "Short version: $SHORT_VERSION" +echo "Release number: r$RELEASE_NUMBER" + +if ! git merge-base --is-ancestor "$GITHUB_SHA" origin/main; then + echo "Commit $GITHUB_SHA (tag $TAG) is not an ancestor of main. Refusing to publish." >&2 + exit 1 +fi + +DOCKERFILE_VERSION=$(grep -oP 'helix-p4d=\K[^ \\]+' "$DOCKERFILE" | head -1 | sed 's/~.*//') +if [[ "$DOCKERFILE_VERSION" != "$PERFORCE_VERSION" ]]; then + echo "Tag ($PERFORCE_VERSION) does not match the version pinned in $DOCKERFILE at this commit ($DOCKERFILE_VERSION)" >&2 + exit 1 +fi + +OWNER_LOWER=$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]') +IMAGE_NAME="ghcr.io/${OWNER_LOWER}/helix-p4d" +CREATED=$(date -u +%Y-%m-%dT%H:%M:%SZ) + +{ + echo "perforce_version=$PERFORCE_VERSION" + echo "short_version=$SHORT_VERSION" + echo "release_number=$RELEASE_NUMBER" + echo "image_name=$IMAGE_NAME" + echo "created=$CREATED" + echo "tags<> "$GITHUB_OUTPUT" diff --git a/.github/workflows/create-release-tag.yml b/.github/workflows/create-release-tag.yml new file mode 100644 index 0000000..1159899 --- /dev/null +++ b/.github/workflows/create-release-tag.yml @@ -0,0 +1,22 @@ +name: Create Release Tag + +on: + workflow_dispatch: {} + +permissions: + contents: write + +jobs: + tag: + runs-on: ubuntu-latest + steps: + # Always operate on main regardless of which branch was selected + # in the "Run workflow" dropdown. + - name: Checkout main + uses: actions/checkout@v7 + with: + ref: main + fetch-depth: 0 + + - name: Create and push release tag + run: bash .github/scripts/release/create-release-tag.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..cf9a33d --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,50 @@ +name: Release Docker Image + +on: + push: + tags: + - '[0-9]*.[0-9]*-[0-9]*-r[0-9]*' + +permissions: + contents: read + packages: write + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Ensure main history is available + run: git fetch origin main:refs/remotes/origin/main + + - name: Validate tag and extract version info + id: version + run: bash .github/scripts/release/validate-and-parse-tag.sh + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 + + - name: Build and push image + uses: docker/build-push-action@v7 + with: + context: ./helix-p4d + platforms: linux/amd64 + push: true + tags: ${{ steps.version.outputs.tags }} + labels: | + org.opencontainers.image.revision=${{ github.sha }} + org.opencontainers.image.version=${{ github.ref_name }} + org.opencontainers.image.created=${{ steps.version.outputs.created }} + cache-from: type=gha + cache-to: type=gha,mode=max \ No newline at end of file diff --git a/README.md b/README.md index 12d02ea..97b919d 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,23 @@ This repository contains a collection of source files for building Docker images ## helix-p4d -This directory contains the source files for building a Perforce Helix core server Docker image. The published Docker images are available as [`sourcegraph/helix-p4d` on Docker Hub](https://hub.docker.com/r/sourcegraph/helix-p4d). +This directory contains the source files for building a Perforce Helix core server Docker image. The published Docker images are available as [`ghcr.io/m3dinar/helix-p4d` on the GitHub Container Registry](https://github.com/M3dinar/helix-docker/pkgs/container/helix-p4d). + +### Available tags + +Every release publishes three tags: + +- `latest` — always the most recently published image +- `.` (e.g. `2026.1`) — always the most recent build for that Perforce release, regardless of the underlying build number +- `.--r` (e.g. `2026.1-2972966-r2`) — the exact, immutable version. `.-` is the Perforce package version pinned in [`helix-p4d/Dockerfile`](helix-p4d/Dockerfile); `rN` is incremented every time the image is rebuilt and republished for that same Perforce version (e.g. following a fix unrelated to the Perforce version itself). Each `rN` corresponds to a dedicated, never-moved git tag of the same name, so the exact commit an image was built from can always be found with: + + ```sh + git show .--rN + ``` + +```sh +docker pull ghcr.io/m3dinar/helix-p4d:latest +``` ### Default server configuration @@ -14,7 +30,7 @@ This directory contains the source files for building a Perforce Helix core serv ### Build the docker image -The `helix-p4d/build.sh` script will build the docker image for you. If you don't provide a tag to the script it will tag the image as `sourcegraph/helix-p4d:latest` +The `helix-p4d/build.sh` script will build the docker image for you. If you don't provide a tag to the script it will tag the image as `ghcr.io/m3dinar/helix-p4d:latest` ``` ./build.sh @@ -27,7 +43,7 @@ To have a disposable Perforce Helix core server running, simply do: ```sh docker run --rm \ --publish 1666:1666 \ - sourcegraph/helix-p4d:latest + ghcr.io/m3dinar/helix-p4d:latest ``` The above command makes the server avaialble locally at `:1666`, with a default super user `admin` and its password `pass12349ers`. @@ -53,7 +69,7 @@ docker run --rm \ --publish 1666:1666 \ --env P4USER=amy \ --env P4PASSWD=securepassword \ - sourcegraph/helix-p4d:latest + ghcr.io/m3dinar/helix-p4d:latest ``` > [!WARNING] @@ -71,10 +87,10 @@ docker run -d \ --publish 1666:1666 \ --env P4PASSWD=securepassword \ --volume ~/.helix-p4d-home:/p4 \ - sourcegraph/helix-p4d:latest + ghcr.io/m3dinar/helix-p4d:latest ``` -Now you have a running server, please read our handbook for [how to set up the client side](https://handbook.sourcegraph.com/departments/technical-success/support/process/p4-enablement/). +Now you have a running server, you can set up a Perforce client (`p4`/`p4v`) pointed at `:1666` using the credentials above. ### Running Perforce Helix with SSL enabled @@ -98,7 +114,7 @@ docker run --rm \ --env P4PORT=ssl:1666 \ --env P4SSLDIR=/ssl \ --volume ./ssl:/ssl \ - sourcegraph/helix-p4d:2023.1 + ghcr.io/m3dinar/helix-p4d:2026.1 ``` ### Restore from a checkpoint @@ -108,6 +124,18 @@ Create a simlink to the gz file named latest in the folder `$P4CKP` Run the container, it will generate the DB from the checkpoint and remove the sym link. The gz can be removed once you're good with it. Triggers are removed. +## CI / Release process + +This repository uses GitHub Actions for three things: + +- **Build check on pull requests** (`.github/workflows/docker-build-check.yml`): every PR targeting `main` builds the `helix-p4d` image (without pushing it). Merging is blocked on `main` if the build fails. +- **Weekly Perforce version check** (`.github/workflows/check-p4d-version.yml`): every Sunday, compares the `helix-p4d` version pinned in the Dockerfile against the latest one available from Perforce. If a newer version exists, it opens (or updates) a tracking issue labeled `p4d-update`. +- **Release** (`.github/workflows/create-release-tag.yml` + `.github/workflows/release.yml`): publishing a new image is a two-step, manually-triggered process: + 1. Run the **"Create Release Tag"** workflow (`Actions` tab → select it → `Run workflow`). It reads the version currently pinned in the Dockerfile on `main`, works out the next available release number, and pushes an immutable git tag `.--r` (e.g. `2026.1-2972966-r2`) on the current `main` commit. + 2. That tag push automatically triggers the **"Release Docker Image"** workflow, which builds and publishes the image to GHCR under three tags: the full tag, `latest`, and `.`. + +Because every `rN` is its own dedicated git tag that never moves, the exact commit an image was built from can always be found with `git show `. + ## Credits This repository is heavily inspired by https://github.com/p4paul/helix-docker and https://github.com/ambakshi/docker-perforce @@ -125,4 +153,4 @@ The fork was done to allow some changes - Unified the use of the setup in each case to configure and start the server - Use of p4dctl - Fixes - - Charset when there is no one selected + - Charset when there is no one selected \ No newline at end of file diff --git a/helix-p4d/Dockerfile b/helix-p4d/Dockerfile index 36c57d2..b13a0f9 100644 --- a/helix-p4d/Dockerfile +++ b/helix-p4d/Dockerfile @@ -4,8 +4,9 @@ # Ubuntu noble and 24.04 are the same, but noble is the codename for 24.04 FROM ubuntu:24.04 -LABEL vendor="Sourcegraph" -LABEL maintainer="Joe Chen (joe@sourcegraph.com)" +LABEL org.opencontainers.image.source="https://github.com/M3dinar/helix-docker" +LABEL org.opencontainers.image.description="Perforce Helix Core (p4d) server, packaged for Docker." +LABEL org.opencontainers.image.authors="M3dinar " RUN apt-get update && \ apt-get install -y wget gnupg2 diff --git a/helix-p4d/build.sh b/helix-p4d/build.sh index ef4be39..5b4af22 100755 --- a/helix-p4d/build.sh +++ b/helix-p4d/build.sh @@ -5,7 +5,7 @@ set -e tag=$1 if [[ -z "$tag" ]]; then - tag="sourcegraph/helix-p4d:latest" + tag="ghcr.io/m3dinar/helix-p4d:latest" fi -docker build -t ${tag} --platform linux/amd64 . +docker build -t ${tag} --platform linux/amd64 . \ No newline at end of file From 44e243d72a7e77285486f33a3114807a3984b224 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Mon, 17 Aug 2026 12:26:40 +0200 Subject: [PATCH 21/23] Fixed the fact that GH does not trig workflow based on tag when the tag is pushed by GH itself --- .github/scripts/release/create-release-tag.sh | 3 ++- .github/workflows/create-release-tag.yml | 11 +++++++++++ .github/workflows/release.yml | 6 ++++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/scripts/release/create-release-tag.sh b/.github/scripts/release/create-release-tag.sh index fd74345..e633c2d 100644 --- a/.github/scripts/release/create-release-tag.sh +++ b/.github/scripts/release/create-release-tag.sh @@ -41,4 +41,5 @@ git config user.email "41898282+github-actions[bot]@users.noreply.github.com" git tag -a "$NEW_TAG" -m "Release $NEW_TAG" git push origin "$NEW_TAG" -echo "Pushed tag $NEW_TAG. This will trigger the release workflow." +echo "tag=$NEW_TAG" >> "$GITHUB_OUTPUT" +echo "Pushed tag $NEW_TAG. Triggering the release workflow explicitly next." diff --git a/.github/workflows/create-release-tag.yml b/.github/workflows/create-release-tag.yml index 1159899..1de41da 100644 --- a/.github/workflows/create-release-tag.yml +++ b/.github/workflows/create-release-tag.yml @@ -19,4 +19,15 @@ jobs: fetch-depth: 0 - name: Create and push release tag + id: tag run: bash .github/scripts/release/create-release-tag.sh + + - name: Trigger release workflow for the new tag + env: + GH_TOKEN: ${{ github.token }} + run: | + gh api \ + --method POST \ + -H "Accept: application/vnd.github+json" \ + /repos/${{ github.repository }}/actions/workflows/release.yml/dispatches \ + -f ref="${{ steps.tag.outputs.tag }}" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index cf9a33d..eeb48c9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -4,6 +4,12 @@ on: push: tags: - '[0-9]*.[0-9]*-[0-9]*-r[0-9]*' + workflow_dispatch: + inputs: + tag: + description: Tag to release + required: true + type: string permissions: contents: read From 0072a69a2b2bf25fd814710ba3624c421aa5c31d Mon Sep 17 00:00:00 2001 From: M3dinar Date: Mon, 17 Aug 2026 12:41:44 +0200 Subject: [PATCH 22/23] Removed dispatch workflow and merge workflow for a more simple approach. --- ...=> create-release-tag-and-build-image.yml} | 30 +++++++++-------- .github/workflows/create-release-tag.yml | 33 ------------------- 2 files changed, 16 insertions(+), 47 deletions(-) rename .github/workflows/{release.yml => create-release-tag-and-build-image.yml} (65%) delete mode 100644 .github/workflows/create-release-tag.yml diff --git a/.github/workflows/release.yml b/.github/workflows/create-release-tag-and-build-image.yml similarity index 65% rename from .github/workflows/release.yml rename to .github/workflows/create-release-tag-and-build-image.yml index eeb48c9..91d4f0a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/create-release-tag-and-build-image.yml @@ -1,34 +1,36 @@ -name: Release Docker Image +name: Create Release Tag and Build Image on: - push: - tags: - - '[0-9]*.[0-9]*-[0-9]*-r[0-9]*' - workflow_dispatch: - inputs: - tag: - description: Tag to release - required: true - type: string + workflow_dispatch: {} permissions: - contents: read + contents: write packages: write jobs: release: runs-on: ubuntu-latest steps: - - name: Checkout + # Always operate on main regardless of which branch was selected + # in the "Run workflow" dropdown. + - name: Checkout main uses: actions/checkout@v7 with: + ref: main fetch-depth: 0 + - name: Create and push release tag + id: tag + run: bash .github/scripts/release/create-release-tag.sh + - name: Ensure main history is available run: git fetch origin main:refs/remotes/origin/main - name: Validate tag and extract version info id: version + env: + GITHUB_REF_NAME: ${{ steps.tag.outputs.tag }} + GITHUB_SHA: ${{ github.sha }} run: bash .github/scripts/release/validate-and-parse-tag.sh - name: Log in to GitHub Container Registry @@ -50,7 +52,7 @@ jobs: tags: ${{ steps.version.outputs.tags }} labels: | org.opencontainers.image.revision=${{ github.sha }} - org.opencontainers.image.version=${{ github.ref_name }} + org.opencontainers.image.version=${{ steps.tag.outputs.tag }} org.opencontainers.image.created=${{ steps.version.outputs.created }} cache-from: type=gha - cache-to: type=gha,mode=max \ No newline at end of file + cache-to: type=gha,mode=max diff --git a/.github/workflows/create-release-tag.yml b/.github/workflows/create-release-tag.yml deleted file mode 100644 index 1de41da..0000000 --- a/.github/workflows/create-release-tag.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: Create Release Tag - -on: - workflow_dispatch: {} - -permissions: - contents: write - -jobs: - tag: - runs-on: ubuntu-latest - steps: - # Always operate on main regardless of which branch was selected - # in the "Run workflow" dropdown. - - name: Checkout main - uses: actions/checkout@v7 - with: - ref: main - fetch-depth: 0 - - - name: Create and push release tag - id: tag - run: bash .github/scripts/release/create-release-tag.sh - - - name: Trigger release workflow for the new tag - env: - GH_TOKEN: ${{ github.token }} - run: | - gh api \ - --method POST \ - -H "Accept: application/vnd.github+json" \ - /repos/${{ github.repository }}/actions/workflows/release.yml/dispatches \ - -f ref="${{ steps.tag.outputs.tag }}" From 7c92f5cf95a7753b2706c62edceeadb311661834 Mon Sep 17 00:00:00 2001 From: M3dinar Date: Mon, 17 Aug 2026 12:54:58 +0200 Subject: [PATCH 23/23] Fixed use of GITHUB default env when creating tag workflow --- .github/scripts/release/validate-and-parse-tag.sh | 7 ++++++- .github/workflows/create-release-tag-and-build-image.yml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/scripts/release/validate-and-parse-tag.sh b/.github/scripts/release/validate-and-parse-tag.sh index 3410554..9d083c8 100644 --- a/.github/scripts/release/validate-and-parse-tag.sh +++ b/.github/scripts/release/validate-and-parse-tag.sh @@ -13,9 +13,14 @@ # tags (multiline list of docker tags to build & push) set -euo pipefail -TAG="${GITHUB_REF_NAME:?GITHUB_REF_NAME is required}" +TAG="${RELEASE_TAG:-${GITHUB_REF_NAME:-}}" DOCKERFILE="helix-p4d/Dockerfile" +if [[ -z "$TAG" ]]; then + echo "No release tag provided. Set RELEASE_TAG for workflows triggered manually; tag-triggered workflows use GITHUB_REF_NAME." >&2 + exit 1 +fi + if [[ ! "$TAG" =~ ^(([0-9]{4}\.[0-9]+)-([0-9]+))-r([0-9]+)$ ]]; then echo "Tag '$TAG' does not match the expected .--r format (e.g. 2026.1-2972966-r2)" >&2 exit 1 diff --git a/.github/workflows/create-release-tag-and-build-image.yml b/.github/workflows/create-release-tag-and-build-image.yml index 91d4f0a..45ef59f 100644 --- a/.github/workflows/create-release-tag-and-build-image.yml +++ b/.github/workflows/create-release-tag-and-build-image.yml @@ -29,7 +29,7 @@ jobs: - name: Validate tag and extract version info id: version env: - GITHUB_REF_NAME: ${{ steps.tag.outputs.tag }} + RELEASE_TAG: ${{ steps.tag.outputs.tag }} GITHUB_SHA: ${{ github.sha }} run: bash .github/scripts/release/validate-and-parse-tag.sh