diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..4d7f17b4 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,32 @@ +version: 2 + +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "sunday" + groups: + all-github-actions: + patterns: + - "*" + + - package-ecosystem: "docker" + directory: "/src" + schedule: + interval: "weekly" + day: "sunday" + groups: + all-docker: + patterns: + - "*" + + - package-ecosystem: "go-mod" + directory: "/src" + schedule: + interval: "weekly" + day: "sunday" + groups: + all-go-mod: + patterns: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a0b0e27f..c9b5a5a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,7 +29,7 @@ jobs: build_docker_image: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Build Docker run: | source ./tool.sh @@ -39,7 +39,7 @@ jobs: sed -i -E -e "s/v[0-9]+\.[0-9]+\.[0-9]+/${VERSION}/" -e "s/GIT_COMMIT_ID/${COMMIT_SHA}/" src/supervisord/version.go build_image_no_tag supervisord "alpine-${VER}" src/supervisord.Dockerfile --build-arg "BASE_NAMESPACE=library" --build-arg "BUILD_IMG=golang:alpine" --build-arg "BASE_IMG=alpine" - build_image_no_tag supervisord "ubuntu-${VER}" src/supervisord.Dockerfile --build-arg "BASE_NAMESPACE=labnow" --build-arg "BUILD_IMG=go:latest" --build-arg "BASE_IMG=ubuntu" + build_image_no_tag supervisord "ubuntu-${VER}" src/supervisord.Dockerfile --build-arg "BASE_NAMESPACE=labnow" --build-arg "BUILD_IMG=go:latest" --build-arg "BASE_IMG=ubuntu" docker tag "${IMG_PREFIX_DST}/supervisord:ubuntu-${VER}" "${IMG_PREFIX_DST}/supervisord:ubuntu" docker tag "${IMG_PREFIX_DST}/supervisord:alpine-${VER}" "${IMG_PREFIX_DST}/supervisord:alpine" push_image supervisord @@ -47,11 +47,11 @@ jobs: build_binary: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: - go-version: 1.26 + go-version: "stable" # 1.26 - name: Build Binary run: | set -eux @@ -70,11 +70,11 @@ jobs: build_goreleaser: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@v6 with: - go-version: 1.26 + go-version: "stable" # 1.26 - name: Install cross-compiler for linux/arm64, UPX env: diff --git a/README.md b/README.md index e8819365..172e03f4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ # Go Implementation of Supervisord +[![License](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/licenses/MIT-Clause) [![Go Report Card](https://goreportcard.com/badge/github.com/LabNow-ai/supervisord)](https://goreportcard.com/report/github.com/LabNow-ai/supervisord) +[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/LabNow-ai/supervisord/ci.yml?branch=main)](https://github.com/LabNow-ai/supervisord/actions/workflows/ci.yml) +[![Recent Code Update](https://img.shields.io/github/last-commit/LabNow-ai/supervisord.svg)](https://github.com/LabNow-ai/supervisord/stargazers) +[![Visit Images on DockerHub](https://img.shields.io/badge/DockerHub-Images-green)](https://hub.docker.com/u/labnow) + +Please generously STAR★ our project or donate to us! [![GitHub Starts](https://img.shields.io/github/stars/LabNow-ai/supervisord.svg?label=Stars)](https://github.com/LabNow-ai/supervisord/stargazers) + +Discussion and contributions are welcome: +[![Join the Discord Chat](https://img.shields.io/badge/Discuss_on-Discord-green)](https://discord.gg/kHUzgQxgbJ) +[![Open an Issue on GitHub](https://img.shields.io/github/issues/LabNow-ai/supervisord)](https://github.com/LabNow-ai/supervisord/issues) ## Why this project? diff --git a/src/supervisord/assets.go b/src/supervisord/assets.go index 8b9c53fb..1e958ffe 100644 --- a/src/supervisord/assets.go +++ b/src/supervisord/assets.go @@ -74,7 +74,7 @@ func newZipFS(r *zip.Reader) *zipFS { continue } z.files[name] = f - // populate parent directories + // populate parent directories with direct child entries only dir := path.Dir(name) if dir == "." { dir = "" diff --git a/src/supervisord/go.mod b/src/supervisord/go.mod index b36f2771..a7a95183 100644 --- a/src/supervisord/go.mod +++ b/src/supervisord/go.mod @@ -16,7 +16,7 @@ require ( github.com/ochinchina/gorilla-xmlrpc v0.0.0-20171012055324-ecf2fe693a2c github.com/prometheus/client_golang v1.12.2 github.com/robfig/cron/v3 v3.0.0 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.1 ) require ( @@ -31,6 +31,6 @@ require ( github.com/rogpeppe/go-charset v0.0.0-20190617161244-0dc95cdf6f31 // indirect github.com/stretchr/testify v1.7.1 // indirect golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect - google.golang.org/protobuf v1.28.0 // indirect - gopkg.in/yaml.v3 v3.0.0 // indirect + google.golang.org/protobuf v1.33.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/src/supervisord/webgui/index.html b/src/supervisord/webgui/index.html index 27b6b188..23f88a38 100644 --- a/src/supervisord/webgui/index.html +++ b/src/supervisord/webgui/index.html @@ -5,6 +5,6 @@ Go-Supervisor - Specify environment variable STATIC_DIR or STATIC_ZIP when staring supervisord to serve static assets, or use APIs /program/{list|start|stop} to operate supervisord. + Specify environment variable STATIC_DIR or STATIC_ZIP when starting supervisord to serve static assets, or use APIs /program/{list|start|stop} to operate supervisord. diff --git a/tool.sh b/tool.sh index 67aeff0e..7957084c 100644 --- a/tool.sh +++ b/tool.sh @@ -1,48 +1,53 @@ #!/bin/bash -set -xu +set -eux CI_PROJECT_NAME=${CI_PROJECT_NAME:-$GITHUB_REPOSITORY} CI_PROJECT_BRANCH=${GITHUB_HEAD_REF:-"main"} CI_PROJECT_SPACE=$(echo "${CI_PROJECT_BRANCH}" | cut -f1 -d'/') -if [ "${CI_PROJECT_BRANCH}" = "main" ] ; then - # If on the main branch, docker images namespace will be same as CI_PROJECT_NAME's name space - export CI_PROJECT_NAMESPACE="$(dirname ${CI_PROJECT_NAME})" ; -else - # not main branch, docker namespace = {CI_PROJECT_NAME's name space} + "-" + {1st substr before / in CI_PROJECT_SPACE} - export CI_PROJECT_NAMESPACE="$(dirname ${CI_PROJECT_NAME})0${CI_PROJECT_SPACE}" ; -fi +# If on the main branch, image namespace will be same as CI_PROJECT_NAME's name space; +# else (not main branch), image namespace = {CI_PROJECT_NAME's name space} + "0" + {1st substr before / in CI_PROJECT_SPACE}. +[ "${CI_PROJECT_BRANCH}" = "main" ] && NAMESPACE_SUFFIX="" || NAMESPACE_SUFFIX="0${CI_PROJECT_SPACE}" ; +export CI_PROJECT_NAMESPACE="$(dirname ${CI_PROJECT_NAME})${NAMESPACE_SUFFIX}" ; -export SRC_NAMESPACE="${REGISTRY_SRC:-docker.io}" -export IMG_PREFIX_DST=$(echo "${REGISTRY_DST:-"docker.io"}/${CI_PROJECT_NAMESPACE}" | awk '{print tolower($0)}') +export IMG_NAMESPACE=$(echo "${CI_PROJECT_NAMESPACE}" | awk '{print tolower($0)}') +export IMG_PREFIX_SRC=$(echo "${REGISTRY_SRC:-"docker.io"}/${IMG_NAMESPACE}" | awk '{print tolower($0)}') +export IMG_PREFIX_DST=$(echo "${REGISTRY_DST:-"docker.io"}/${IMG_NAMESPACE}" | awk '{print tolower($0)}') export TAG_SUFFIX="-$(git rev-parse --short HEAD)" -echo "--------> CI_PROJECT_NAMESPACE=${CI_PROJECT_NAMESPACE}" # use different namespace for dev/prd -echo "--------> DOCKER_SRC_NAMESPACE=${SRC_NAMESPACE}" +echo "--------> CI_PROJECT_NAMESPACE=${CI_PROJECT_NAMESPACE}" +echo "--------> DOCKER_IMG_NAMESPACE=${IMG_NAMESPACE}" +echo "--------> DOCKER_IMG_PREFIX_SRC=${IMG_PREFIX_SRC}" echo "--------> DOCKER_IMG_PREFIX_DST=${IMG_PREFIX_DST}" echo "--------> DOCKER_TAG_SUFFIX=${TAG_SUFFIX}" -[ ! -f /etc/docker/daemon.json ] && sudo tee /etc/docker/daemon.json > /dev/null <<< '{}' -jq '.experimental=true | ."data-root"="/mnt/docker"' /etc/docker/daemon.json > /tmp/daemon.json && sudo mv /tmp/daemon.json /etc/docker/ -( sudo service docker restart || true ) && cat /etc/docker/daemon.json && docker info build_image() { echo "$@" ; IMG=$1; TAG=$2; FILE=$3; shift 3; VER=$(date +%Y.%m%d.%H%M)${TAG_SUFFIX}; WORKDIR="$(pwd)"; - docker build --compress --force-rm=true -t "${IMG_PREFIX_DST}/${IMG}:${TAG}" -f "$FILE" --build-arg "BASE_NAMESPACE=${SRC_NAMESPACE}" "$@" "${WORKDIR}" ; - docker tag "${IMG_PREFIX_DST}/${IMG}:${TAG}" "${IMG_PREFIX_DST}/${IMG}:${VER}" ; + docker build --compress --force-rm=true -t "${IMG_PREFIX_DST}/${IMG}:${TAG}" -f "$FILE" --build-arg "BASE_NAMESPACE=${IMG_PREFIX_SRC}" "$@" "${WORKDIR}" + docker tag "${IMG_PREFIX_DST}/${IMG}:${TAG}" "${IMG_PREFIX_DST}/${IMG}:${VER}" + echo "${IMG_PREFIX_DST}/${IMG}:${TAG}" } build_image_no_tag() { echo "$@" ; IMG=$1; TAG=$2; FILE=$3; shift 3; WORKDIR="$(pwd)"; - docker build --compress --force-rm=true -t "${IMG_PREFIX_DST}/${IMG}:${TAG}" -f "$FILE" --build-arg "BASE_NAMESPACE=${SRC_NAMESPACE}" "$@" "${WORKDIR}" ; + docker build --compress --force-rm=true -t "${IMG_PREFIX_DST}/${IMG}:${TAG}" -f "$FILE" --build-arg "BASE_NAMESPACE=${IMG_PREFIX_SRC}" "$@" "${WORKDIR}" + echo "${IMG_PREFIX_DST}/${IMG}:${TAG}" +} + +alias_image() { + IMG_1=$1; TAG_1=$2; IMG_2=$3; TAG_2=$4; shift 4; VER=$(date +%Y.%m%d.%H%M)${TAG_SUFFIX}; + docker tag "${IMG_PREFIX_DST}/${IMG_1}:${TAG_1}" "${IMG_PREFIX_DST}/${IMG_2}:${TAG_2}" + docker tag "${IMG_PREFIX_DST}/${IMG_2}:${TAG_2}" "${IMG_PREFIX_DST}/${IMG_2}:${VER}" } push_image() { KEYWORD="${1:-second}"; docker image prune --force && docker images | sort; - IMAGES=$(docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.CreatedSince}}" | grep "${KEYWORD}" | awk '{print $1 ":" $2}') ; + IMAGES=$(docker images --format "{{.Repository}}\t{{.Tag}}\t{{.CreatedSince}}" | grep "${KEYWORD}" | awk '{print $1 ":" $2}') ; + [ -n "${IMAGES}" ] || { echo "!! No images matched keyword: ${KEYWORD}"; return 1; } echo "$DOCKER_REGISTRY_PASSWORD" | docker login "${REGISTRY_DST}" -u "$DOCKER_REGISTRY_USERNAME" --password-stdin ; for IMG in $(echo "${IMAGES}" | tr " " "\n") ; do @@ -53,24 +58,37 @@ push_image() { } clear_images() { - KEYWORD=${1:-'days ago\|weeks ago\|months ago\|years ago'}; # if no keyword is provided, clear all images build days ago + KEYWORD=${1:-'days ago\|weeks ago\|months ago\|years ago'}; # if no keyword is provided, clear all images built days ago IMGS_1=$(docker images | grep "${KEYWORD}" | awk '{print $1 ":" $2}') ; IMGS_2=$(docker images | grep "${KEYWORD}" | awk '{print $3}') ; for IMG in $(echo "$IMGS_1 $IMGS_2" | tr " " "\n") ; do - docker rmi "${IMG}" || true; status=$?; echo "[${status}] image removed > ${IMG}"; + docker rmi "${IMG}" ; status=$?; echo "[${status}] image removed > ${IMG}"; done docker image prune --force && docker images ; } remove_folder() { - sudo du -h -d1 "$1" || true ; - sudo rm -rf "$1" || true ; + for dir in "$@"; do + if [ -d "$dir" ]; then + echo "Removing folder: $dir" ; + sudo du -h -d1 "$dir" || true ; + sudo rm -rf "$dir" || true ; + else + echo "Warn: directory not found: $dir" ; + fi + done } free_diskspace() { - remove_folder /usr/share/dotnet - remove_folder /usr/local/lib/android - df -h + remove_folder /usr/share/dotnet ; # /usr/local/lib/android /var/lib/docker + df -h ; +} + +setup_github_actions() { + [ ! -f /etc/docker/daemon.json ] && sudo tee /etc/docker/daemon.json > /dev/null <<< '{}' ; + jq '.experimental=true | ."data-root"="/mnt/docker"' /etc/docker/daemon.json > /tmp/daemon.json && sudo mv /tmp/daemon.json /etc/docker/ ; + ( sudo service docker restart || true ) && cat /etc/docker/daemon.json && docker info ; } +[ "$GITHUB_ACTIONS" = "true" ] && echo "Running in GitHub Actions and Setup Env: $(setup_github_actions)"