From 0fb89ef74d41409d57c74d0828c37056ed95cb72 Mon Sep 17 00:00:00 2001
From: clerie <git@clerie.de>
Date: Tue, 19 Mar 2024 17:31:18 +0100
Subject: [PATCH] pkgs/clerie-update-nixfiles: Add script that merges back
 nixfiles updates

---
 flake.nix                                     |   1 +
 .../clerie-merge-nixfiles-update.nix          |  13 ++
 .../clerie-merge-nixfiles-update.sh           | 122 ++++++++++++++++++
 pkgs/overlay.nix                              |   1 +
 4 files changed, 137 insertions(+)
 create mode 100644 pkgs/clerie-update-nixfiles/clerie-merge-nixfiles-update.nix
 create mode 100755 pkgs/clerie-update-nixfiles/clerie-merge-nixfiles-update.sh

diff --git a/flake.nix b/flake.nix
index 192ddd4..aa46d87 100644
--- a/flake.nix
+++ b/flake.nix
@@ -113,6 +113,7 @@
     in {
       inherit (pkgs)
         clerie-system-upgrade
+        clerie-merge-nixfiles-update
         clerie-update-nixfiles
         chromium-incognito
         iot-data
diff --git a/pkgs/clerie-update-nixfiles/clerie-merge-nixfiles-update.nix b/pkgs/clerie-update-nixfiles/clerie-merge-nixfiles-update.nix
new file mode 100644
index 0000000..ed37399
--- /dev/null
+++ b/pkgs/clerie-update-nixfiles/clerie-merge-nixfiles-update.nix
@@ -0,0 +1,13 @@
+{ pkgs, ... }:
+
+pkgs.writeShellApplication {
+  name = "clerie-merge-nixfiles-update";
+  text = builtins.readFile ./clerie-merge-nixfiles-update.sh;
+  runtimeInputs = with pkgs; [
+    curl
+    git
+    jq
+    openssh
+  ];
+}
+
diff --git a/pkgs/clerie-update-nixfiles/clerie-merge-nixfiles-update.sh b/pkgs/clerie-update-nixfiles/clerie-merge-nixfiles-update.sh
new file mode 100755
index 0000000..7f402d3
--- /dev/null
+++ b/pkgs/clerie-update-nixfiles/clerie-merge-nixfiles-update.sh
@@ -0,0 +1,122 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+xgit() {
+	git -c "user.name=Flake Update Bot" -c "user.email=flake-update-bot@clerie.de" "$@"
+}
+
+xgit_parent_commits() {
+	xgit show -q --format="%P" "$@" | sed "s/ /\n/g"
+}
+
+xgit_refs_for_commit() {
+	xgit show -q --format="%D" "$@" | sed "s/, /\n/g" | sed -E "s/((.+) -> )?(.+)/\3/g"
+}
+
+commit_is_head_of_branch() {
+	COMMIT="$1"
+	BRANCH="$2"
+	xgit_refs_for_commit "${COMMIT}" | grep -E "^${BRANCH}$" > /dev/null
+}
+
+no_confirm=""
+
+while [[ $# -gt 0 ]]; do
+  case $1 in
+  --no-confirm)
+    no_confirm=1
+    shift
+    ;;
+  *)
+    echo "unknown option: $1"
+    exit 1
+    ;;
+  esac
+done
+
+echo "[!] Init git repo"
+xgit status > /dev/null || xgit clone gitea@git.clerie.de:clerie/nixfiles.git .
+
+echo "[!] Make sure git repo is up to date"
+xgit fetch --all
+
+echo "[!] Checkout master"
+xgit checkout master
+
+echo "[!] Update master"
+xgit pull origin master
+
+echo "[!] Fetch git commit of last hydra run"
+echo "[!] Checking https://hydra.clerie.de/jobset/nixfiles/nixfiles-updated-inputs/latest-eval"
+GIT_REV_OF_LAST_HYDRA_RUN=$(curl --json "" -X GET -L https://hydra.clerie.de/jobset/nixfiles/nixfiles-updated-inputs/latest-eval 2> /dev/null | \
+	jq -r .flake | sed -E "s/.+&rev=(.*)/\1/g")
+echo "[!] Last hydra ran from ${GIT_REV_OF_LAST_HYDRA_RUN} (https://git.clerie.de/clerie/nixfiles/commit/${GIT_REV_OF_LAST_HYDRA_RUN})"
+
+echo "[!] Check if commit is current head of origin/updated-inputs"
+set +e
+if ! commit_is_head_of_branch "${GIT_REV_OF_LAST_HYDRA_RUN}" "origin/updated-inputs"; then
+	echo "[!] Commit is not head of origin/updated-inputs"
+	echo "[!] Hydra seem to still process the current head of origin/updated-inputs"
+	exit 0
+fi
+set -e
+
+echo "[!] Find out update branch"
+PARENT_COMMITS=$(xgit_parent_commits "${GIT_REV_OF_LAST_HYDRA_RUN}")
+
+update_branch=
+for commit in $PARENT_COMMITS; do
+	set +e
+	if update_branch=$(xgit_refs_for_commit "${commit}" | sort -d | grep -E "^origin/updated-inputs-.+$" | head -1); then
+		break
+	fi
+	set -e
+done
+
+if [[ -z "$update_branch" ]]; then
+	echo "[!] No update branch found"
+	exit 0
+fi
+
+echo "[!] Update branch $update_branch"
+
+echo "[!] Check if update branch forks from current master"
+contains_current_master_head=
+for commit in $(git rev-list "${update_branch}"); do
+	set +e
+	if xgit_refs_for_commit "${commit}" | sort -d | grep -E "^master$" | head -1 > /dev/null; then
+		contains_current_master_head=1
+		break
+	fi
+	set -e
+done
+
+if [[ -z "$contains_current_master_head" ]]; then
+	echo "[!] ${update_branch} does not contain the current master head"
+	echo "[!] Cannot merge ${update_branch}"
+	exit 0
+fi
+
+echo "[!] ${update_branch} can be merged into master"
+
+merge_diff=$(xgit diff --color master "${update_branch}")
+
+if [[ -z $merge_diff ]]; then
+	echo "[!] Nothing changes, nothing to merge"
+	exit 0
+fi
+
+echo "${merge_diff}"
+
+if [[ -z $no_confirm ]]; then
+  read -e -r -p "[?] Merge ${update_branch} into master?" confirm
+  echo "$confirm" > /dev/null
+fi
+
+echo "[!] Merging ${update_branch} into master"
+
+xgit merge --ff-only "${update_branch}"
+
+
+echo "[!] Merge successful"
diff --git a/pkgs/overlay.nix b/pkgs/overlay.nix
index 5a6c751..644a48c 100644
--- a/pkgs/overlay.nix
+++ b/pkgs/overlay.nix
@@ -1,5 +1,6 @@
 final: prev: {
   clerie-system-upgrade = final.callPackage ./clerie-system-upgrade/clerie-system-upgrade.nix {};
+  clerie-merge-nixfiles-update = final.callPackage ./clerie-update-nixfiles/clerie-merge-nixfiles-update.nix {};
   clerie-update-nixfiles = final.callPackage ./clerie-update-nixfiles/clerie-update-nixfiles.nix {};
   chromium-incognito = final.callPackage ./chromium-incognito {};
   iot-data = final.python3.pkgs.callPackage ./iot-data {};