diff --git a/.githooks/post-receive b/.githooks/post-receive index 49b24f2..b44e19a 100644 --- a/.githooks/post-receive +++ b/.githooks/post-receive @@ -1,10 +1,11 @@ #!/bin/bash + deploy_expressjs_blog() { - set -x local ref="$1" local branch="${ref#refs/heads/}" local path="/srv/jasonpoage.com/expressjs-blog-$branch" + set -x if [[ "$branch" == "production" || "$branch" == "main" || "$branch" == "testing" ]]; then GIT_WORK_TREE="$path" git checkout -f "$branch" @@ -12,16 +13,48 @@ yarn yarn combine:css systemctl --user restart express-blog@"$branch".service - cp /srv/jasonpoage.com/$branch.env "$path"/.env + ln -f /srv/jasonpoage.com/"$branch".env "$path"/.env # Blog content GIT_DIR="/srv/jasonpoage.com/expressjs-blog-posts.git" - # Always checkout the main branch of the blog posts GIT_WORK_TREE="$path/content" git checkout -f main fi set +x } -while read -r oldrev newrev ref; do - deploy_expressjs_blog "$ref" -done +run_postreceive_tests() { + local branch="$1" + local tmpdir pidfile logfile + tmpdir=$(mktemp -d) + pidfile="$tmpdir/test.pid" + logfile="$tmpdir/test.log" + trap 'kill $(cat "$pidfile" 2>/dev/null) 2>/dev/null; rm -rf "$tmpdir"' EXIT + + git clone . "$tmpdir" --quiet + cd "$tmpdir" || return 1 + cp /srv/jasonpoage.com/"${branch}".env .env + + yarn install --silent + export PORT=4123 + + nohup yarn start >>"$logfile" 2>&1 & + echo $! >"$pidfile" + + sleep 2 + if ! npm run test:postreceive; then + kill "$(cat "$pidfile")" 2>/dev/null + return 1 + fi + + kill "$(cat "$pidfile")" 2>/dev/null +} + +while read -r oldrev newrev ref; do + branch="${ref#refs/heads/}" + if run_postreceive_tests "$branch"; then + deploy_expressjs_blog "$ref" + else + echo "Post-receive tests failed. Deployment aborted." + exit 1 + fi +done diff --git a/.githooks/pre-push b/.githooks/pre-push index 6b2a73a..af335e1 100755 --- a/.githooks/pre-push +++ b/.githooks/pre-push @@ -1,14 +1,21 @@ #!/bin/sh # Push content subrepo before pushing main repo remote="$1" -export GIT_TRACE=1 -export GIT_TRACE_PACKET=1 -export GIT_TRACE_PERFORMANCE=1 -export GIT_SSH_COMMAND="ssh -vvv" +#export GIT_TRACE=1 +#export GIT_TRACE_PACKET=1 +#export GIT_TRACE_PERFORMANCE=1 +#export GIT_SSH_COMMAND="ssh -vvv" set -euo pipefail set -x +npm run test:prepush + +if [ $? -ne 0 ]; then + echo "Tests failed. Push aborted." + exit 1 +fi + cd content git push "$remote" main cd .. diff --git a/package.json b/package.json index e701c80..f582471 100644 --- a/package.json +++ b/package.json @@ -5,13 +5,14 @@ "main": "index.js", "scripts": { "combine:css": "node combine-css.js", - "test": "node ./test/runTests.js", "start": "nodemon ./src/app.js --trace-exit", "maildev": "maildev", "main": "pm2 start ecosystem.config.js --only expressjs-blog-main", "testing": "pm2 start ecosystem.config.js --only expressjs-blog-testing", "stop-main": "node_modules/pm2/bin/pm2 delete expressjs-blog-main", - "stop-testing": "node_modules/pm2/bin/pm2 delete expressjs-blog-testing" + "stop-testing": "node_modules/pm2/bin/pm2 delete expressjs-blog-testing", + "test:prepush": "node scripts/test-prepush.js", + "test:postreceive": "node scripts/test-postreceive.js" }, "keywords": [], "author": "", diff --git a/scripts/fetch_behavior.js b/scripts/fetch_behavior.js new file mode 100644 index 0000000..a66ff6a --- /dev/null +++ b/scripts/fetch_behavior.js @@ -0,0 +1,13 @@ +// test-sitemap.js +const fetch = require("node-fetch"); + +async function test() { + const res = await fetch("http://127.0.0.1:3400/sitemap.json"); + const data = await res.json(); + + console.log("Status:", res.status); + console.log("Data:", JSON.stringify(data, null, 2)); + console.log("Routes:", data); +} + +test().catch(console.error); diff --git a/scripts/fetch_routes.js b/scripts/fetch_routes.js new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/scripts/fetch_routes.js diff --git a/scripts/test-postreceive.js b/scripts/test-postreceive.js new file mode 100644 index 0000000..2a55761 --- /dev/null +++ b/scripts/test-postreceive.js @@ -0,0 +1 @@ +console.log("No post-receive tests yet"); diff --git a/scripts/test-prepush.js b/scripts/test-prepush.js new file mode 100644 index 0000000..2a5e643 --- /dev/null +++ b/scripts/test-prepush.js @@ -0,0 +1,37 @@ +const Mocha = require("mocha"); + +async function runTestFile(filePath, description) { + console.log(`Running ${description}...`); + + const mocha = new Mocha({ + reporter: "spec", + timeout: 5000, + }); + + mocha.addFile(filePath); + + return new Promise((resolve, reject) => { + mocha.run((failures) => { + if (failures) { + reject(new Error(`${description} failed with ${failures} failures`)); + } else { + resolve(); + } + }); + }); +} + +async function runTests() { + try { + await runTestFile("./test/env.test.js", "environment validation tests"); + console.log("✓ Environment validation passed. Running route tests..."); + + await runTestFile("./test/routes.test.js", "route tests"); + console.log("✓ All tests passed!"); + } catch (error) { + console.error("Test execution failed:", error.message); + process.exit(1); + } +} + +runTests(); diff --git a/test/fetch_behavior.js b/test/fetch_behavior.js deleted file mode 100644 index a66ff6a..0000000 --- a/test/fetch_behavior.js +++ /dev/null @@ -1,13 +0,0 @@ -// test-sitemap.js -const fetch = require("node-fetch"); - -async function test() { - const res = await fetch("http://127.0.0.1:3400/sitemap.json"); - const data = await res.json(); - - console.log("Status:", res.status); - console.log("Data:", JSON.stringify(data, null, 2)); - console.log("Routes:", data); -} - -test().catch(console.error); diff --git a/test/fetch_routes.js b/test/fetch_routes.js deleted file mode 100644 index e69de29..0000000 --- a/test/fetch_routes.js +++ /dev/null diff --git a/test/runTests.js b/test/runTests.js deleted file mode 100644 index 2a5e643..0000000 --- a/test/runTests.js +++ /dev/null @@ -1,37 +0,0 @@ -const Mocha = require("mocha"); - -async function runTestFile(filePath, description) { - console.log(`Running ${description}...`); - - const mocha = new Mocha({ - reporter: "spec", - timeout: 5000, - }); - - mocha.addFile(filePath); - - return new Promise((resolve, reject) => { - mocha.run((failures) => { - if (failures) { - reject(new Error(`${description} failed with ${failures} failures`)); - } else { - resolve(); - } - }); - }); -} - -async function runTests() { - try { - await runTestFile("./test/env.test.js", "environment validation tests"); - console.log("✓ Environment validation passed. Running route tests..."); - - await runTestFile("./test/routes.test.js", "route tests"); - console.log("✓ All tests passed!"); - } catch (error) { - console.error("Test execution failed:", error.message); - process.exit(1); - } -} - -runTests();