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" jobs: nix-update: runs-on: nixos 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: 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 nix eval --raw ".#$pkg.passthru.updateScript" >/dev/null 2>&1 } run_update() { local pkg=$1 local before_hash=$(git rev-parse HEAD) if ! has_update_script "$pkg"; then echo "⏭️ Skipping $pkg (no updateScript defined)" return 1 fi echo "::group::Updating $pkg" if nix-update --flake --commit --use-update-script "$pkg" 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 PACKAGES=$(find pkgs -mindepth 1 -maxdepth 1 -type d -exec basename {} \; 2>/dev/null | sort) if [ -z "$PACKAGES" ]; then echo "No packages found to update" exit 0 fi for pkg in $PACKAGES; do if run_update "$pkg"; then UPDATES_FOUND=true UPDATED_PACKAGES="${UPDATED_PACKAGES}, $pkg" fi done fi UPDATED_PACKAGES=$(echo "$UPDATED_PACKAGES" | sed 's/^, //') 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' run: | cd "$REPO_DIR" IFS=', ' read -ra PKGS <<< "${{ steps.update.outputs.updated_packages }}" for pkg in "${PKGS[@]}"; do echo "Building $pkg..." if ! nix build .#$pkg; then echo "❌ Build failed for $pkg. Aborting push." exit 1 fi echo "✓ Build successful" done - name: Push Changes if: steps.update.outputs.has_updates == 'true' run: | cd "$REPO_DIR" PACKAGES="${{ steps.update.outputs.updated_packages }}" echo "Checking for dirty state..." git status --porcelain git reset --hard HEAD echo "Pulling latest changes (rebase)..." git pull --rebase origin master echo "Pushing changes to master..." git push origin master echo "✓ Successfully pushed updates for: $PACKAGES" - name: Cleanup if: always() run: | rm -f ~/.git-credentials rm -rf "$REPO_DIR" rm -f /tmp/update-*.log - name: Summary if: always() run: | if [ "${{ steps.update.outputs.has_updates }}" = "true" ]; then echo "✅ Successfully updated and pushed: ${{ steps.update.outputs.updated_packages }}" else echo "ℹ️ No updates required." fi