The GITEA_TOKEN lacks 'lfs' scope, causing the LFS batch API to reject uploads. Upload .zst files directly as release assets via the Gitea API instead. This eliminates git-lfs, the separate releases repo, and all LFS-related plumbing.
This commit is contained in:
+21
-117
@@ -29,7 +29,7 @@ jobs:
|
|||||||
- name: Install archiso and dependencies
|
- name: Install archiso and dependencies
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
pacman -Syu --noconfirm --needed archiso jq git-lfs zstd
|
pacman -Syu --noconfirm --needed archiso jq zstd
|
||||||
|
|
||||||
- name: Ensure /dev/stdin exists for mkinitcpio
|
- name: Ensure /dev/stdin exists for mkinitcpio
|
||||||
run: |
|
run: |
|
||||||
@@ -81,14 +81,12 @@ jobs:
|
|||||||
echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
|
echo "tag_name=${TAG_NAME}" >> "$GITHUB_OUTPUT"
|
||||||
echo "release_name=Arch Linux ISO (${BASE_DATE} Rev ${REVISION})" >> "$GITHUB_OUTPUT"
|
echo "release_name=Arch Linux ISO (${BASE_DATE} Rev ${REVISION})" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
- name: Create Release and Upload ISO via Git LFS
|
- name: Create Release and Upload ISO
|
||||||
env:
|
env:
|
||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
# Use internal Gitea URL to bypass traefik proxy timeout on large uploads
|
# Use internal Gitea URL to bypass traefik proxy timeout on large uploads
|
||||||
GITEA_API: http://192.168.1.168:3000/api/v1
|
GITEA_API: http://192.168.1.168:3000/api/v1
|
||||||
GITEA_PUBLIC_URL: https://git.vilaythong.us
|
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
RELEASES_REPO: alvinlollo/AlvinArch-releases
|
|
||||||
TAG_NAME: ${{ steps.tag.outputs.tag_name }}
|
TAG_NAME: ${{ steps.tag.outputs.tag_name }}
|
||||||
RELEASE_NAME: ${{ steps.tag.outputs.release_name }}
|
RELEASE_NAME: ${{ steps.tag.outputs.release_name }}
|
||||||
run: |
|
run: |
|
||||||
@@ -104,15 +102,6 @@ jobs:
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
RELEASES_OWNER="${RELEASES_REPO%%/*}"
|
|
||||||
RELEASES_NAME="${RELEASES_REPO#*/}"
|
|
||||||
GITEA_BASE="${GITEA_API%/api/v1}"
|
|
||||||
GITEA_SCHEME="${GITEA_BASE%%://*}"
|
|
||||||
GITEA_HOST="${GITEA_BASE#*://}"
|
|
||||||
CLONE_URL="${GITEA_SCHEME}://${RELEASES_OWNER}:${GITEA_TOKEN}@${GITEA_HOST}/${RELEASES_REPO}.git"
|
|
||||||
REPO_DIR="$PWD/.releases-repo"
|
|
||||||
trap 'rm -rf "$REPO_DIR"' EXIT
|
|
||||||
|
|
||||||
# Collect the ISOs produced by the build
|
# Collect the ISOs produced by the build
|
||||||
isos=(out/*.iso)
|
isos=(out/*.iso)
|
||||||
if (( ${#isos[@]} == 0 )); then
|
if (( ${#isos[@]} == 0 )); then
|
||||||
@@ -140,93 +129,14 @@ jobs:
|
|||||||
sha256sums+=("$sha")
|
sha256sums+=("$sha")
|
||||||
done
|
done
|
||||||
|
|
||||||
# Make sure the releases repo exists (create it via API if missing)
|
# Build the release body with SHA-256 checksums
|
||||||
if ! curl -sf -o /dev/null -H "Authorization: token $GITEA_TOKEN" \
|
printf -v body 'Arch Linux live ISO %s\n\nChecksums (SHA-256):\n' "$RELEASE_NAME"
|
||||||
"$GITEA_API/repos/$RELEASES_REPO"; then
|
|
||||||
echo "Creating releases repo '$RELEASES_REPO'..."
|
|
||||||
curl -sf -X POST \
|
|
||||||
-H "Authorization: token $GITEA_TOKEN" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
"$GITEA_API/user/repos" \
|
|
||||||
-d "{\"name\": \"$RELEASES_NAME\", \"description\": \"Compressed Arch Linux live ISOs (Git LFS)\", \"auto_init\": true}" > /dev/null
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Push the compressed ISOs to the releases repo via Git LFS
|
|
||||||
if ! GIT_LFS_SKIP_SMUDGE=1 git clone --quiet "$CLONE_URL" "$REPO_DIR" 2>/dev/null; then
|
|
||||||
echo "❌ Failed to clone $RELEASES_REPO (check token access)." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Work on the 'main' branch (create it if the remote default differs)
|
|
||||||
if git -C "$REPO_DIR" rev-parse --verify -q origin/main >/dev/null 2>&1; then
|
|
||||||
git -C "$REPO_DIR" checkout -q -B main origin/main
|
|
||||||
else
|
|
||||||
git -C "$REPO_DIR" checkout -q -B main
|
|
||||||
fi
|
|
||||||
|
|
||||||
git -C "$REPO_DIR" lfs install --local
|
|
||||||
git -C "$REPO_DIR" lfs track "*.iso.zst"
|
|
||||||
mkdir -p "$REPO_DIR/releases/$TAG_NAME"
|
|
||||||
for zst in "${zst_files[@]}"; do
|
|
||||||
cp "$zst" "$REPO_DIR/releases/$TAG_NAME/"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Seed a short README redirecting to the main repo (status badges on top)
|
|
||||||
cat > "$REPO_DIR/README.md" <<'MDEOF'
|
|
||||||
[](https://git.vilaythong.us/alvinlollo/AlvinArch/actions?workflow=build-iso.yaml)
|
|
||||||
[](https://git.vilaythong.us/alvinlollo/AlvinArch/actions?workflow=tests.yaml)
|
|
||||||
|
|
||||||
# AlvinArch Releases
|
|
||||||
|
|
||||||
Compressed (zstd) Arch Linux live ISOs built automatically by
|
|
||||||
[alvinlollo/AlvinArch](https://git.vilaythong.us/alvinlollo/AlvinArch).
|
|
||||||
|
|
||||||
**Main repository:** [alvinlollo/AlvinArch](https://git.vilaythong.us/alvinlollo/AlvinArch)
|
|
||||||
MDEOF
|
|
||||||
|
|
||||||
git -C "$REPO_DIR" config user.name "Gitea Actions"
|
|
||||||
git -C "$REPO_DIR" config user.email "actions@gitea.local"
|
|
||||||
git -C "$REPO_DIR" add .gitattributes README.md "releases/$TAG_NAME"
|
|
||||||
if git -C "$REPO_DIR" diff --cached --quiet; then
|
|
||||||
echo "⚠️ No changes to commit for $TAG_NAME — releasing as-is." >&2
|
|
||||||
else
|
|
||||||
git -C "$REPO_DIR" commit --quiet -m "Add $TAG_NAME"
|
|
||||||
fi
|
|
||||||
if ! git -C "$REPO_DIR" push --quiet origin main; then
|
|
||||||
echo "❌ Failed to push $TAG_NAME to $RELEASES_REPO." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Free disk space immediately — the clone + LFS objects are multi-GB
|
|
||||||
rm -rf "$REPO_DIR"
|
|
||||||
|
|
||||||
# Verify each LFS object exists server-side (oid == the sha256 we recorded)
|
|
||||||
for i in "${!zst_files[@]}"; do
|
|
||||||
fname=$(basename "${zst_files[$i]}")
|
|
||||||
size=$(stat -c %s "${zst_files[$i]}")
|
|
||||||
oid=${sha256sums[$i]}
|
|
||||||
lfs_payload=$(jq -nc --arg oid "$oid" --argjson sz "$size" \
|
|
||||||
'{operation:"download",transfers:["basic"],objects:[{oid:$oid,size:$sz}]}')
|
|
||||||
obj=$(curl -sf -u "$RELEASES_OWNER:$GITEA_TOKEN" \
|
|
||||||
-H "Content-Type: application/vnd.git-lfs+json" \
|
|
||||||
-d "$lfs_payload" \
|
|
||||||
"$GITEA_BASE/$RELEASES_REPO.git/info/lfs/objects/batch")
|
|
||||||
if [[ "$(jq -r '.objects[0] | has("actions")' <<< "$obj")" != "true" ]]; then
|
|
||||||
echo "❌ Verification failed: LFS object for '$fname' ($size bytes) missing on server." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
echo " ✅ Verified '$fname' ($size bytes) on $RELEASES_REPO"
|
|
||||||
done
|
|
||||||
|
|
||||||
# Create the release with a link to the file directory + SHA-256 checksums
|
|
||||||
DOWNLOAD_URL="$GITEA_PUBLIC_URL/$RELEASES_REPO/src/branch/main/releases/$TAG_NAME"
|
|
||||||
printf -v body 'Arch Linux live ISO %s\n\nDownload: %s\n\nChecksums (SHA-256):\n' \
|
|
||||||
"$RELEASE_NAME" "$DOWNLOAD_URL"
|
|
||||||
for i in "${!zst_files[@]}"; do
|
for i in "${!zst_files[@]}"; do
|
||||||
printf -v line -- '- `%s`: sha256 `%s`\n' "$(basename "${zst_files[$i]}")" "${sha256sums[$i]}"
|
printf -v line -- '- `%s`: sha256 `%s`\n' "$(basename "${zst_files[$i]}")" "${sha256sums[$i]}"
|
||||||
body+="$line"
|
body+="$line"
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Create the release
|
||||||
payload=$(jq -nc --arg tag "$TAG_NAME" --arg name "$RELEASE_NAME" --arg body "$body" \
|
payload=$(jq -nc --arg tag "$TAG_NAME" --arg name "$RELEASE_NAME" --arg body "$body" \
|
||||||
'{tag_name:$tag,name:$name,body:$body}')
|
'{tag_name:$tag,name:$name,body:$body}')
|
||||||
RELEASE_ID=$(curl -sf -X POST \
|
RELEASE_ID=$(curl -sf -X POST \
|
||||||
@@ -234,22 +144,19 @@ jobs:
|
|||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
"$GITEA_API/repos/$REPOSITORY/releases" \
|
"$GITEA_API/repos/$REPOSITORY/releases" \
|
||||||
-d "$payload" | jq -er '.id')
|
-d "$payload" | jq -er '.id')
|
||||||
|
echo " ✅ Created release $TAG_NAME (ID: $RELEASE_ID)"
|
||||||
|
|
||||||
echo " ✅ Released $TAG_NAME (ID: $RELEASE_ID) with download link + SHA-256 checksums"
|
# Upload each .zst file as a release asset
|
||||||
|
for i in "${!zst_files[@]}"; do
|
||||||
# Mirror the release on the releases repo via API (creates tag + release)
|
fname=$(basename "${zst_files[$i]}")
|
||||||
if ! curl -sf -o /dev/null -H "Authorization: token $GITEA_TOKEN" \
|
size=$(stat -c %s "${zst_files[$i]}")
|
||||||
"$GITEA_API/repos/$RELEASES_REPO/releases/tags/$TAG_NAME"; then
|
echo "Uploading $fname ($(( size / 1024 / 1024 )) MiB) to release $TAG_NAME..."
|
||||||
if ! curl -sf -X POST \
|
curl -sf -X POST \
|
||||||
-H "Authorization: token $GITEA_TOKEN" \
|
-H "Authorization: token $GITEA_TOKEN" \
|
||||||
-H "Content-Type: application/json" \
|
-F "attachment=@${zst_files[$i]}" \
|
||||||
"$GITEA_API/repos/$RELEASES_REPO/releases" \
|
"$GITEA_API/repos/$REPOSITORY/releases/$RELEASE_ID/assets" | jq -er '.browser_download_url'
|
||||||
-d "$payload" > /dev/null; then
|
echo " ✅ Uploaded $fname"
|
||||||
echo "⚠️ Failed to mirror release on $RELEASES_REPO (non-fatal)." >&2
|
done
|
||||||
else
|
|
||||||
echo " ✅ Mirrored $TAG_NAME release on $RELEASES_REPO"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
- name: Keep only latest 2 releases
|
- name: Keep only latest 2 releases
|
||||||
if: success()
|
if: success()
|
||||||
@@ -257,27 +164,24 @@ jobs:
|
|||||||
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }}
|
||||||
GITEA_API: http://192.168.1.168:3000/api/v1
|
GITEA_API: http://192.168.1.168:3000/api/v1
|
||||||
REPOSITORY: ${{ github.repository }}
|
REPOSITORY: ${{ github.repository }}
|
||||||
RELEASES_REPO: alvinlollo/AlvinArch-releases
|
|
||||||
run: |
|
run: |
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
test -n "$GITEA_TOKEN"
|
test -n "$GITEA_TOKEN"
|
||||||
|
|
||||||
for repo in "$REPOSITORY" "$RELEASES_REPO"; do
|
echo "Pruning old releases in $REPOSITORY..."
|
||||||
echo "Pruning old releases in $repo..."
|
|
||||||
readarray -t ids < <(curl -sf -H "Authorization: token $GITEA_TOKEN" \
|
readarray -t ids < <(curl -sf -H "Authorization: token $GITEA_TOKEN" \
|
||||||
"$GITEA_API/repos/$repo/releases" \
|
"$GITEA_API/repos/$REPOSITORY/releases" \
|
||||||
| jq -er 'sort_by(.created_at) | .[].id')
|
| jq -er 'sort_by(.created_at) | .[].id')
|
||||||
|
|
||||||
to_delete=$(( ${#ids[@]} - 2 ))
|
to_delete=$(( ${#ids[@]} - 2 ))
|
||||||
if (( to_delete > 0 )); then
|
if (( to_delete > 0 )); then
|
||||||
for ((i = 0; i < to_delete; i++)); do
|
for ((i = 0; i < to_delete; i++)); do
|
||||||
id=${ids[$i]}
|
id=${ids[$i]}
|
||||||
echo "Deleting old release ID: $id (in $repo)"
|
echo "Deleting old release ID: $id"
|
||||||
curl -sf -X DELETE -H "Authorization: token $GITEA_TOKEN" \
|
curl -sf -X DELETE -H "Authorization: token $GITEA_TOKEN" \
|
||||||
"$GITEA_API/repos/$repo/releases/$id"
|
"$GITEA_API/repos/$REPOSITORY/releases/$id"
|
||||||
done
|
done
|
||||||
fi
|
fi
|
||||||
done
|
|
||||||
|
|
||||||
- name: Cleanup mkarchiso mounts and workdirs
|
- name: Cleanup mkarchiso mounts and workdirs
|
||||||
if: always() # Runs on success, failure, or cancellation
|
if: always() # Runs on success, failure, or cancellation
|
||||||
@@ -297,7 +201,7 @@ jobs:
|
|||||||
$PRIV losetup -D || true
|
$PRIV losetup -D || true
|
||||||
|
|
||||||
# Remove working directories with proper permissions
|
# Remove working directories with proper permissions
|
||||||
$PRIV rm -rf "$PWD/work" "$PWD/.releases-repo"
|
$PRIV rm -rf "$PWD/work"
|
||||||
|
|
||||||
- name: Remove built ISO
|
- name: Remove built ISO
|
||||||
if: always()
|
if: always()
|
||||||
|
|||||||
Reference in New Issue
Block a user