Files
nixpkgs/.gitea/workflows/nix-update.yml
2026-01-21 07:17:01 +01:00

424 lines
14 KiB
YAML
Raw Permalink Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
name: Update Nix Packages with nix-update
on:
schedule:
- cron: "0 2,14 * * *" # Every 12 hours at 2 AM and 2 PM
workflow_dispatch:
inputs:
package:
description: "Specific package to update (optional)"
required: false
type: string
concurrency:
group: nix-update-${{ github.ref }}
cancel-in-progress: true
env:
GIT_AUTHOR_NAME: "nix-update bot"
GIT_AUTHOR_EMAIL: "bot@m3ta.dev"
GIT_COMMITTER_NAME: "nix-update bot"
GIT_COMMITTER_EMAIL: "bot@m3ta.dev"
REPO_DIR: "/tmp/nixpkgs"
# Nix configuration
NIX_PATH: "nixpkgs=channel:nixos-unstable"
NIX_CONFIG: "experimental-features = nix-command flakes"
# Non-interactive mode
DEBIAN_FRONTEND: "noninteractive"
GIT_TERMINAL_PROMPT: "0"
jobs:
nix-update:
runs-on: nixos
timeout-minutes: 180
steps:
- name: Setup Environment and Authenticate
run: |
if [ -d "$REPO_DIR" ]; then rm -rf "$REPO_DIR"; fi
git config --global credential.helper store
echo "https://m3tam3re:${{ secrets.NIX_UPDATE_TOKEN }}@code.m3ta.dev" > ~/.git-credentials
chmod 600 ~/.git-credentials
git config --global user.name "$GIT_AUTHOR_NAME"
git config --global user.email "$GIT_AUTHOR_EMAIL"
git config --global init.defaultBranch master
- name: Checkout Repository
run: |
git clone --no-single-branch \
"https://m3tam3re@code.m3ta.dev/m3tam3re/nixpkgs.git" \
"$REPO_DIR"
- name: Update opencode Flake Input
id: update-opencode
run: |
cd "$REPO_DIR"
echo "::group::Checking for opencode updates"
# Get latest release from GitHub API (strip v prefix for comparison)
LATEST_RELEASE=$(curl -s "https://api.github.com/repos/anomalyco/opencode/releases/latest" | jq -r '.tag_name' | sed 's/^v//')
# Extract current version from flake.nix
CURRENT_VERSION=$(grep -oP 'opencode\.url = "github:anomalyco/opencode/v\K[^"]+' flake.nix)
echo "Current opencode version: $CURRENT_VERSION"
echo "Latest opencode version: $LATEST_RELEASE"
# Check if update is needed
if [ "$LATEST_RELEASE" != "$CURRENT_VERSION" ]; then
echo "🔄 Updating opencode from $CURRENT_VERSION to $LATEST_RELEASE"
# Update flake.nix with new version
sed -i 's|opencode\.url = "github:anomalyco/opencode/v.*"|opencode.url = "github:anomalyco/opencode/v'"$LATEST_RELEASE"'"|' flake.nix
# Update flake lock to fetch new revision
nix flake update opencode
# Format with alejandra
nix fmt flake.nix
# Verify the update
echo "::endgroup::"
echo "::group::Verifying opencode update"
# Run flake check
if ! nix flake check; then
echo "❌ Flake check failed after opencode update"
git checkout flake.nix flake.lock
exit 1
fi
# Build opencode package
if ! nix build .#opencode 2>&1 | tee /tmp/opencode-build.log; then
echo "❌ Build failed for opencode"
git checkout flake.nix flake.lock
exit 1
fi
echo "✅ Flake check passed"
echo "✅ Build successful for opencode"
echo "::endgroup::"
# Commit the change
echo "::group::Committing opencode update"
git add flake.nix flake.lock
git commit -m "chore: update opencode flake input to $LATEST_RELEASE"
echo "opencode_update=true" >> $GITHUB_OUTPUT
echo "opencode_version=${LATEST_RELEASE}" >> $GITHUB_OUTPUT
echo "::endgroup::"
echo "✅ Updated opencode to $LATEST_RELEASE"
else
echo "✓ opencode is already up to date"
echo "opencode_update=false" >> $GITHUB_OUTPUT
echo "opencode_version=${CURRENT_VERSION}" >> $GITHUB_OUTPUT
echo "::endgroup::"
fi
- name: Check Prerequisites
id: check
run: |
cd "$REPO_DIR"
if [ ! -d "pkgs" ]; then
echo "❌ Error: 'pkgs' directory not found."
exit 1
fi
if [ -f "flake.nix" ]; then
echo "has_flake=true" >> $GITHUB_OUTPUT
else
echo "has_flake=false" >> $GITHUB_OUTPUT
fi
- name: Update Packages
id: update
run: |
cd "$REPO_DIR"
set -e
git checkout master
UPDATES_FOUND=false
UPDATED_PACKAGES=""
check_commit() {
[ "$1" != "$(git rev-parse HEAD)" ] && echo "true" || echo "false"
}
has_update_script() {
local pkg=$1
# Check if package has passthru.updateScript attribute
nix eval .#${pkg}.passthru.updateScript --json >/dev/null 2>&1
}
run_update() {
local pkg=$1
local before_hash=$(git rev-parse HEAD)
echo "::group::Updating $pkg"
local args=("--flake" "--commit" "--use-github-releases")
args+=("$pkg")
if nix-update "${args[@]}" 2>&1 | tee /tmp/update-${pkg}.log; then
if [ "$(check_commit "$before_hash")" = "true" ]; then
echo "✅ Updated $pkg"
echo "::endgroup::"
return 0
fi
fi
echo "::endgroup::"
if ! grep -q "already up to date\|No new version found" /tmp/update-${pkg}.log; then
echo "⚠️ Update failed for $pkg"
fi
return 1
}
if [ -n "${{ inputs.package }}" ]; then
pkg="${{ inputs.package }}"
if [ -d "pkgs/$pkg" ]; then
if run_update "$pkg"; then
UPDATES_FOUND=true
UPDATED_PACKAGES="$pkg"
fi
else
echo "❌ Package 'pkgs/$pkg' not found"
fi
else
# Dynamically discover packages with updateScript attribute
echo "🔍 Discovering packages with passthru.updateScript..."
# Get all packages and filter those with updateScript
ALL_PACKAGES=$(find pkgs -mindepth 1 -maxdepth 1 -type d -exec basename {} \; 2>/dev/null | sort)
UPDATABLE_PACKAGES=""
if [ -z "$ALL_PACKAGES" ]; then
echo "No packages found in pkgs/"
exit 0
fi
for pkg in $ALL_PACKAGES; do
if has_update_script "$pkg"; then
echo " ✓ $pkg (has updateScript)"
UPDATABLE_PACKAGES="$UPDATABLE_PACKAGES $pkg"
else
echo " ⊘ $pkg (no updateScript - skipping)"
fi
done
if [ -z "$UPDATABLE_PACKAGES" ]; then
echo " No packages with updateScript found."
exit 0
fi
echo ""
echo "📦 Found $(echo $UPDATABLE_PACKAGES | wc -w) updatable packages"
echo ""
# Parallel updates with 4 concurrent jobs
MAX_JOBS=4
JOB_COUNT=0
SUCCESS_LIST=()
for pkg in $UPDATABLE_PACKAGES; do
(run_update "$pkg" && echo "$pkg" >> /tmp/success.txt || true) &
JOB_COUNT=$((JOB_COUNT + 1))
# Wait if we hit max concurrent jobs
if [ $JOB_COUNT -ge $MAX_JOBS ]; then
wait
JOB_COUNT=0
fi
done
# Wait for remaining jobs
wait
# Parse results
if [ -f /tmp/success.txt ]; then
SUCCESS_LIST=$(cat /tmp/success.txt | tr '\n' ' ')
UPDATED_PACKAGES=$(echo "$SUCCESS_LIST" | sed 's/ /, /g' | sed 's/, $//')
UPDATES_FOUND=true
fi
rm -f /tmp/success.txt
fi
COMMIT_COUNT=$(git rev-list --count origin/master..HEAD)
if [ "$COMMIT_COUNT" -gt 0 ]; then
echo "✅ $COMMIT_COUNT updates committed locally."
echo "has_updates=true" >> $GITHUB_OUTPUT
echo "updated_packages=${UPDATED_PACKAGES}" >> $GITHUB_OUTPUT
else
echo " No updates found."
echo "has_updates=false" >> $GITHUB_OUTPUT
fi
- name: Verify Builds
if: steps.update.outputs.has_updates == 'true' || steps.update-opencode.outputs.opencode_update == 'true'
run: |
cd "$REPO_DIR"
echo "::group::Running flake check"
if ! nix flake check; then
echo "❌ Flake check failed"
exit 1
fi
echo "✅ Flake check passed"
echo "::endgroup::"
IFS=', ' read -ra PKGS <<< "${{ steps.update.outputs.updated_packages }}"
FAILED_PACKAGES=()
SUCCESSFUL_PACKAGES=()
for pkg in "${PKGS[@]}"; do
echo "::group::Building $pkg"
if nix build .#$pkg 2>&1 | tee /tmp/build-${pkg}.log; then
echo "✅ Build successful for $pkg"
SUCCESSFUL_PACKAGES+=("$pkg")
else
echo "❌ Build failed for $pkg"
FAILED_PACKAGES+=("$pkg")
fi
echo "::endgroup::"
done
if [ ${#FAILED_PACKAGES[@]} -gt 0 ]; then
echo ""
echo "❌ Failed packages: ${FAILED_PACKAGES[*]}"
echo "✅ Successful packages: ${SUCCESSFUL_PACKAGES[*]}"
echo ""
# Upload logs as artifacts for debugging
echo "## Build Failure Logs" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
for pkg in "${FAILED_PACKAGES[@]}"; do
echo "### $pkg" >> $GITHUB_STEP_SUMMARY
echo '```bash' >> $GITHUB_STEP_SUMMARY
cat /tmp/build-${pkg}.log >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
done
exit 1
fi
echo ""
echo "✅ All packages built successfully: ${SUCCESSFUL_PACKAGES[*]}"
- name: Push Changes
if: steps.update.outputs.has_updates == 'true' || steps.update-opencode.outputs.opencode_update == 'true'
run: |
cd "$REPO_DIR"
PACKAGES="${{ steps.update.outputs.updated_packages }}"
# Add opencode to packages list if it was updated
if [ "${{ steps.update-opencode.outputs.opencode_update }}" = "true" ]; then
if [ -n "$PACKAGES" ]; then
PACKAGES="$PACKAGES, opencode"
else
PACKAGES="opencode"
fi
fi
echo "::group::Git Operations"
echo "Current commit: $(git rev-parse HEAD)"
echo "Pending commits: $(git rev-list --count origin/master..HEAD)"
echo ""
echo "Pulling latest changes (rebase)..."
if git pull --rebase origin master; then
echo "✅ Rebase successful"
else
echo "⚠️ Rebase failed, attempting force push..."
git reset --hard origin/master
git push --force-with-lease origin master
echo "✓ Force push completed"
exit 0
fi
echo ""
echo "Pushing changes to master..."
git push origin master
echo ""
echo "✅ Successfully pushed updates for: $PACKAGES"
echo "::endgroup::"
- name: Upload Build Logs
if: failure()
uses: actions/upload-artifact@v4
with:
name: build-logs-${{ github.run_number }}
path: |
/tmp/update-*.log
/tmp/build-*.log
/tmp/opencode-build.log
retention-days: 7
- name: Cleanup
if: always()
run: |
# Remove git credentials securely
rm -f ~/.git-credentials
git config --global --unset credential.helper 2>/dev/null || true
# Remove temporary directory
rm -rf "$REPO_DIR"
# Remove all log files
rm -f /tmp/update-*.log /tmp/build-*.log /tmp/opencode-build.log /tmp/update-log.txt /tmp/success-packages.txt
# Clear sensitive environment variables
unset GIT_AUTHOR_EMAIL GIT_COMMITTER_EMAIL
- name: Summary
if: always()
run: |
HAS_UPDATES="false"
if [ "${{ steps.update.outputs.has_updates }}" = "true" ]; then
HAS_UPDATES="true"
echo "# ✅ Update Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Updated Packages" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "\`${{ steps.update.outputs.updated_packages }}\`" >> $GITHUB_STEP_SUMMARY
fi
if [ "${{ steps.update-opencode.outputs.opencode_update }}" = "true" ]; then
HAS_UPDATES="true"
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Updated Flake Input" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **opencode**: \`v${{ steps.update-opencode.outputs.opencode_version }}\`" >> $GITHUB_STEP_SUMMARY
fi
if [ "$HAS_UPDATES" = "true" ]; then
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Status" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- ✅ All updates validated with \`nix flake check\`" >> $GITHUB_STEP_SUMMARY
echo "- ✅ All builds successful" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Changes pushed to master" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Workflow Performance" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- Started: ${{ github.event.head_commit.timestamp }}" >> $GITHUB_STEP_SUMMARY
echo "- Completed: $(date -u +'%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
echo "- Workflow Run: [#${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})" >> $GITHUB_STEP_SUMMARY
else
echo "# No Updates Required" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "No updates found this run. All packages and flake inputs are up to date." >> $GITHUB_STEP_SUMMARY
fi