Some checks failed
Build linux_amd64 extension and upload to Packages / build-linux-amd64 (push) Has been cancelled
282 lines
13 KiB
YAML
282 lines
13 KiB
YAML
name: Build linux_amd64 extension and upload to Packages
|
|
on:
|
|
workflow_dispatch:
|
|
inputs:
|
|
version:
|
|
description: Package version (defaults to tag name or short SHA)
|
|
required: false
|
|
push:
|
|
branches:
|
|
- main
|
|
tags:
|
|
- 'v*'
|
|
|
|
jobs:
|
|
build-linux-amd64:
|
|
runs-on: ubuntu-latest
|
|
env:
|
|
EXTENSION_NAME: ui
|
|
DUCKDB_PLATFORM: linux_amd64
|
|
steps:
|
|
- name: Checkout repository (manual)
|
|
env:
|
|
TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
if [ -d .git ]; then
|
|
echo "Repository already present"
|
|
else
|
|
server="${GITHUB_SERVER_URL:-${{ github.server_url }}}"
|
|
repo_full="${GITHUB_REPOSITORY:-${{ github.repository }}}"
|
|
sha="${GITHUB_SHA:-${{ github.sha }}}"
|
|
host="$(echo "$server" | sed -E 's#^https?://([^/]+).*#\1#')"
|
|
if [ -n "${TOKEN:-}" ]; then
|
|
umask 077
|
|
printf "machine %s\n login token\n password %s\n" "$host" "$TOKEN" > "$HOME/.netrc"
|
|
fi
|
|
git init .
|
|
git config --global --add safe.directory "$(pwd)"
|
|
git remote add origin "$server/$repo_full.git"
|
|
git -c http.https://$host/.extraheader="" fetch --depth=1 origin "$sha"
|
|
git checkout -q FETCH_HEAD
|
|
fi
|
|
|
|
- name: Show workspace status
|
|
run: |
|
|
set -e
|
|
git --no-pager status | cat
|
|
- name: Install build dependencies
|
|
run: |
|
|
set -e
|
|
export DEBIAN_FRONTEND=noninteractive
|
|
apt-get update
|
|
apt-get install -y --no-install-recommends \
|
|
build-essential cmake ninja-build python3 python3-venv pkg-config \
|
|
libssl-dev curl git ca-certificates jq
|
|
- name: Preflight Gitea upload (fast-fail)
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
: "${GITEA_TOKEN:?GITEA_TOKEN secret is required}"
|
|
server="${GITHUB_SERVER_URL:-${{ github.server_url }}}"
|
|
owner="${GITHUB_REPOSITORY_OWNER:-${{ github.repository_owner }}}"
|
|
repo_full="${GITHUB_REPOSITORY:-${{ github.repository }}}"
|
|
pkg="${repo_full##*/}-preflight"
|
|
version="preflight-${GITHUB_RUN_ID:-0}-${GITHUB_RUN_ATTEMPT:-0}-$(date +%s)"
|
|
name="check.bin"
|
|
tmpfile="$(mktemp)"
|
|
printf "auth check %s\n" "$(date -u +%FT%TZ)" > "$tmpfile"
|
|
# Normalize server to effective scheme+host (handles http->https redirects)
|
|
base_no_trail="$(echo "$server" | sed 's#/*$##')"
|
|
# Use GET (not HEAD) to avoid servers that don't support HEAD on this endpoint
|
|
effective_version_url=$(curl -sS -L -o /dev/null -w '%{url_effective}' "$base_no_trail/api/v1/version" || echo "")
|
|
normalized_server=$(echo "$effective_version_url" | sed -E 's#^(https?://[^/]+).*$#\1#')
|
|
if [ -n "$normalized_server" ]; then
|
|
server="$normalized_server"
|
|
fi
|
|
url="$server/api/packages/$owner/generic/$pkg/$version/$name?replace=1"
|
|
mask() { local s="$1"; local n=${#s}; if [ "$n" -le 8 ]; then printf "*** (len=%s)" "$n"; else printf "%s***%s (len=%s)" "${s:0:4}" "${s:n-4:4}" "$n"; fi; }
|
|
echo "Preflight variables:"
|
|
echo " server=$server"
|
|
echo " owner=$owner"
|
|
echo " package=$pkg"
|
|
echo " version=$version"
|
|
echo " url=$url"
|
|
echo " token=$(mask "$GITEA_TOKEN")"
|
|
echo "Validating token via /api/v1/user:"
|
|
curl -sS -L -o /dev/null -w " auth check -> HTTP %{http_code}\n" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" "$server/api/v1/user" || true
|
|
whoami_json=$(curl -sS -L -H "Authorization: token ${GITEA_TOKEN}" "$server/api/v1/user" || echo "")
|
|
auth_user=$(echo "$whoami_json" | jq -r '.login // empty')
|
|
if [ -z "$auth_user" ]; then auth_user="$owner"; fi
|
|
echo " auth user=$auth_user"
|
|
echo "Attempting preflight upload"
|
|
tmpdir_pf="$(mktemp -d)"
|
|
resp_headers_pf="$tmpdir_pf/headers.txt"
|
|
resp_body_pf="$tmpdir_pf/body.txt"
|
|
http_code=$(curl -sS -L -i -X PUT \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/octet-stream" \
|
|
--upload-file "$tmpfile" "$url" \
|
|
-D "$resp_headers_pf" -o "$resp_body_pf" -w "%{http_code}" || true)
|
|
echo "Preflight response HTTP code: $http_code"
|
|
echo "Preflight response headers:"; sed -n '1,200p' "$resp_headers_pf" | sed 's/\r$//' || true
|
|
if [ -s "$resp_body_pf" ]; then
|
|
echo "Preflight response body (first 200 bytes):"; head -c 200 "$resp_body_pf"; echo
|
|
fi
|
|
case "$http_code" in
|
|
401|301|302|303|307|308)
|
|
echo "Preflight got $http_code; retrying with HTTP Basic auth (owner:token)" ;;
|
|
*) ;;
|
|
esac
|
|
if [ "$http_code" = "401" ] || [ "$http_code" = "301" ] || [ "$http_code" = "302" ] || [ "$http_code" = "303" ] || [ "$http_code" = "307" ] || [ "$http_code" = "308" ]; then
|
|
http_code=$(curl -sS -L -i -X PUT \
|
|
-u "$auth_user:${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/octet-stream" \
|
|
--upload-file "$tmpfile" "$url" \
|
|
-D "$resp_headers_pf" -o "$resp_body_pf" -w "%{http_code}" || true)
|
|
echo "Preflight retry HTTP code: $http_code"
|
|
echo "Preflight retry response headers:"; sed -n '1,200p' "$resp_headers_pf" | sed 's/\r$//' || true
|
|
if [ -s "$resp_body_pf" ]; then
|
|
echo "Preflight retry body (first 200 bytes):"; head -c 200 "$resp_body_pf"; echo
|
|
fi
|
|
fi
|
|
case "$http_code" in
|
|
2*) echo "Preflight upload succeeded, cleaning up" ;;
|
|
*) echo "Preflight upload failed with HTTP $http_code" >&2; exit 1 ;;
|
|
esac
|
|
# Cleanup the uploaded dummy package version (best effort)
|
|
curl -sS -L -o /dev/null -w " delete -> HTTP %{http_code}\n" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" -X DELETE \
|
|
"$server/api/packages/$owner/generic/$pkg/$version" || \
|
|
curl -sS -L -o /dev/null -w " delete (basic) -> HTTP %{http_code}\n" \
|
|
-u "$owner:${GITEA_TOKEN}" -X DELETE \
|
|
"$server/api/packages/$owner/generic/$pkg/$version" || true
|
|
- name: Initialize submodules
|
|
run: |
|
|
set -e
|
|
git submodule update --init --recursive
|
|
|
|
- name: Build release (linux_amd64)
|
|
env:
|
|
GEN: ""
|
|
run: |
|
|
set -e
|
|
make -j"$(nproc)" release
|
|
|
|
- name: Find extension artifact
|
|
id: artifact
|
|
run: |
|
|
set -euo pipefail
|
|
path="$(ls -1 build/release/extension/${EXTENSION_NAME}/${EXTENSION_NAME}.duckdb_extension 2>/dev/null || true)"
|
|
if [ -z "$path" ]; then
|
|
path="$(find build/release -type f -name '*.duckdb_extension' | head -n 1 || true)"
|
|
fi
|
|
if [ -z "$path" ]; then
|
|
echo "Extension artifact not found" >&2
|
|
exit 1
|
|
fi
|
|
echo "file=$path" >> "$GITHUB_OUTPUT"
|
|
echo "Found: $path"
|
|
|
|
- name: Compute package version
|
|
id: ver
|
|
run: |
|
|
set -euo pipefail
|
|
version='${{ inputs.version }}'
|
|
if [ -z "$version" ]; then
|
|
if [ "${{ github.ref_type }}" = "tag" ]; then
|
|
version='${{ github.ref_name }}'
|
|
else
|
|
version="dev-${GITHUB_SHA::8}"
|
|
fi
|
|
fi
|
|
echo "version=$version" >> "$GITHUB_OUTPUT"
|
|
echo "Using version: $version"
|
|
- name: Upload to Gitea Packages (generic)
|
|
env:
|
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
|
run: |
|
|
set -euo pipefail
|
|
: "${GITEA_TOKEN:?GITEA_TOKEN secret is required}"
|
|
# Derive server/owner/pkg from env if not provided
|
|
server="${GITHUB_SERVER_URL:-${{ github.server_url }}}"
|
|
owner="${GITHUB_REPOSITORY_OWNER:-${{ github.repository_owner }}}"
|
|
repo_full="${GITHUB_REPOSITORY:-${{ github.repository }}}"
|
|
pkg="${repo_full##*/}"
|
|
# Use previously computed version & artifact if available
|
|
version='${{ steps.ver.outputs.version }}'
|
|
file='${{ steps.artifact.outputs.file }}'
|
|
# Fallbacks if steps were skipped
|
|
if [ -z "${version}" ]; then
|
|
if [ -n "${GITHUB_REF_TYPE:-}" ] && [ "${GITHUB_REF_TYPE}" = "tag" ]; then
|
|
version="${GITHUB_REF_NAME:-dev-${GITHUB_SHA::8}}"
|
|
else
|
|
version="dev-${GITHUB_SHA::8}"
|
|
fi
|
|
fi
|
|
if [ -z "${file}" ]; then
|
|
file="$(ls -1 build/release/extension/${EXTENSION_NAME}/${EXTENSION_NAME}.duckdb_extension 2>/dev/null || true)"
|
|
if [ -z "$file" ]; then
|
|
file="$(find build/release -type f -name '*.duckdb_extension' | head -n 1 || true)"
|
|
fi
|
|
fi
|
|
[ -n "$server" ] || { echo "server not set" >&2; exit 1; }
|
|
[ -n "$owner" ] || { echo "owner not set" >&2; exit 1; }
|
|
[ -n "$pkg" ] || { echo "pkg not set" >&2; exit 1; }
|
|
[ -n "$version" ] || { echo "version not set" >&2; exit 1; }
|
|
[ -n "$file" ] || { echo "file not set" >&2; exit 1; }
|
|
# Normalize server using effective URL of /api/v1/version (handles http->https)
|
|
base_no_trail="$(echo "$server" | sed 's#/*$##')"
|
|
effective_version_url=$(curl -sS -L -o /dev/null -w '%{url_effective}' "$base_no_trail/api/v1/version" || echo "")
|
|
normalized_server=$(echo "$effective_version_url" | sed -E 's#^(https?://[^/]+).*$#\1#')
|
|
if [ -n "$normalized_server" ]; then
|
|
server="$normalized_server"
|
|
fi
|
|
# Determine authenticated username for Basic auth fallback
|
|
whoami_json=$(curl -sS -L -H "Authorization: token ${GITEA_TOKEN}" "$server/api/v1/user" || echo "")
|
|
auth_user=$(echo "$whoami_json" | jq -r '.login // empty')
|
|
if [ -z "$auth_user" ]; then auth_user="$owner"; fi
|
|
name="$(basename "$file")"
|
|
url="$server/api/packages/$owner/generic/$pkg/$version/$name?replace=1"
|
|
# Debug helpers (avoid leaking secrets)
|
|
mask() { local s="$1"; local n=${#s}; if [ "$n" -le 8 ]; then printf "*** (len=%s)" "$n"; else printf "%s***%s (len=%s)" "${s:0:4}" "${s:n-4:4}" "$n"; fi; }
|
|
filesize=$(stat -c%s "$file" 2>/dev/null || echo "?")
|
|
host="$(echo "$server" | sed -E 's#^https?://([^/]+).*#\1#')"
|
|
echo "Derived variables:"
|
|
echo " server=$server"
|
|
echo " owner=$owner"
|
|
echo " package=$pkg"
|
|
echo " version=$version"
|
|
echo " artifact=$file (size=${filesize} bytes, name=$name)"
|
|
echo " url=$url"
|
|
echo " token=$(mask "$GITEA_TOKEN")"
|
|
echo "Curl version:"; curl --version | head -n 1
|
|
echo "DNS for $host:"; getent hosts "$host" || true
|
|
|
|
echo "Checking API reachability (no auth):"
|
|
curl -sS -L -o /dev/null -w " /api/v1/version -> HTTP %{http_code}\n" "$server/api/v1/version" || true
|
|
|
|
echo "Validating token via /api/v1/user:"
|
|
curl -sS -L -o /dev/null -w " auth check -> HTTP %{http_code}\n" \
|
|
-H "Authorization: token ${GITEA_TOKEN}" "$server/api/v1/user" || true
|
|
echo " auth user=$auth_user"
|
|
|
|
echo "Uploading $file to $url"
|
|
# Perform upload and capture response details without exposing token
|
|
tmpdir="$(mktemp -d)"
|
|
resp_headers="$tmpdir/headers.txt"
|
|
resp_body="$tmpdir/body.txt"
|
|
http_code=$(curl -sS -L -i -X PUT \
|
|
-H "Authorization: token ${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/octet-stream" \
|
|
--retry 2 --retry-delay 2 --max-time 300 \
|
|
--upload-file "$file" "$url" \
|
|
-D "$resp_headers" -o "$resp_body" -w "%{http_code}" || true)
|
|
echo "Response HTTP code: $http_code"
|
|
echo "Response headers:"; sed -n '1,200p' "$resp_headers" | sed 's/\r$//' || true
|
|
if [ -s "$resp_body" ]; then
|
|
echo "Response body (first 200 bytes):"; head -c 200 "$resp_body"; echo
|
|
fi
|
|
|
|
# If unauthorized or redirected, retry once using HTTP Basic auth (per Gitea docs)
|
|
if [ "$http_code" = "401" ] || [ "$http_code" = "403" ] || [ "$http_code" = "301" ] || [ "$http_code" = "302" ] || [ "$http_code" = "303" ] || [ "$http_code" = "307" ] || [ "$http_code" = "308" ]; then
|
|
echo "HTTP $http_code; retrying with HTTP Basic auth (auth_user:token)"
|
|
http_code=$(curl -sS -L -i -X PUT \
|
|
-u "$auth_user:${GITEA_TOKEN}" \
|
|
-H "Content-Type: application/octet-stream" \
|
|
--retry 2 --retry-delay 2 --max-time 300 \
|
|
--upload-file "$file" "$url" \
|
|
-D "$resp_headers" -o "$resp_body" -w "%{http_code}" || true)
|
|
echo "Retry HTTP code: $http_code"
|
|
echo "Retry response headers:"; sed -n '1,200p' "$resp_headers" | sed 's/\r$//' || true
|
|
if [ -s "$resp_body" ]; then
|
|
echo "Retry response body (first 200 bytes):"; head -c 200 "$resp_body"; echo
|
|
fi
|
|
fi
|
|
|
|
case "$http_code" in
|
|
2*) echo "Upload complete." ;;
|
|
*) echo "Upload failed with HTTP $http_code" >&2; exit 1 ;;
|
|
esac |