diff --git a/.github/workflows/external_trigger.yml b/.github/workflows/external_trigger.yml index a42509a..6a2cd94 100644 --- a/.github/workflows/external_trigger.yml +++ b/.github/workflows/external_trigger.yml @@ -29,7 +29,7 @@ jobs: echo "> [!NOTE]" >> $GITHUB_STEP_SUMMARY echo "> External trigger running off of main branch. To disable this trigger, add \`unifi-network-application_main\` into the Github organizational variable \`SKIP_EXTERNAL_TRIGGER\`." >> $GITHUB_STEP_SUMMARY printf "\n## Retrieving external version\n\n" >> $GITHUB_STEP_SUMMARY - EXT_RELEASE=$(curl -sX GET https://dl.ui.com/unifi/debian/dists/stable/ubiquiti/binary-amd64/Packages.gz | gunzip | grep -A 7 -m 1 'Package: unifi' | awk -F ': ' '/Version/{print $2;exit}' | awk -F '-' '{print $1}') + EXT_RELEASE=$(curl -sX GET 'https://fw-update.ubnt.com/api/firmware-latest?filter=eq~~product~~unifi-controller&filter=eq~~platform~~unix&filter=eq~~channel~~release' | jq -r '._embedded.firmware[].version' | awk -F '+' '{print $1}') echo "Type is \`custom_version_command\`" >> $GITHUB_STEP_SUMMARY if grep -q "^unifi-network-application_main_${EXT_RELEASE}" <<< "${SKIP_EXTERNAL_TRIGGER}"; then echo "> [!WARNING]" >> $GITHUB_STEP_SUMMARY diff --git a/Dockerfile b/Dockerfile index 9080f1d..676cee2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,7 +10,6 @@ LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DA LABEL maintainer="thespad" # environment settings -ARG UNIFI_BRANCH="stable" ENV DEBIAN_FRONTEND="noninteractive" RUN \ @@ -23,16 +22,16 @@ RUN \ unzip && \ echo "**** install unifi ****" && \ if [ -z ${UNIFI_VERSION+x} ]; then \ - UNIFI_VERSION=$(curl -sX GET https://dl.ui.com/unifi/debian/dists/${UNIFI_BRANCH}/ubiquiti/binary-amd64/Packages.gz \ - | gunzip \ - | grep -A 7 -m 1 'Package: unifi' \ - | awk -F ': ' '/Version/{print $2;exit}' \ - | awk -F '-' '{print $1}'); \ + UNIFI_VERSION=$(curl -sX GET "https://fw-update.ubnt.com/api/firmware-latest?filter=eq~~product~~unifi-controller&filter=eq~~platform~~unix&filter=eq~~channel~~release" \ + | jq -r '._embedded.firmware[].version' \ + | awk -F '+' '{print $1}'); \ fi && \ + UNIFI_DOWNLOAD=$(curl -sX GET "https://fw-update.ubnt.com/api/firmware?filter=eq~~product~~unifi-controller&filter=eq~~platform~~unix&filter=eq~~channel~~release&sort=-version" \ + | jq -r "._embedded.firmware[] | select(.version | test(\"${UNIFI_VERSION}\")) | ._links.data.href") && \ mkdir -p /app && \ curl -o \ /tmp/unifi.zip -L \ - "https://dl.ui.com/unifi/${UNIFI_VERSION}/UniFi.unix.zip" && \ + "${UNIFI_DOWNLOAD}" && \ unzip /tmp/unifi.zip -d /usr/lib && \ mv /usr/lib/UniFi /usr/lib/unifi && \ printf "Linuxserver.io version: ${VERSION}\nBuild-date: ${BUILD_DATE}" > /build_version && \ diff --git a/Dockerfile.aarch64 b/Dockerfile.aarch64 index 2909319..b1fedef 100644 --- a/Dockerfile.aarch64 +++ b/Dockerfile.aarch64 @@ -10,7 +10,6 @@ LABEL build_version="Linuxserver.io version:- ${VERSION} Build-date:- ${BUILD_DA LABEL maintainer="thespad" # environment settings -ARG UNIFI_BRANCH="stable" ENV DEBIAN_FRONTEND="noninteractive" RUN \ @@ -23,16 +22,16 @@ RUN \ unzip && \ echo "**** install unifi ****" && \ if [ -z ${UNIFI_VERSION+x} ]; then \ - UNIFI_VERSION=$(curl -sX GET https://dl.ui.com/unifi/debian/dists/${UNIFI_BRANCH}/ubiquiti/binary-amd64/Packages.gz \ - | gunzip \ - | grep -A 7 -m 1 'Package: unifi' \ - | awk -F ': ' '/Version/{print $2;exit}' \ - | awk -F '-' '{print $1}'); \ + UNIFI_VERSION=$(curl -sX GET "https://fw-update.ubnt.com/api/firmware-latest?filter=eq~~product~~unifi-controller&filter=eq~~platform~~unix&filter=eq~~channel~~release" \ + | jq -r '._embedded.firmware[].version' \ + | awk -F '+' '{print $1}'); \ fi && \ + UNIFI_DOWNLOAD=$(curl -sX GET "https://fw-update.ubnt.com/api/firmware?filter=eq~~product~~unifi-controller&filter=eq~~platform~~unix&filter=eq~~channel~~release&sort=-version" \ + | jq -r "._embedded.firmware[] | select(.version | test(\"${UNIFI_VERSION}\")) | ._links.data.href") && \ mkdir -p /app && \ curl -o \ /tmp/unifi.zip -L \ - "https://dl.ui.com/unifi/${UNIFI_VERSION}/UniFi.unix.zip" && \ + "${UNIFI_DOWNLOAD}" && \ unzip /tmp/unifi.zip -d /usr/lib && \ mv /usr/lib/UniFi /usr/lib/unifi && \ printf "Linuxserver.io version: ${VERSION}\nBuild-date: ${BUILD_DATE}" > /build_version && \ diff --git a/Jenkinsfile b/Jenkinsfile index 4efb609..e902ae8 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -147,7 +147,7 @@ pipeline { steps{ script{ env.EXT_RELEASE = sh( - script: ''' curl -sX GET https://dl.ui.com/unifi/debian/dists/stable/ubiquiti/binary-amd64/Packages.gz | gunzip | grep -A 7 -m 1 'Package: unifi' | awk -F ': ' '/Version/{print $2;exit}' | awk -F '-' '{print $1}' ''', + script: ''' curl -sX GET 'https://fw-update.ubnt.com/api/firmware-latest?filter=eq~~product~~unifi-controller&filter=eq~~platform~~unix&filter=eq~~channel~~release' | jq -r '._embedded.firmware[].version' | awk -F '+' '{print $1}' ''', returnStdout: true).trim() env.RELEASE_LINK = 'custom_command' } @@ -208,6 +208,7 @@ pipeline { env.META_TAG = env.EXT_RELEASE_CLEAN + '-ls' + env.LS_TAG_NUMBER env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'latest' } } } @@ -233,6 +234,7 @@ pipeline { env.EXT_RELEASE_TAG = 'version-' + env.EXT_RELEASE_CLEAN env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.DEV_DOCKERHUB_IMAGE + '/tags/' env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'develop' } } } @@ -258,6 +260,7 @@ pipeline { env.CODE_URL = 'https://github.com/' + env.LS_USER + '/' + env.LS_REPO + '/pull/' + env.PULL_REQUEST env.DOCKERHUB_LINK = 'https://hub.docker.com/r/' + env.PR_DOCKERHUB_IMAGE + '/tags/' env.BUILDCACHE = 'docker.io/lsiodev/buildcache,registry.gitlab.com/linuxserver.io/docker-jenkins-builder/lsiodev-buildcache,ghcr.io/linuxserver/lsiodev-buildcache,quay.io/linuxserver.io/lsiodev-buildcache' + env.CITEST_IMAGETAG = 'develop' } } } @@ -280,7 +283,7 @@ pipeline { -v ${WORKSPACE}:/mnt \ -e AWS_ACCESS_KEY_ID=\"${S3_KEY}\" \ -e AWS_SECRET_ACCESS_KEY=\"${S3_SECRET}\" \ - ghcr.io/linuxserver/baseimage-alpine:3.20 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ + ghcr.io/linuxserver/baseimage-alpine:3 s6-envdir -fn -- /var/run/s6/container_environment /bin/bash -c "\ apk add --no-cache python3 && \ python3 -m venv /lsiopy && \ pip install --no-cache-dir -U pip && \ @@ -615,13 +618,16 @@ pipeline { echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids IFS=',' read -ra CACHE <<< "$BUILDCACHE" for i in "${CACHE[@]}"; do docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" done - for p in $(jobs -p); do - wait "$p" || { echo "job $p failed" >&2; exit 1; } + for p in "${!pids[@]}"; do + wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; } done fi ''' @@ -681,13 +687,16 @@ pipeline { echo $GITHUB_TOKEN | docker login ghcr.io -u LinuxServer-CI --password-stdin echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin + if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids IFS=',' read -ra CACHE <<< "$BUILDCACHE" for i in "${CACHE[@]}"; do docker push ${i}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" done - for p in $(jobs -p); do - wait "$p" || { echo "job $p failed" >&2; exit 1; } + for p in "${!pids[@]}"; do + wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; } done fi ''' @@ -741,12 +750,14 @@ pipeline { echo $GITLAB_TOKEN | docker login registry.gitlab.com -u LinuxServer.io --password-stdin echo $QUAYPASS | docker login quay.io -u $QUAYUSER --password-stdin if [[ "${PACKAGE_CHECK}" != "true" ]]; then + declare -A pids IFS=',' read -ra CACHE <<< "$BUILDCACHE" for i in "${CACHE[@]}"; do docker push ${i}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} & + pids[$!]="$i" done - for p in $(jobs -p); do - wait "$p" || { echo "job $p failed" >&2; exit 1; } + for p in "${!pids[@]}"; do + wait "$p" || { [[ "${pids[$p]}" != *"quay.io"* ]] && exit 1; } done fi ''' @@ -871,7 +882,7 @@ pipeline { CI_DOCKERENV="LSIO_FIRST_PARTY=true" fi fi - docker pull ghcr.io/linuxserver/ci:latest + docker pull ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} if [ "${MULTIARCH}" == "true" ]; then docker pull ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} --platform=arm64 docker tag ghcr.io/linuxserver/lsiodev-buildcache:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} ${IMAGE}:arm64v8-${META_TAG} @@ -895,7 +906,7 @@ pipeline { -e WEB_PATH=\"${CI_WEBPATH}\" \ -e NODE_NAME=\"${NODE_NAME}\" \ -e SYFT_IMAGE_TAG=\"${CI_SYFT_IMAGE_TAG:-${SYFT_IMAGE_TAG}}\" \ - -t ghcr.io/linuxserver/ci:latest \ + -t ghcr.io/linuxserver/ci:${CITEST_IMAGETAG} \ python3 test_build.py''' } } @@ -921,9 +932,11 @@ pipeline { CACHEIMAGE=${i} fi done - docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${META_TAG} -t ${PUSHIMAGE}:latest -t ${PUSHIMAGE}:${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} + docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${META_TAG} -t ${PUSHIMAGE}:latest -t ${PUSHIMAGE}:${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } if [ -n "${SEMVER}" ]; then - docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} + docker buildx imagetools create --prefer-index=false -t ${PUSHIMAGE}:${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${PUSHIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } fi done ''' @@ -948,20 +961,27 @@ pipeline { CACHEIMAGE=${i} fi done - docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${META_TAG} -t ${MANIFESTIMAGE}:amd64-latest -t ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} - docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${META_TAG} -t ${MANIFESTIMAGE}:arm64v8-latest -t ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${META_TAG} -t ${MANIFESTIMAGE}:amd64-latest -t ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${META_TAG} -t ${MANIFESTIMAGE}:arm64v8-latest -t ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } if [ -n "${SEMVER}" ]; then - docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} - docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${SEMVER} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:amd64-${SEMVER} ${CACHEIMAGE}:amd64-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create --prefer-index=false -t ${MANIFESTIMAGE}:arm64v8-${SEMVER} ${CACHEIMAGE}:arm64v8-${COMMIT_SHA}-${BUILD_NUMBER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } fi done for MANIFESTIMAGE in "${IMAGE}" "${GITLABIMAGE}" "${GITHUBIMAGE}" "${QUAYIMAGE}"; do - docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest - docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} - - docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} + docker buildx imagetools create -t ${MANIFESTIMAGE}:latest ${MANIFESTIMAGE}:amd64-latest ${MANIFESTIMAGE}:arm64v8-latest || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create -t ${MANIFESTIMAGE}:${META_TAG} ${MANIFESTIMAGE}:amd64-${META_TAG} ${MANIFESTIMAGE}:arm64v8-${META_TAG} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } + docker buildx imagetools create -t ${MANIFESTIMAGE}:${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:amd64-${EXT_RELEASE_TAG} ${MANIFESTIMAGE}:arm64v8-${EXT_RELEASE_TAG} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } if [ -n "${SEMVER}" ]; then - docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} + docker buildx imagetools create -t ${MANIFESTIMAGE}:${SEMVER} ${MANIFESTIMAGE}:amd64-${SEMVER} ${MANIFESTIMAGE}:arm64v8-${SEMVER} || \ + { if [[ "${MANIFESTIMAGE}" != "${QUAYIMAGE}" ]]; then exit 1; fi; } fi done ''' @@ -979,6 +999,16 @@ pipeline { environment name: 'EXIT_STATUS', value: '' } steps { + echo "Auto-generating release notes" + sh '''if [ "$(git tag --points-at HEAD)" != "" ]; then + echo "Existing tag points to current commit, suggesting no new LS changes" + AUTO_RELEASE_NOTES="No changes" + else + AUTO_RELEASE_NOTES=$(curl -fsL -H "Authorization: token ${GITHUB_TOKEN}" -H "Accept: application/vnd.github+json" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases/generate-notes \ + -d '{"tag_name":"'${META_TAG}'",\ + "target_commitish": "main"}' \ + | jq -r '.body' | sed 's|## What.s Changed||') + fi''' echo "Pushing New tag for current commit ${META_TAG}" sh '''curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/git/tags \ -d '{"tag":"'${META_TAG}'",\ @@ -989,12 +1019,19 @@ pipeline { echo "Pushing New release for Tag" sh '''#! /bin/bash echo "Updating to ${EXT_RELEASE_CLEAN}" > releasebody.json - echo '{"tag_name":"'${META_TAG}'",\ - "target_commitish": "main",\ - "name": "'${META_TAG}'",\ - "body": "**CI Report:**\\n\\n'${CI_URL:-N/A}'\\n\\n**LinuxServer Changes:**\\n\\n'${LS_RELEASE_NOTES}'\\n\\n**Remote Changes:**\\n\\n' > start - printf '","draft": false,"prerelease": false}' >> releasebody.json - paste -d'\\0' start releasebody.json > releasebody.json.done + jq -n \ + --arg tag_name "$META_TAG" \ + --arg target_commitish "main" \ + --arg ci_url "${CI_URL:-N/A}" \ + --arg ls_notes "$AUTO_RELEASE_NOTES" \ + --arg remote_notes "$(cat releasebody.json)" \ + '{ + "tag_name": $tag_name, + "target_commitish": $target_commitish, + "name": $tag_name, + "body": ("**CI Report:**\\n\\n" + $ci_url + "\\n\\n**LinuxServer Changes:**\\n\\n" + $ls_notes + "\\n\\n**Remote Changes:**\\n\\n" + $remote_notes), + "draft": false, + "prerelease": false }' > releasebody.json.done curl -H "Authorization: token ${GITHUB_TOKEN}" -X POST https://api.github.com/repos/${LS_USER}/${LS_REPO}/releases -d @releasebody.json.done''' } } diff --git a/jenkins-vars.yml b/jenkins-vars.yml index 58b8f3d..86449a7 100644 --- a/jenkins-vars.yml +++ b/jenkins-vars.yml @@ -3,7 +3,7 @@ # jenkins variables project_name: unifi-network-application external_type: na -custom_version_command: "curl -sX GET https://dl.ui.com/unifi/debian/dists/stable/ubiquiti/binary-amd64/Packages.gz | gunzip | grep -A 7 -m 1 'Package: unifi' | awk -F ': ' '/Version/{print $2;exit}' | awk -F '-' '{print $1}'" +custom_version_command: "curl -sX GET 'https://fw-update.ubnt.com/api/firmware-latest?filter=eq~~product~~unifi-controller&filter=eq~~platform~~unix&filter=eq~~channel~~release' | jq -r '._embedded.firmware[].version' | awk -F '+' '{print $1}'" release_type: stable release_tag: latest ls_branch: main diff --git a/readme-vars.yml b/readme-vars.yml index 5fb807b..eac9a65 100644 --- a/readme-vars.yml +++ b/readme-vars.yml @@ -181,6 +181,7 @@ init_diagram: | "unifi-network-application:latest" <- Base Images # changelog changelogs: + - {date: "20.10.25:", desc: "Switch to using FW API endpoint for version checks."} - {date: "08.05.25:", desc: "Update sample `init-mongo.sh` for compatibility with 9.1.120 (only affects new installs)."} - {date: "13.02.25:", desc: "Revert JRE to 17."} - {date: "12.02.25:", desc: "Bump JRE to 21."}