Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor git-pull #3875

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 0 additions & 7 deletions git_pull/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,6 @@ FROM $BUILD_FROM
# Setup base
RUN apk add --no-cache jq curl git openssh-client

# Home Assistant CLI
ARG BUILD_ARCH
ARG CLI_VERSION
RUN curl -Lso /usr/bin/ha \
"https://github.com/home-assistant/cli/releases/download/${CLI_VERSION}/ha_${BUILD_ARCH}" \
&& chmod a+x /usr/bin/ha

# Copy data
COPY data/run.sh /

Expand Down
237 changes: 121 additions & 116 deletions git_pull/data/run.sh
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
#!/bin/bash
#!/usr/bin/with-contenv bashio

#### config ####

CONFIG_PATH=/data/options.json
HOME=~

DEPLOYMENT_KEY=$(jq --raw-output ".deployment_key[]" $CONFIG_PATH)
DEPLOYMENT_KEY_PROTOCOL=$(jq --raw-output ".deployment_key_protocol" $CONFIG_PATH)
DEPLOYMENT_USER=$(jq --raw-output ".deployment_user" $CONFIG_PATH)
DEPLOYMENT_PASSWORD=$(jq --raw-output ".deployment_password" $CONFIG_PATH)
GIT_BRANCH=$(jq --raw-output '.git_branch' $CONFIG_PATH)
GIT_COMMAND=$(jq --raw-output '.git_command' $CONFIG_PATH)
GIT_REMOTE=$(jq --raw-output '.git_remote' $CONFIG_PATH)
GIT_PRUNE=$(jq --raw-output '.git_prune' $CONFIG_PATH)
REPOSITORY=$(jq --raw-output '.repository' $CONFIG_PATH)
AUTO_RESTART=$(jq --raw-output '.auto_restart' $CONFIG_PATH)
RESTART_IGNORED_FILES=$(jq --raw-output '.restart_ignore | join(" ")' $CONFIG_PATH)
REPEAT_ACTIVE=$(jq --raw-output '.repeat.active' $CONFIG_PATH)
REPEAT_INTERVAL=$(jq --raw-output '.repeat.interval' $CONFIG_PATH)
DEPLOYMENT_KEY=$(bashio::config 'deployment_key')
DEPLOYMENT_KEY_PROTOCOL=$(bashio::config 'deployment_key_protocol')
DEPLOYMENT_USER=$(bashio::config 'deployment_user')
DEPLOYMENT_PASSWORD=$(bashio::config 'deployment_password')
GIT_BRANCH=$(bashio::config 'git_branch')
GIT_COMMAND=$(bashio::config 'git_command')
GIT_REMOTE=$(bashio::config 'git_remote')
GIT_PRUNE=$(bashio::config 'git_prune')
REPOSITORY=$(bashio::config 'repository')
AUTO_RESTART=$(bashio::config 'auto_restart')
RESTART_IGNORED_FILES=$(bashio::config 'restart_ignore | join(" ")')
REPEAT_ACTIVE=$(bashio::config 'repeat.active')
REPEAT_INTERVAL=$(bashio::config 'repeat.interval')
################

#### functions ####
function add-ssh-key {
echo "[Info] Start adding SSH key"
bashio::log.info "[Info] Start adding SSH key"
mkdir -p ~/.ssh

(
echo "Host *"
echo " StrictHostKeyChecking no"
) > ~/.ssh/config

echo "[Info] Setup deployment_key on id_${DEPLOYMENT_KEY_PROTOCOL}"
bashio::log.info "[Info] Setup deployment_key on id_${DEPLOYMENT_KEY_PROTOCOL}"
rm -f "${HOME}/.ssh/id_${DEPLOYMENT_KEY_PROTOCOL}"
while read -r line; do
echo "$line" >> "${HOME}/.ssh/id_${DEPLOYMENT_KEY_PROTOCOL}"
Expand All @@ -43,17 +43,17 @@ function add-ssh-key {
function git-clone {
# create backup
BACKUP_LOCATION="/tmp/config-$(date +%Y-%m-%d_%H-%M-%S)"
echo "[Info] Backup configuration to $BACKUP_LOCATION"
bashio::log.info "[Info] Backup configuration to $BACKUP_LOCATION"

mkdir "${BACKUP_LOCATION}" || { echo "[Error] Creation of backup directory failed"; exit 1; }
cp -rf /config/* "${BACKUP_LOCATION}" || { echo "[Error] Copy files to backup directory failed"; exit 1; }
mkdir "${BACKUP_LOCATION}" || bashio::exit.nok "[Error] Creation of backup directory failed"
cp -rf /config/* "${BACKUP_LOCATION}" || bashio::exit.nok "[Error] Copy files to backup directory failed"

# remove config folder content
rm -rf /config/{,.[!.],..?}* || { echo "[Error] Clearing /config failed"; exit 1; }
rm -rf /config/{,.[!.],..?}* || { bashio::exit.nok "[Error] Clearing /config failed"
raypappa marked this conversation as resolved.
Show resolved Hide resolved

# git clone
echo "[Info] Start git clone"
git clone "$REPOSITORY" /config || { echo "[Error] Git clone failed"; exit 1; }
bashio::log.info "[Info] Start git clone"
git clone "$REPOSITORY" /config || bashio::exit.nok "[Error] Git clone failed"

# try to copy non yml files back
cp "${BACKUP_LOCATION}" "!(*.yaml)" /config 2>/dev/null
Expand All @@ -64,14 +64,14 @@ function git-clone {

function check-ssh-key {
if [ -n "$DEPLOYMENT_KEY" ]; then
echo "Check SSH connection"
bashio::log.info "Check SSH connection"
IFS=':' read -ra GIT_URL_PARTS <<< "$REPOSITORY"
# shellcheck disable=SC2029
DOMAIN="${GIT_URL_PARTS[0]}"
if OUTPUT_CHECK=$(ssh -T -o "StrictHostKeyChecking=no" -o "BatchMode=yes" "$DOMAIN" 2>&1) || { [[ $DOMAIN = *"@github.com"* ]] && [[ $OUTPUT_CHECK = *"You've successfully authenticated"* ]]; }; then
echo "[Info] Valid SSH connection for $DOMAIN"
bashio::log.info "[Info] Valid SSH connection for $DOMAIN"
else
echo "[Warn] No valid SSH connection for $DOMAIN"
bashio::log.warn "[Warn] No valid SSH connection for $DOMAIN"
add-ssh-key
fi
fi
Expand All @@ -80,7 +80,7 @@ fi
function setup-user-password {
if [ -n "$DEPLOYMENT_USER" ]; then
cd /config || return
echo "[Info] setting up credential.helper for user: ${DEPLOYMENT_USER}"
bashio::log.info "[Info] setting up credential.helper for user: ${DEPLOYMENT_USER}"
git config --system credential.helper 'store --file=/tmp/git-credentials'

# Extract the hostname from repository
Expand Down Expand Up @@ -108,124 +108,129 @@ password=${DEPLOYMENT_PASSWORD}
"

# Use git commands to write the credentials to ~/.git-credentials
echo "[Info] Saving git credentials to /tmp/git-credentials"
bashio::log.info "[Info] Saving git credentials to /tmp/git-credentials"
# shellcheck disable=SC2259
git credential fill | git credential approve <<< "$cred_data"
fi
}

function git-synchronize {
# is /config a local git repo?
if git rev-parse --is-inside-work-tree &>/dev/null
then
echo "[Info] Local git repository exists"

# Is the local repo set to the correct origin?
CURRENTGITREMOTEURL=$(git remote get-url --all "$GIT_REMOTE" | head -n 1)
if [ "$CURRENTGITREMOTEURL" = "$REPOSITORY" ]
then
echo "[Info] Git origin is correctly set to $REPOSITORY"
OLD_COMMIT=$(git rev-parse HEAD)

# Always do a fetch to update repos
echo "[Info] Start git fetch..."
git fetch "$GIT_REMOTE" || { echo "[Error] Git fetch failed"; return 1; }

# Prune if configured
if [ "$GIT_PRUNE" == "true" ]
then
echo "[Info] Start git prune..."
git prune || { echo "[Error] Git prune failed"; return 1; }
fi
if ! git rev-parse --is-inside-work-tree &>/dev/null; then
bashio::log.warn "[Warn] Git repository doesn't exist"
git-clone
return
fi

# Do we switch branches?
GIT_CURRENT_BRANCH=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD)
if [ -z "$GIT_BRANCH" ] || [ "$GIT_BRANCH" == "$GIT_CURRENT_BRANCH" ]; then
echo "[Info] Staying on currently checked out branch: $GIT_CURRENT_BRANCH..."
else
echo "[Info] Switching branches - start git checkout of branch $GIT_BRANCH..."
git checkout "$GIT_BRANCH" || { echo "[Error] Git checkout failed"; exit 1; }
GIT_CURRENT_BRANCH=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD)
fi
bashio::log.info "[Info] Local git repository exists"
# Is the local repo set to the correct origin?
CURRENTGITREMOTEURL=$(git remote get-url --all "$GIT_REMOTE" | head -n 1)
if [ "$CURRENTGITREMOTEURL" != "$REPOSITORY" ]; then
bashio::exit.nok "[Error] git origin does not match $REPOSITORY!";
return
fi

bashio::log.info "[Info] Git origin is correctly set to $REPOSITORY"
OLD_COMMIT=$(git rev-parse HEAD)

# Always do a fetch to update repos
bashio::log.info "[Info] Start git fetch..."
git fetch "$GIT_REMOTE" "$GIT_BRANCH" || bashio::exit.nok "[Error] Git fetch failed";

# Pull or reset depending on user preference
case "$GIT_COMMAND" in
pull)
echo "[Info] Start git pull..."
git pull || { echo "[Error] Git pull failed"; return 1; }
;;
reset)
echo "[Info] Start git reset..."
git reset --hard "$GIT_REMOTE"/"$GIT_CURRENT_BRANCH" || { echo "[Error] Git reset failed"; return 1; }
;;
*)
echo "[Error] Git command is not set correctly. Should be either 'reset' or 'pull'"
exit 1
;;
esac
else
echo "[Error] git origin does not match $REPOSITORY!"; exit 1;
fi
# Prune if configured
if [ "$GIT_PRUNE" == "true" ]
then
bashio::log.info "[Info] Start git prune..."
git prune || bashio::exit.nok "[Error] Git prune failed";
fi

# Do we switch branches?
GIT_CURRENT_BRANCH=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD)
if [ -z "$GIT_BRANCH" ] || [ "$GIT_BRANCH" == "$GIT_CURRENT_BRANCH" ]; then
bashio::log.info "[Info] Staying on currently checked out branch: $GIT_CURRENT_BRANCH..."
else
echo "[Warn] Git repository doesn't exist"
git-clone
bashio::log.info "[Info] Switching branches - start git checkout of branch $GIT_BRANCH..."
git checkout "$GIT_BRANCH" || bashio::exit.nok "[Error] Git checkout failed"
GIT_CURRENT_BRANCH=$(git rev-parse --symbolic-full-name --abbrev-ref HEAD)
fi

# Pull or reset depending on user preference
case "$GIT_COMMAND" in
pull)
bashio::log.info "[Info] Start git pull..."
git pull || bashio::exit.nok "[Error] Git pull failed";
;;
reset)
bashio::log.info "[Info] Start git reset..."
git reset --hard "$GIT_REMOTE"/"$GIT_CURRENT_BRANCH" || bashio::exit.nok "[Error] Git reset failed";
;;
*)
bashio::exit.nok "[Error] Git command is not set correctly. Should be either 'reset' or 'pull'"
;;
esac
}

function validate-config {
echo "[Info] Checking if something has changed..."
bashio::log.info "[Info] Checking if something has changed..."
# Compare commit ids & check config
NEW_COMMIT=$(git rev-parse HEAD)
if [ "$NEW_COMMIT" != "$OLD_COMMIT" ]; then
echo "[Info] Something has changed, checking Home-Assistant config..."
if ha --no-progress core check; then
if [ "$AUTO_RESTART" == "true" ]; then
DO_RESTART="false"
CHANGED_FILES=$(git diff "$OLD_COMMIT" "$NEW_COMMIT" --name-only)
echo "Changed Files: $CHANGED_FILES"
if [ -n "$RESTART_IGNORED_FILES" ]; then
for changed_file in $CHANGED_FILES; do
restart_required_file=""
for restart_ignored_file in $RESTART_IGNORED_FILES; do
if [ -d "$restart_ignored_file" ]; then
# file to be ignored is a whole dir
restart_required_file=$(echo "${changed_file}" | grep "^${restart_ignored_file}")
else
restart_required_file=$(echo "${changed_file}" | grep "^${restart_ignored_file}$")
fi
# break on first match
if [ -n "$restart_required_file" ]; then break; fi
done
if [ -z "$restart_required_file" ]; then
DO_RESTART="true"
echo "[Info] Detected restart-required file: $changed_file"
fi
done
else
DO_RESTART="true"
fi
if [ "$DO_RESTART" == "true" ]; then
echo "[Info] Restart Home-Assistant"
ha --no-progress core restart 2&> /dev/null
if [ "$NEW_COMMIT" == "$OLD_COMMIT" ]; then
bashio::log.info "[Info] Nothing has changed."
return
fi
bashio::log.info "[Info] Something has changed, checking Home-Assistant config..."
if ! bashio::core.check; then
bashio::log.error "[Error] Configuration updated but it does not pass the config check. Do not restart until this is fixed!"
return
fi
if [ "$AUTO_RESTART" != "true" ]; then
bashio::log.info "[Info] Local configuration has changed. Restart required."
return
fi
DO_RESTART="false"
CHANGED_FILES=$(git diff "$OLD_COMMIT" "$NEW_COMMIT" --name-only)
bashio::log.info "Changed Files: $CHANGED_FILES"
if [ -n "$RESTART_IGNORED_FILES" ]; then
for changed_file in $CHANGED_FILES; do
restart_required_file=""
for restart_ignored_file in $RESTART_IGNORED_FILES; do
bashio::log.info "[Info] Checking: $changed_file for $restart_ignored_file"
if [ -d "$restart_ignored_file" ]; then
# file to be ignored is a whole dir
set +e
restart_required_file=$(echo "${changed_file}" | grep "^${restart_ignored_file}")
set -e
else
echo "[Info] No Restart Required, only ignored changes detected"
set +e
restart_required_file=$(echo "${changed_file}" | grep "^${restart_ignored_file}$")
set -e
fi
# break on first match
if [ -n "$restart_required_file" ]; then break; fi
done
if [ -z "$restart_required_file" ]; then
DO_RESTART="true"
bashio::log.info "[Info] Detected restart-required file: $changed_file"
else
echo "[Info] Local configuration has changed. Restart required."
bashio::log.info "[Info] Detected ignored file: $changed_file"
fi
else
echo "[Error] Configuration updated but it does not pass the config check. Do not restart until this is fixed!"
fi
done
else
DO_RESTART="true"
fi

if [ "$DO_RESTART" == "true" ]; then
bashio::log.info "[Info] Restart Home-Assistant"
bashio::core.restart
else
echo "[Info] Nothing has changed."
bashio::log.info "[Info] No Restart Required, only ignored changes detected"
fi
}

###################

#### Main program ####
cd /config || { echo "[Error] Failed to cd into /config"; exit 1; }
cd /config || bashio::exit.nok "[Error] Failed to cd into /config";

while true; do
check-ssh-key
Expand Down