Optimize APK update checks and CI builds
Build Alpine Packages / build-and-publish (v3.24, 3.24) (push) Failing after 2h20m30s

This commit is contained in:
Joachim Schlöffel
2026-08-24 08:51:30 +02:00
parent 9b9473f497
commit 479886d37d
10 changed files with 269 additions and 172 deletions
+12 -7
View File
@@ -39,7 +39,7 @@ jobs:
steps: steps:
- name: Prepare Environment - name: Prepare Environment
run: | run: |
apk add --no-cache --update abuild-rootbld alpine-sdk atools-apkbuild-lint bash ca-certificates curl doas git nodejs rsync shellcheck sudo tar apk add --no-cache --update abuild-rootbld alpine-sdk atools-apkbuild-lint bash ca-certificates curl doas git jq nodejs rsync shellcheck sudo tar
mkdir -p "$ALPINE_APK_REPO_CACHE" "$CARGO_HOME" "$RUSTUP_HOME" "$CARGO_TARGET_DIR" mkdir -p "$ALPINE_APK_REPO_CACHE" "$CARGO_HOME" "$RUSTUP_HOME" "$CARGO_TARGET_DIR"
chown -R 1000:1000 /cache/public-alpine-packages/${{ matrix.alpine_registry_branch }} chown -R 1000:1000 /cache/public-alpine-packages/${{ matrix.alpine_registry_branch }}
@@ -64,6 +64,7 @@ jobs:
- name: Prepare package cache - name: Prepare package cache
if: github.event_name != 'schedule' if: github.event_name != 'schedule'
id: package-selection
run: | run: |
scripts/apk/ci-package-cache.sh prepare scripts/apk/ci-package-cache.sh prepare
@@ -71,9 +72,13 @@ jobs:
if: github.event_name != 'schedule' if: github.event_name != 'schedule'
run: | run: |
scripts/apk/ci-build.sh scripts/apk/ci-build.sh
scripts/apk/ci-package-cache.sh sync if [ -d packages/local ]; then
scripts/apk/export-ci-assets.sh scripts/apk/list-packages.sh
scripts/apk/list-packages.sh fi
- name: Export GreptimeDB CI assets
if: github.event_name != 'schedule' && steps.package-selection.outputs.greptimedb_selected == 'true'
run: scripts/apk/export-ci-assets.sh
- name: Check artifact upload support - name: Check artifact upload support
if: github.event_name != 'schedule' if: github.event_name != 'schedule'
@@ -86,7 +91,7 @@ jobs:
fi fi
- name: Upload generated CI assets - name: Upload generated CI assets
if: github.event_name != 'schedule' && steps.artifact-upload.outputs.available == 'true' if: github.event_name != 'schedule' && steps.package-selection.outputs.greptimedb_selected == 'true' && steps.artifact-upload.outputs.available == 'true'
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: greptimedb-musl-binaries-${{ matrix.alpine_registry_branch }} name: greptimedb-musl-binaries-${{ matrix.alpine_registry_branch }}
@@ -97,9 +102,9 @@ jobs:
run: scripts/apk/ci-smoke.sh run: scripts/apk/ci-smoke.sh
- name: Runtime test - name: Runtime test
if: github.event_name != 'schedule' if: github.event_name != 'schedule' && env.ALPINE_SKIP_BUILD != '1'
run: scripts/apk/runtime-test.sh run: scripts/apk/runtime-test.sh
- name: Publish Alpine packages - name: Publish Alpine packages
if: github.event_name != 'pull_request' && github.event_name != 'schedule' if: github.event_name != 'pull_request' && github.event_name != 'schedule' && env.ALPINE_SKIP_BUILD != '1'
run: scripts/apk/publish-gitea.sh run: scripts/apk/publish-gitea.sh
+7 -2
View File
@@ -92,7 +92,7 @@ apk:lint-shell Run ShellCheck for packaging automation
apk:packages List built Alpine packages and dependencies apk:packages List built Alpine packages and dependencies
apk:publish-check Run lint, multi-arch build, package listing, and smoke test apk:publish-check Run lint, multi-arch build, package listing, and smoke test
apk:publish-gitea Publish built packages to the Gitea Alpine package registry apk:publish-gitea Publish built packages to the Gitea Alpine package registry
apk:outdated Check packaged upstream versions against latest GitHub releases apk:outdated Check packaged upstream versions and release summaries
apk:shell Open an Alpine package build shell in Docker apk:shell Open an Alpine package build shell in Docker
apk:smoke Install-test built packages from the local repository in Docker apk:smoke Install-test built packages from the local repository in Docker
apk:test-install Test README installation instructions in a fresh Alpine container apk:test-install Test README installation instructions in a fresh Alpine container
@@ -231,10 +231,15 @@ versions fail the command:
APK_UPDATE_CHECK_MODE=fail mise run apk:outdated APK_UPDATE_CHECK_MODE=fail mise run apk:outdated
``` ```
When an update is available, the command also lists compact release-note
summaries for every release between the packaged and latest versions.
### Gitea Workflow ### Gitea Workflow
`.gitea/workflows/build.yml` builds and publishes `v3.24`. Pull requests `.gitea/workflows/build.yml` builds and publishes `v3.24`. Pull requests
build only. build only. CI compares source package versions with the published registry,
then rebuilds only changed or unpublished packages; local build commands keep
using their local caches.
Repository variables: Repository variables:
+1
View File
@@ -1,6 +1,7 @@
[tools] [tools]
act = "latest" act = "latest"
docker-cli = "latest" docker-cli = "latest"
jq = "latest"
shellcheck = "latest" shellcheck = "latest"
[tasks."apk:build"] [tasks."apk:build"]
+2 -1
View File
@@ -8,7 +8,7 @@ arch="x86_64"
license="Apache-2.0" license="Apache-2.0"
depends="ca-certificates /bin/sh" depends="ca-certificates /bin/sh"
makedepends=" makedepends="
crystal>=1.20.1 crystal=1.21.0-r0
curl curl
gc-dev gc-dev
help2man help2man
@@ -40,6 +40,7 @@ export CRYSTAL_CACHE_DIR="${CRYSTAL_CACHE_DIR:-$srcdir/crystal-cache}"
export SHARDS_CACHE_PATH="${SHARDS_CACHE_PATH:-$srcdir/shards-cache}" export SHARDS_CACHE_PATH="${SHARDS_CACHE_PATH:-$srcdir/shards-cache}"
build() { build() {
crystal --version
make make
make man make man
} }
+2 -2
View File
@@ -9,8 +9,8 @@ Build command:
make make
``` ```
LavinMQ 2.9.1 requires Crystal 1.20.1 or newer, so build with Alpine 3.24 or LavinMQ 2.9.2 requires Crystal 1.21.0. The package pins Alpine edge's native
newer. Crystal package, avoiding a glibc toolchain in the Alpine musl build.
## Runtime Layout ## Runtime Layout
+3
View File
@@ -4,6 +4,9 @@ FROM alpine:${ALPINE_VERSION}
ARG BUILDER_UID=1000 ARG BUILDER_UID=1000
ARG BUILDER_GID=1000 ARG BUILDER_GID=1000
RUN printf '%s\n' 'https://dl-cdn.alpinelinux.org/alpine/edge/community' \
>> /etc/apk/repositories
RUN apk add --no-cache \ RUN apk add --no-cache \
abuild-rootbld \ abuild-rootbld \
alpine-sdk \ alpine-sdk \
+94 -150
View File
@@ -5,11 +5,29 @@ repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# shellcheck source=scripts/apk/package-lib.sh # shellcheck source=scripts/apk/package-lib.sh
. "${repo_root}/scripts/apk/package-lib.sh" . "${repo_root}/scripts/apk/package-lib.sh"
repo_name="${ALPINE_REPO_NAME:-local}"
arches="${ALPINE_ARCHES:-x86_64 aarch64}" arches="${ALPINE_ARCHES:-x86_64 aarch64}"
cache_root="${ALPINE_APK_REPO_CACHE:-/cache/public-alpine-packages/${ALPINE_REGISTRY_BRANCH:-local}/apk-repo}" branch="${ALPINE_REGISTRY_BRANCH:-v${ALPINE_VERSION:-3.24}}"
repo_dest="${repo_root}/packages/${repo_name}" repository="${ALPINE_REGISTRY_REPOSITORY:-${PACKAGE_NAME:-main}}"
instance_url="${INSTANCE_URL:-}"
owner="${PACKAGE_OWNER:-}"
command_name="${1:-prepare}" command_name="${1:-prepare}"
registry_cache="${CI_REGISTRY_CACHE_DIR:-${repo_root}/.cache/ci-registry}"
require_registry_config() {
local name="$1" value="$2"
[[ -n "${value}" ]] && return
printf 'missing required CI registry setting: %s\n' "${name}" >&2
exit 2
}
registry_url() {
printf '%s/api/packages/%s/alpine/%s/%s\n' \
"${instance_url%/}" "${owner}" "${branch}" "${repository}"
}
registry_key_url() {
printf '%s/api/packages/%s/alpine/key\n' "${instance_url%/}" "${owner}"
}
all_packages() { all_packages() {
while IFS= read -r package_dir; do while IFS= read -r package_dir; do
@@ -18,9 +36,7 @@ all_packages() {
} }
mark_all_packages() { mark_all_packages() {
local reason="$1" printf 'Rebuilding all packages: %s\n' "$1" >&2
printf 'Rebuilding all packages: %s\n' "${reason}" >&2
all_packages all_packages
} }
@@ -30,34 +46,23 @@ diff_base() {
if [[ -n "${base_ref}" ]] && git rev-parse --verify "origin/${base_ref}" >/dev/null 2>&1; then if [[ -n "${base_ref}" ]] && git rev-parse --verify "origin/${base_ref}" >/dev/null 2>&1; then
printf '%s...HEAD\n' "origin/${base_ref}" printf '%s...HEAD\n' "origin/${base_ref}"
return elif [[ -n "${before}" && ! "${before}" =~ ^0+$ ]] && git rev-parse --verify "${before}^{commit}" >/dev/null 2>&1; then
fi
if [[ -n "${before}" && ! "${before}" =~ ^0+$ ]] && git rev-parse --verify "${before}^{commit}" >/dev/null 2>&1; then
printf '%s..HEAD\n' "${before}" printf '%s..HEAD\n' "${before}"
return elif git rev-parse --verify HEAD^ >/dev/null 2>&1; then
fi
if git rev-parse --verify "HEAD^" >/dev/null 2>&1; then
printf 'HEAD^..HEAD\n' printf 'HEAD^..HEAD\n'
return else
return 1
fi fi
return 1
} }
changed_packages() { changed_packages() {
local base local base changed_paths changed_path package
local changed_paths
local changed_path
local package
declare -A selected=() declare -A selected=()
if ! base="$(diff_base)"; then if ! base="$(diff_base)"; then
mark_all_packages "no usable git diff base" mark_all_packages "no usable git diff base"
return return
fi fi
if ! changed_paths="$(git diff --name-only "${base}")"; then if ! changed_paths="$(git diff --name-only "${base}")"; then
mark_all_packages "git diff failed for ${base}" mark_all_packages "git diff failed for ${base}"
return return
@@ -72,8 +77,7 @@ changed_packages() {
;; ;;
packaging/alpine/local/*) packaging/alpine/local/*)
package="${changed_path#packaging/alpine/local/}" package="${changed_path#packaging/alpine/local/}"
package="${package%%/*}" selected["${package%%/*}"]=1
selected["${package}"]=1
;; ;;
esac esac
done <<< "${changed_paths}" done <<< "${changed_paths}"
@@ -83,167 +87,107 @@ changed_packages() {
done | sort done | sort
} }
restore_cache() { download_registry_metadata() {
if [[ -d "${cache_root}" ]]; then local arch url
mkdir -p "${repo_dest}"
cp -a "${cache_root}/." "${repo_dest}/" require_registry_config INSTANCE_URL "${instance_url}"
printf 'Restored Alpine package repository cache from %s\n' "${cache_root}" require_registry_config PACKAGE_OWNER "${owner}"
else mkdir -p "${registry_cache}"
printf 'No Alpine package repository cache found at %s\n' "${cache_root}" url="$(registry_url)"
fi for arch in ${arches}; do
curl --fail --silent --show-error --location \
--output "${registry_cache}/${arch}.APKINDEX.tar.gz" \
"${url}/${arch}/APKINDEX.tar.gz"
done
curl --fail --silent --show-error --location \
--output "${registry_cache}/registry.rsa.pub" \
"$(registry_key_url)"
} }
package_apk_names() { load_registry_index() {
local package_dir="$1" local arch package_name package_version
local arch="$2" declare -gA registry_packages=()
apk_package_apk_names "${package_dir}" "${arch}"
}
package_cache_complete() {
local package_dir="$1"
local package_name
local arch
local apk_name
package_name="$(apk_package_name "${package_dir}")"
for arch in ${arches}; do for arch in ${arches}; do
case "${arch}" in while IFS=$'\t' read -r package_name package_version; do
x86_64|aarch64) ;; [[ -n "${package_name}" && -n "${package_version}" ]] || continue
*) printf 'unsupported Alpine architecture: %s\n' "${arch}" >&2; exit 2 ;; registry_packages["${arch}|${package_name}|${package_version}"]=1
esac done < <(
tar -xOzf "${registry_cache}/${arch}.APKINDEX.tar.gz" APKINDEX | awk '
if ! apk_package_supports_arch "${package_dir}" "${arch}"; then /^P:/ { package = substr($0, 3); next }
continue /^V:/ { if (package != "") print package "\t" substr($0, 3); package = "" }
fi '
)
while IFS= read -r apk_name; do
if [[ ! -f "${repo_dest}/${arch}/${apk_name}" ]]; then
printf 'Cache miss for %s: missing %s/%s\n' "${package_name}" "${arch}" "${apk_name}" >&2
return 1
fi
done < <(package_apk_names "${package_dir}" "${arch}")
done done
return 0
} }
select_missing_packages() { registry_missing_packages() {
local package_dir local package_dir package_name arch spec spec_name spec_version missing
local package_name
while IFS= read -r package_dir; do while IFS= read -r package_dir; do
apk_validate_package_dir "${package_dir}" apk_validate_package_dir "${package_dir}"
package_name="$(apk_package_name "${package_dir}")" package_name="$(apk_package_name "${package_dir}")"
if ! package_cache_complete "${package_dir}"; then missing=0
printf '%s\n' "${package_name}"
fi
done < <(apk_all_package_dirs "${repo_root}")
}
prune_stale_apks() {
local package_dir
local arch
local apk_name
local current_apk
declare -A expected_apks=()
if [[ ! -d "${repo_dest}" ]]; then
return
fi
while IFS= read -r package_dir; do
apk_validate_package_dir "${package_dir}"
for arch in ${arches}; do for arch in ${arches}; do
case "${arch}" in apk_package_supports_arch "${package_dir}" "${arch}" || continue
x86_64|aarch64) ;; while IFS= read -r spec; do
*) printf 'unsupported Alpine architecture: %s\n' "${arch}" >&2; exit 2 ;; spec_name="${spec%%=*}"
esac spec_version="${spec#*=}"
if [[ -z "${registry_packages[${arch}|${spec_name}|${spec_version}]:-}" ]]; then
if ! apk_package_supports_arch "${package_dir}" "${arch}"; then missing=1
continue printf 'Registry miss: %s (%s, %s)\n' "${package_name}" "${arch}" "${spec}" >&2
fi fi
done < <(apk_package_versioned_names "${package_dir}" "${arch}")
while IFS= read -r apk_name; do
expected_apks["${repo_dest}/${arch}/${apk_name}"]=1
done < <(package_apk_names "${package_dir}" "${arch}")
done done
[[ "${missing}" == 1 ]] && printf '%s\n' "${package_name}"
done < <(apk_all_package_dirs "${repo_root}") done < <(apk_all_package_dirs "${repo_root}")
shopt -s nullglob
for current_apk in "${repo_dest}"/*/*.apk; do
if [[ -z "${expected_apks[${current_apk}]:-}" ]]; then
rm -f "${current_apk}"
printf 'Pruned stale cached APK: %s\n' "${current_apk#"${repo_root}/"}"
fi
done
shopt -u nullglob
} }
prepare() { prepare() {
local selected_packages
local selected local selected
declare -A selected_map=() declare -A selected_map=()
restore_cache download_registry_metadata
prune_stale_apks load_registry_index
while IFS= read -r selected; do while IFS= read -r selected; do
[[ -n "${selected}" ]] || continue [[ -n "${selected}" ]] && selected_map["${selected}"]=1
selected_map["${selected}"]=1
done < <(changed_packages) done < <(changed_packages)
while IFS= read -r selected; do while IFS= read -r selected; do
[[ -n "${selected}" ]] || continue [[ -n "${selected}" ]] && selected_map["${selected}"]=1
selected_map["${selected}"]=1 done < <(registry_missing_packages)
done < <(select_missing_packages)
selected_packages="$( ALPINE_PACKAGES="$(for selected in "${!selected_map[@]}"; do printf '%s\n' "${selected}"; done | sort | xargs)"
for selected in "${!selected_map[@]}"; do if [[ -n "${ALPINE_PACKAGES}" ]]; then
printf '%s\n' "${selected}" ALPINE_SKIP_BUILD=0
done | sort | xargs printf 'Selected packages for rebuild: %s\n' "${ALPINE_PACKAGES}"
)"
if [[ -n "${selected_packages}" ]]; then
printf 'Selected packages for rebuild: %s\n' "${selected_packages}"
export ALPINE_PACKAGES="${selected_packages}"
export ALPINE_SKIP_BUILD=0
else else
printf 'No packages selected for rebuild\n' ALPINE_SKIP_BUILD=1
export ALPINE_PACKAGES="" printf 'No packages selected for rebuild: registry satisfies source metadata\n'
export ALPINE_SKIP_BUILD=1
fi fi
if [[ -n "${GITHUB_ENV:-}" ]]; then if [[ -n "${GITHUB_ENV:-}" ]]; then
{ {
printf 'ALPINE_PACKAGES=%s\n' "${ALPINE_PACKAGES}" printf 'ALPINE_PACKAGES=%s\n' "${ALPINE_PACKAGES}"
printf 'ALPINE_SKIP_BUILD=%s\n' "${ALPINE_SKIP_BUILD}" printf 'ALPINE_SKIP_BUILD=%s\n' "${ALPINE_SKIP_BUILD}"
printf 'ALPINE_REGISTRY_URL=%s\n' "$(registry_url)"
printf 'ALPINE_REGISTRY_KEY=%s\n' "${registry_cache}/registry.rsa.pub"
} >> "${GITHUB_ENV}" } >> "${GITHUB_ENV}"
fi fi
} if [[ -n "${GITHUB_OUTPUT:-}" ]]; then
if [[ -n "${ALPINE_PACKAGES}" ]]; then
sync_cache() { printf 'packages_selected=true\n' >> "${GITHUB_OUTPUT}"
if [[ ! -d "${repo_dest}" ]]; then else
printf 'missing package repository: %s\n' "${repo_dest}" >&2 printf 'packages_selected=false\n' >> "${GITHUB_OUTPUT}"
exit 1 fi
if [[ " ${ALPINE_PACKAGES} " == *" greptimedb "* ]]; then
printf 'greptimedb_selected=true\n' >> "${GITHUB_OUTPUT}"
else
printf 'greptimedb_selected=false\n' >> "${GITHUB_OUTPUT}"
fi
fi fi
prune_stale_apks
mkdir -p "${cache_root}"
rsync -a --delete "${repo_dest}/" "${cache_root}/"
printf 'Updated Alpine package repository cache at %s\n' "${cache_root}"
} }
case "${command_name}" in case "${command_name}" in
prepare) prepare) prepare ;;
prepare *) printf 'usage: %s prepare\n' "$0" >&2; exit 2 ;;
;;
sync)
sync_cache
;;
*)
printf 'usage: %s [prepare|sync]\n' "$0" >&2
exit 2
;;
esac esac
+35 -4
View File
@@ -2,19 +2,50 @@
set -euo pipefail set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
# shellcheck source=scripts/apk/package-lib.sh
. "${repo_root}/scripts/apk/package-lib.sh"
repo_name="${ALPINE_REPO_NAME:-local}" repo_name="${ALPINE_REPO_NAME:-local}"
arch="${ALPINE_ARCH:-$(apk --print-arch)}" arch="${ALPINE_ARCH:-$(apk --print-arch)}"
packages="${SMOKE_PACKAGES:-seaweedfs seaweedfs-master-openrc seaweedfs-filer-openrc seaweedfs-worker-openrc greptimedb lavinmq lavinmq-openrc gitea gitea-openrc}" packages="${SMOKE_PACKAGES:-seaweedfs seaweedfs-master-openrc seaweedfs-filer-openrc seaweedfs-worker-openrc greptimedb lavinmq lavinmq-openrc gitea gitea-openrc}"
repo_dir="${repo_root}/packages/${repo_name}/${arch}" repo_dir="${repo_root}/packages/${repo_name}/${arch}"
registry_url="${ALPINE_REGISTRY_URL:-}"
registry_key="${ALPINE_REGISTRY_KEY:-}"
read -r -a package_list <<< "${packages}" read -r -a package_list <<< "${packages}"
declare -A versioned_packages=()
if [[ ! -d "${repo_dir}" ]]; then while IFS= read -r package_dir; do
printf 'missing local repository: packages/%s/%s\n' "${repo_name}" "${arch}" >&2 while IFS= read -r spec; do
versioned_packages["${spec%%=*}"]="${spec}"
done < <(apk_package_versioned_names "${package_dir}" "${arch}")
done < <(apk_all_package_dirs "${repo_root}")
for package in "${package_list[@]}"; do
if [[ -z "${versioned_packages[${package}]:-}" ]]; then
printf 'smoke package is not defined by a source APKBUILD: %s\n' "${package}" >&2
exit 2
fi
package="${versioned_packages[${package}]}"
done
if [[ -d "${repo_dir}" ]]; then
cp "${repo_dir}"/*.rsa.pub /etc/apk/keys/
echo "${repo_root}/packages/${repo_name}" >> /etc/apk/repositories
elif [[ -z "${registry_url}" ]]; then
printf 'missing local repository and no registry fallback: packages/%s/%s\n' "${repo_name}" "${arch}" >&2
exit 1 exit 1
fi fi
if [[ -n "${registry_url}" ]]; then
if [[ ! -f "${registry_key}" ]]; then
printf 'missing Alpine registry signing key: %s\n' "${registry_key:-<unset>}" >&2
exit 1
fi
cp "${registry_key}" /etc/apk/keys/
echo "${registry_url}" >> /etc/apk/repositories
fi
cp "${repo_dir}"/*.rsa.pub /etc/apk/keys/ for index in "${!package_list[@]}"; do
echo "${repo_root}/packages/${repo_name}" >> /etc/apk/repositories package_list[index]="${versioned_packages[${package_list[index]}]}"
done
apk update apk update
apk add "${package_list[@]}" apk add "${package_list[@]}"
if command -v weed >/dev/null 2>&1; then if command -v weed >/dev/null 2>&1; then
+86 -5
View File
@@ -13,17 +13,59 @@ fi
github_latest_release() { github_latest_release() {
local repo="$1" local repo="$1"
local api_url="https://api.github.com/repos/${repo}/releases/latest"
local response local response
response="$(curl -fsSL \ response="$(curl -fsSL \
-H 'Accept: application/vnd.github+json' \ -H 'Accept: application/vnd.github+json' \
-H 'X-GitHub-Api-Version: 2022-11-28' \ -H 'X-GitHub-Api-Version: 2022-11-28' \
"${api_url}" 2>/dev/null)" || return 1 "https://api.github.com/repos/${repo}/releases/latest" 2>/dev/null)" || return 1
printf '%s\n' "${response}" | jq -er '.tag_name'
}
printf '%s\n' "${response}" \ github_release_rows() {
| sed -n 's/^[[:space:]]*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/p' \ local repo="$1"
| head -n 1 local current_tag="$2"
local page=1
local response
local release_count
while :; do
response="$(curl -fsSL \
-H 'Accept: application/vnd.github+json' \
-H 'X-GitHub-Api-Version: 2022-11-28' \
"https://api.github.com/repos/${repo}/releases?per_page=100&page=${page}" 2>/dev/null)" || return 1
release_count="$(printf '%s\n' "${response}" | jq -er 'if type == "array" then length else error("expected release array") end')" || return 1
[[ "${release_count}" -gt 0 ]] || return 0
printf '%s\n' "${response}" | jq -r '
.[]
| select(.draft | not)
| select(.prerelease | not)
| [
.tag_name,
(.published_at // "-"),
(.name // .tag_name),
.html_url,
(
(.body // "")
| gsub("[\\r\\n\\t]+"; " ")
| gsub("[`*_>#]"; "")
| gsub(" +"; " ")
| gsub("^ +"; "")
| gsub(" +$"; "")
| if length > 240 then .[0:237] + "..." else . end
)
]
| @tsv
'
if printf '%s\n' "${response}" | jq -e --arg tag "${current_tag}" '
any(.[]; .tag_name == $tag and (.draft | not) and (.prerelease | not))
' >/dev/null; then
return 0
fi
page=$((page + 1))
done
} }
apkbuild_value() { apkbuild_value() {
@@ -104,6 +146,7 @@ printf '%-14s %-14s %-14s %-18s %s\n' "PACKAGE" "CURRENT" "LATEST" "STATUS" "UPS
has_update=0 has_update=0
has_unknown=0 has_unknown=0
release_details=""
while IFS= read -r package_dir; do while IFS= read -r package_dir; do
apk_validate_package_dir "${package_dir}" apk_validate_package_dir "${package_dir}"
@@ -121,6 +164,40 @@ while IFS= read -r package_dir; do
if version_is_newer "${latest_version}" "${current_version}"; then if version_is_newer "${latest_version}" "${current_version}"; then
status="update-available" status="update-available"
has_update=1 has_update=1
package_details="${package_name}: ${current_version} -> ${latest_version}"
case "${version_prefix}" in
none|"") current_tag="${current_version}" ;;
*) current_tag="${version_prefix}${current_version}" ;;
esac
if release_rows="$(github_release_rows "${repo}" "${current_tag}")" && [[ -n "${release_rows}" ]]; then
current_tag_found=0
while IFS=$'\t' read -r release_tag published_at release_name release_url release_excerpt; do
[[ -n "${release_tag}" ]] || continue
release_version="$(normalize_version "${release_tag}" "${version_prefix}")"
if [[ "${release_tag}" == "${current_tag}" ]]; then
current_tag_found=1
fi
if version_is_newer "${release_version}" "${current_version}"; then
package_details+=$'\n'
package_details+=" ${release_version} (${published_at}) — ${release_name}"
package_details+=$'\n'
package_details+=" ${release_url}"
if [[ -n "${release_excerpt}" ]]; then
package_details+=$'\n'
package_details+=" ${release_excerpt}"
fi
fi
done <<< "${release_rows}"
if [[ "${current_tag_found}" == 0 ]]; then
package_details+=$'\n'
package_details+=" Note: current release tag ${current_tag} was not found; listed releases compare newer than ${current_version}."
fi
else
package_details+=$'\n'
package_details+=" Note: release details could not be fetched."
fi
release_details+=$'\n'
release_details+="${package_details}"
else else
status="current" status="current"
fi fi
@@ -139,6 +216,10 @@ while IFS= read -r package_dir; do
"${upstream_url}" "${upstream_url}"
done < <(apk_package_dirs "${repo_root}") done < <(apk_package_dirs "${repo_root}")
if [[ -n "${release_details}" ]]; then
printf '\nRelease details:%s\n' "${release_details}"
fi
if [[ "${mode}" == "fail" && ( "${has_update}" -ne 0 || "${has_unknown}" -ne 0 ) ]]; then if [[ "${mode}" == "fail" && ( "${has_update}" -ne 0 || "${has_unknown}" -ne 0 ) ]]; then
exit 1 exit 1
fi fi
+27 -1
View File
@@ -106,7 +106,8 @@ apk_package_apk_names() {
local pkgrel local pkgrel
local subpackage local subpackage
local subpackages local subpackages
export CARCH="${arch}" # shellcheck disable=SC2034 # APKBUILD reads CARCH while sourced below.
local CARCH="${arch}"
cd "${package_dir}" || exit 1 cd "${package_dir}" || exit 1
# shellcheck source=/dev/null # shellcheck source=/dev/null
. ./APKBUILD . ./APKBUILD
@@ -119,6 +120,31 @@ apk_package_apk_names() {
) )
} }
apk_package_versioned_names() {
local package_dir="$1"
local arch="$2"
(
set +u
local pkgname
local pkgver
local pkgrel
local subpackage
local subpackages
# shellcheck disable=SC2034 # APKBUILD reads CARCH while sourced below.
local CARCH="${arch}"
cd "${package_dir}" || exit 1
# shellcheck source=/dev/null
. ./APKBUILD
printf '%s=%s-r%s\n' "${pkgname}" "${pkgver}" "${pkgrel}"
for subpackage in ${subpackages:-}; do
subpackage="${subpackage%%:*}"
printf '%s=%s-r%s\n' "${subpackage}" "${pkgver}" "${pkgrel}"
done
)
}
apk_container_package_dir() { apk_container_package_dir() {
local repo_root="$1" local repo_root="$1"
local package_dir="$2" local package_dir="$2"