diff --git a/.githooks/post-receive b/.githooks/post-receive index 28ef6d0..19644d5 100644 --- a/.githooks/post-receive +++ b/.githooks/post-receive @@ -70,6 +70,69 @@ systemctl --user restart express-blog@"$branch".service } +# Smart dependency installation (only if package files changed) +get_dependencies() { + local oldrev="$1" + local newrev="$2" + local install_required=true + if [[ -n "$oldrev" && "$oldrev" != "0000000000000000000000000000000000000000" ]]; then + if ! git --git-dir="$GIT_DIR" diff-tree --name-only -r "$oldrev..$newrev" | grep -qE "(package\.json|yarn\.lock)$"; then + echo "No changes detected in package.json or yarn.lock. Skipping yarn install." + install_required=false + else + echo "Changes detected in package.json or yarn.lock. Running yarn install." + fi + else + echo "Running yarn install (initial deployment)." + fi + + if [[ "$install_required" == "true" ]]; then + yarn + fi +} + +# Single function to handle all repo and submodule updates (force-push safe) +update_repo_and_submodules() { + local branch="$1" + local deploy_path="$2" + + echo "Updating repository and submodules (force-push safe)..." + + cd "$deploy_path" || { + echo "Error: Could not change directory to $deploy_path" + return 1 + } + SAVED_GIT_DIR="$GIT_DIR" + unset GIT_DIR + + git remote show + git branch -l + # Update main repository - always fetch and hard reset (handles force pushes) + echo "Fetching and updating main repository..." + git fetch origin || { + echo "Error: Failed to fetch from origin" + return 1 + } + + git reset --hard "origin/$branch" || { + echo "Error: Failed to reset to origin/$branch" + return 1 + } + + # Update submodules - handle force pushes by resetting each submodule + echo "Updating submodules..." + git submodule update --init --recursive --force || { + echo "Standard submodule update failed, cleaning and retrying..." + return 1 + } + + echo "Repository and submodules updated successfully" + + export GIT_DIR="$SAVED_GIT_DIR" + unset SAVED_GIT_DIR +} + +# Updated conservative deployment function using the unified update conservative_deploy_expressjs_blog() { local branch="$1" local oldrev="${2:-}" @@ -78,70 +141,35 @@ local envfile="${5:-}" echo "Using preserving deployment method for production environment..." - - # Define the bare repositories - local MAIN_APP_BARE_REPO="$GIT_DIR" - local CONTENT_BARE_REPO="/srv/jasonpoage.com/expressjs-blog-posts.git" # set -x - # Update the working tree in place - git --git-dir="$MAIN_APP_BARE_REPO" --work-tree="$deploy_path" checkout -f "$branch" + # Initialize the deployment directory if it doesn't exist + if [[ ! -d "$deploy_path" ]]; then + echo "Creating deployment directory..." + git clone --branch "$branch" "$GIT_DIR" "$deploy_path" || { + echo "Error: Failed to create deployment directory" + return 1 + } + fi + # Single unified update function handles everything + update_repo_and_submodules "$branch" "$deploy_path" "$GIT_DIR" || return 1 + cd "$deploy_path" || { echo "Error: Could not change directory to $deploy_path" return 1 } - ln -f "$envfile" "$deploy_path/.env" + ln -f "$envfile" "$deploy_path/.env" || return 1 - # Smart dependency installation (only if package files changed) - local install_required=true - if [[ -n "$oldrev" && "$oldrev" != "0000000000000000000000000000000000000000" ]]; then - if ! git --git-dir="$MAIN_APP_BARE_REPO" diff-tree --name-only -r "$oldrev..$newrev" | grep -qE "(package\.json|yarn\.lock)$"; then - echo "No changes detected in package.json or yarn.lock. Skipping yarn install." - install_required=false - else - echo "Changes detected in package.json or yarn.lock. Running yarn install." - fi - else - echo "Running yarn install (initial deployment)." - fi + get_dependencies "$oldrev" "$newrev" || return 1 - if [[ "$install_required" == "true" ]]; then - yarn - fi - - # Smart CSS bundling (only if CSS files changed) - if [[ -n "$oldrev" && -n "$newrev" ]]; then - yarn combine:css "$oldrev" "$newrev" "$MAIN_APP_BARE_REPO" - else - yarn combine:css - fi + yarn combine:css "$oldrev" "$newrev" "$GIT_DIR" || return 1 systemctl --user restart express-blog@"$branch".service - # Handle content repository updates - if [[ -d "$deploy_path/content" ]]; then - cd "$deploy_path/content" || { - echo "Error: Could not change directory to $deploy_path/content" - return 1 - } - current_commit=$(git rev-parse HEAD) - git fetch origin - latest_commit=$(git rev-parse origin/main) - - if [[ "$current_commit" != "$latest_commit" ]]; then - git reset --hard origin/main - echo "Content updated to latest commit" - else - echo "Content already up to date" - fi - else - git clone --branch main "$CONTENT_BARE_REPO" "$deploy_path/content" - fi - - # set +x + set +x } deploy_expressjs_blog() { @@ -155,18 +183,23 @@ deploy_path=$(get_deploy_path "$branch") envfile=$(get_deploy_env_file "$branch") - if [[ "$branch" == "staging" || "$branch" == "main" || "$branch" == "testing" ]]; then - - # For testing environments, use the efficient method (replace everything) - if [[ "$branch" == "testing" ]]; then - quick_deploy_expressjs_blog "$branch" "$test_dir" "$deploy_path" "$envfile" - return 0 - else - # For production/main, use the preserving method (keep logs, update in place) - conservative_deploy_expressjs_blog "$branch" "$oldrev" "$newrev" "$deploy_path" "$envfile" - return 0 - fi - fi + + case "$branch" in + "testing") + quick_deploy_expressjs_blog "$branch" "$test_dir" "$deploy_path" "$envfile" + return 0 + ;; + "staging") + # For production/main, use the preserving method (keep logs, update in place) + conservative_deploy_expressjs_blog "$branch" "$oldrev" "$newrev" "$deploy_path" "$envfile" + return 0 + ;; + "main") + conservative_deploy_expressjs_blog "$branch" "$oldrev" "$newrev" "$deploy_path" "$envfile" + # echo "Deployment available at: $deploy_path" + ;; + + esac } @@ -196,6 +229,9 @@ export TEST_SCHEMA=http export NODE_ENV=testing + # echo "Skipping tests" + # return 0 + echo "Running build scripts..." yarn combine_css || return 1 @@ -219,14 +255,21 @@ } initialize_submodules() { - local tmpdir="$1" + local worktree="$1" echo "Initializing and updating submodules for test environment..." - git --work-tree="$tmpdir" submodule update --init --recursive || { - ls "$tmpdir" -a + git --work-tree="$worktree" submodule update --init --recursive || { + ls "$worktree" -a echo "Error: Failed to initialize/update submodules for test environment." return 1 } } +update_submodules() { + local worktree="$1" + git --work-tree="$worktree" submodule update --init --recursive || { + echo "Error: Failed to initialize/update submodules in deployment" + return 1 + } +} wait_for_service() { local logfile="$1" # Wait for the application to become responsive @@ -258,7 +301,6 @@ } # set -x -SKIP_DEPLOYMENT=true # Main script execution loop while read -r oldrev newrev ref; do tmpdir=$(mktemp -d) @@ -266,12 +308,8 @@ echo "--- Processing push for branch: $branch (from $oldrev to $newrev) ---" if run_postreceive_tests "$branch" "$tmpdir"; then echo "Tests passed for $branch. Proceeding with deployment." - if [[ -z "$SKIP_DEPLOYMENT" ]]; then - deploy_expressjs_blog "$branch" "$tmpdir" - echo "Deployment of $branch complete." - else - echo "Deployed to: $tmpdir" - fi + deploy_expressjs_blog "$branch" "$tmpdir" + echo "Deployment of $branch complete." else echo "Post-receive tests failed for $branch. Deployment aborted." exit 1 diff --git a/.githooks/pre-push b/.githooks/pre-push index 4a7a65f..8d44aab 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -9,12 +9,24 @@ set -euo pipefail # set -x -export TEST_SCHEMA="http" -npm run test:prepush -if [ $? -ne 0 ]; then - echo "Tests failed. Push aborted." - exit 1 +export TEST_SCHEMA="http" + +# Path to store last tested commit hash +TEST_CACHE_FILE=".last_tested_commit" + +# Get current commit hash +CURRENT_COMMIT=$(git rev-parse HEAD) + +if [ -f "$TEST_CACHE_FILE" ] && grep -q "$CURRENT_COMMIT" "$TEST_CACHE_FILE"; then + echo "Tests already passed for commit $CURRENT_COMMIT. Skipping tests." +else + npm run test:prepush + + if [ $? -ne 0 ]; then + echo "Tests failed. Push aborted." + exit 1 + fi fi cd content diff --git a/scripts/runTests.js b/scripts/runTests.js index 2a5e643..80d2381 100644 --- a/scripts/runTests.js +++ b/scripts/runTests.js @@ -1,4 +1,6 @@ const Mocha = require("mocha"); +const { execSync } = require("child_process"); +const fs = require("fs"); async function runTestFile(filePath, description) { console.log(`Running ${description}...`); @@ -28,6 +30,9 @@ await runTestFile("./test/routes.test.js", "route tests"); console.log("✓ All tests passed!"); + + const commitHash = execSync("git rev-parse HEAD").toString().trim(); + fs.writeFileSync(".last_tested_commit", commitHash + "\n"); } catch (error) { console.error("Test execution failed:", error.message); process.exit(1); diff --git a/test/routes.test.js b/test/routes.test.js index ed1aabe..8fcb08e 100644 --- a/test/routes.test.js +++ b/test/routes.test.js @@ -38,7 +38,7 @@ method: "HEAD", redirect: "manual", }); - console.log("Healthcheck body: ", res.text()); + // console.log("Healthcheck body: ", res.text()); expect(res.ok).to.be.true; serverOnline = true; }); @@ -100,7 +100,7 @@ // "Extracted routes:", // routes.map((r) => r.loc || "NO_LOC") // ); - console.log("Total routes found:", routes.length); + // console.log("Total routes found:", routes.length); expect(routes).to.be.an("array").that.is.not.empty; } catch (error) { @@ -120,7 +120,7 @@ // Skip the root route and any routes without a proper loc if (route.loc && route.loc !== "/" && route.loc !== "#") { const url = baseUrl + route.loc; - console.log(`Testing route: ${route.loc}`); + // console.log(`Testing route: ${route.loc}`); try { const res = await fetch(url, {