diff --git a/scripts/ci/bootstrap-apt.sh b/scripts/ci/bootstrap-apt.sh index 37ddc1a..061fc8b 100755 --- a/scripts/ci/bootstrap-apt.sh +++ b/scripts/ci/bootstrap-apt.sh @@ -8,12 +8,33 @@ export DEBIAN_FRONTEND=noninteractive distribution_id="$(detect_debian_distribution_id)" distribution_codename="$(detect_debian_distribution)" +metadata_file="$(ci_metadata_file)" refresh_package_indexes=false log "Bootstrapping APT packages for $distribution_id:$distribution_codename" printf 'Acquire::http::Proxy "http://cbrapt01.lan.cyber.gent:3142";\n' >/etc/apt/apt.conf.d/80proxy apt-get update +apt-get install -y --no-install-recommends \ + ca-certificates \ + curl \ + git +update-ca-certificates + +bash ./scripts/ci/preflight-package.sh + +if [[ -f "$metadata_file" ]]; then + set -a + # shellcheck disable=SC1090 + . "$metadata_file" + set +a + + if [[ "${SKIP_PACKAGE_BUILD:-false}" == "true" ]]; then + log "Skipping package bootstrap because the package already exists in Gitea" + exit 0 + fi +fi + apt-get upgrade -y apt-get install -y --no-install-recommends build-essential @@ -39,12 +60,9 @@ fi apt-get install -y --no-install-recommends \ autoconf \ automake \ - ca-certificates \ cmake \ - curl \ flex \ gawk \ - git \ gnupg \ libbz2-dev \ libcap2-bin \ diff --git a/scripts/ci/build-package.sh b/scripts/ci/build-package.sh index 1e5e6c4..1da340e 100755 --- a/scripts/ci/build-package.sh +++ b/scripts/ci/build-package.sh @@ -14,7 +14,19 @@ work_root="$(ci_work_root)" helper_dir="$work_root/hercules-helper" artifacts_dir="$work_root/artifacts" build_path="/home/bill/hyperion-build-package" -metadata_file="$artifacts_dir/package.env" +metadata_file="$(ci_metadata_file)" + +if [[ -f "$metadata_file" ]]; then + set -a + # shellcheck disable=SC1090 + . "$metadata_file" + set +a + + if [[ "${SKIP_PACKAGE_BUILD:-false}" == "true" ]]; then + log "Skipping package build because the package already exists in Gitea" + exit 0 + fi +fi log "Preparing CI work root at $work_root" rm -rf "$work_root" diff --git a/scripts/ci/preflight-package.sh b/scripts/ci/preflight-package.sh new file mode 100644 index 0000000..2dace3c --- /dev/null +++ b/scripts/ci/preflight-package.sh @@ -0,0 +1,229 @@ +#!/usr/bin/env bash + +set -euo pipefail + +source "$(cd "$(dirname "$0")/.." && pwd)/lib/common.sh" + +require_cmd awk +require_cmd curl +require_cmd dpkg +require_cmd git +require_cmd gzip + +load_build_config + +work_root="$(ci_work_root)" +artifacts_dir="$(ci_artifacts_dir)" +metadata_file="$(ci_metadata_file)" +helper_dir="$work_root/hercules-helper-preflight" +hyperion_dir="$work_root/hyperion-preflight" + +owner="${GITEA_PACKAGE_OWNER:-${CI_REPO_OWNER:-}}" +username="${GITEA_PACKAGE_USERNAME:-${CI_REPO_OWNER:-}}" +base_url="${GITEA_BASE_URL:-$DEFAULT_GITEA_BASE_URL}" +package_distribution="${DEBIAN_DISTRIBUTION:-$(detect_debian_distribution)}" +package_component="${DEBIAN_COMPONENT:-$DEFAULT_DEBIAN_COMPONENT}" +package_architecture="$(dpkg --print-architecture)" + +resolve_helper_template_dir() { + local template_dir="$1/packagers/debian/hercules-hyperion" + + if [[ -d "$template_dir" ]]; then + printf '%s\n' "$template_dir" + return 0 + fi + + template_dir="$( + find "$1/packagers/debian" -mindepth 1 -maxdepth 1 -type d -name 'hyperion-*' \ + | sort -V \ + | tail -n 1 + )" + + [[ -n "$template_dir" ]] || die "No Hyperion Debian package template directory found under $1/packagers/debian" + printf '%s\n' "$template_dir" +} + +resolve_hyperion_repo_url() { + printf '%s\n' "${GIT_REPO_HYPERION:-${git_repo_hyperion:-https://github.com/SDL-Hercules-390/hyperion.git}}" +} + +resolve_hyperion_repo_branch() { + printf '%s\n' "${GIT_BRANCH_HYPERION:-${git_branch_hyperion:-}}" +} + +resolve_hyperion_repo_commit() { + printf '%s\n' "${GIT_COMMIT_HYPERION:-${git_commit_hyperion:-}}" +} + +clone_repo() { + local repo_url="$1" + local repo_dir="$2" + local repo_branch="${3:-}" + + rm -rf "$repo_dir" + + if [[ -n "$repo_branch" ]]; then + git clone --branch "$repo_branch" "$repo_url" "$repo_dir" + else + git clone "$repo_url" "$repo_dir" + fi +} + +determine_hyperion_version() { + local repo_dir="$1" + + if [[ -x "$repo_dir/_dynamic_version" ]]; then + ( + cd "$repo_dir" + ./_dynamic_version . VERSION \ + | awk '{sub("-modified","", $0); print}' \ + | tr -d '"' + ) + return 0 + fi + + git -C "$repo_dir" describe --tags --dirty --always 2>/dev/null || echo unknown +} + +fetch_package_index() { + local response_file + local status_code + local url + local suffix + + response_file="$(mktemp)" + + for suffix in Packages Packages.gz; do + url="$base_url/api/packages/$owner/debian/dists/$package_distribution/$package_component/binary-$package_architecture/$suffix" + status_code="$( + curl \ + --silent \ + --show-error \ + --location \ + --output "$response_file" \ + --write-out '%{http_code}' \ + --user "$username:$GITEA_PACKAGE_TOKEN" \ + "$url" + )" + + case "$status_code" in + 200) + if [[ "$suffix" == "Packages.gz" ]]; then + gzip -dc "$response_file" + else + cat "$response_file" + fi + rm -f "$response_file" + return 0 + ;; + 404) + ;; + *) + cat "$response_file" >&2 + rm -f "$response_file" + die "Package index query failed with HTTP $status_code for $url" + ;; + esac + done + + rm -f "$response_file" + return 1 +} + +package_exists_in_index() { + local package_name="$1" + local package_version="$2" + + awk -v target_package="$package_name" -v target_version="$package_version" ' + BEGIN { + RS = "" + FS = "\n" + } + { + found_package = 0 + found_version = 0 + for (i = 1; i <= NF; i++) { + if ($i == "Package: " target_package) { + found_package = 1 + } + if ($i == "Version: " target_version) { + found_version = 1 + } + } + if (found_package && found_version) { + matched = 1 + exit + } + } + END { + if (matched) { + exit 0 + } + exit 1 + } + ' +} + +write_metadata() { + local skip_build="$1" + local package_name="$2" + local package_version="$3" + + mkdir -p "$artifacts_dir" + + cat >"$metadata_file" <"$package_index_file"; then + have_package_index=true +fi + +if [[ "$have_package_index" == "true" ]] && package_exists_in_index "$package_name" "$package_version" <"$package_index_file"; then + rm -f "$package_index_file" + write_metadata true "$package_name" "$package_version" + log "Package already exists in registry; build will be skipped" + exit 0 +fi + +rm -f "$package_index_file" +write_metadata false "$package_name" "$package_version" +log "Package does not exist in registry; build will continue" diff --git a/scripts/ci/upload-package.sh b/scripts/ci/upload-package.sh index ff2463a..2fc990c 100755 --- a/scripts/ci/upload-package.sh +++ b/scripts/ci/upload-package.sh @@ -5,10 +5,9 @@ set -euo pipefail source "$(cd "$(dirname "$0")/.." && pwd)/lib/common.sh" require_cmd curl -require_env GITEA_PACKAGE_TOKEN work_root="$(ci_work_root)" -metadata_file="$work_root/artifacts/package.env" +metadata_file="$(ci_metadata_file)" [[ -f "$metadata_file" ]] || die "Package metadata file not found: $metadata_file" @@ -17,6 +16,13 @@ set -a . "$metadata_file" set +a +if [[ "${SKIP_PACKAGE_BUILD:-false}" == "true" ]]; then + log "Skipping package upload because the package already exists in Gitea" + exit 0 +fi + +require_env GITEA_PACKAGE_TOKEN + owner="${GITEA_PACKAGE_OWNER:-${CI_REPO_OWNER:-}}" username="${GITEA_PACKAGE_USERNAME:-${CI_REPO_OWNER:-}}" base_url="${GITEA_BASE_URL:-$DEFAULT_GITEA_BASE_URL}" diff --git a/scripts/lib/common.sh b/scripts/lib/common.sh index da92a37..ea02a06 100755 --- a/scripts/lib/common.sh +++ b/scripts/lib/common.sh @@ -117,3 +117,11 @@ load_build_config() { ci_work_root() { printf '%s\n' "${CI_WORK_ROOT:-$DEFAULT_CI_WORK_ROOT}" } + +ci_artifacts_dir() { + printf '%s/artifacts\n' "$(ci_work_root)" +} + +ci_metadata_file() { + printf '%s/package.env\n' "$(ci_artifacts_dir)" +}