Last active
August 27, 2025 21:49
-
-
Save absynce/7bfcac7da4eb96fae6329cd4896a1ca4 to your computer and use it in GitHub Desktop.
Git pre-push hook elm-pages script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "type": "application", | |
| "source-directories": [ | |
| "." | |
| ], | |
| "elm-version": "0.19.1", | |
| "dependencies": { | |
| "direct": { | |
| "dillonkearns/elm-pages": "10.2.2", | |
| "elm/browser": "1.0.2", | |
| "elm/core": "1.0.5", | |
| "elm/html": "1.0.0" | |
| }, | |
| "indirect": { | |
| "Chadtech/elm-bool-extra": "2.4.2", | |
| "avh4/elm-color": "1.0.0", | |
| "danfishgold/base64-bytes": "1.1.0", | |
| "danyx23/elm-mimetype": "4.0.1", | |
| "dillonkearns/elm-bcp47-language-tag": "2.0.0", | |
| "dillonkearns/elm-cli-options-parser": "3.2.0", | |
| "dillonkearns/elm-date-or-date-time": "2.0.0", | |
| "dillonkearns/elm-form": "3.0.1", | |
| "elm/bytes": "1.0.8", | |
| "elm/file": "1.0.5", | |
| "elm/http": "2.0.0", | |
| "elm/json": "1.1.3", | |
| "elm/parser": "1.1.0", | |
| "elm/random": "1.0.0", | |
| "elm/regex": "1.0.0", | |
| "elm/time": "1.0.0", | |
| "elm/url": "1.0.0", | |
| "elm/virtual-dom": "1.0.4", | |
| "elm-community/basics-extra": "4.1.0", | |
| "elm-community/list-extra": "8.7.0", | |
| "elm-community/maybe-extra": "5.3.0", | |
| "fredcy/elm-parseint": "2.0.1", | |
| "jluckyiv/elm-utc-date-strings": "1.0.0", | |
| "justinmimbs/date": "4.1.0", | |
| "mdgriffith/elm-codegen": "5.2.0", | |
| "miniBill/elm-codec": "2.3.0", | |
| "miniBill/elm-unicode": "1.1.1", | |
| "noahzgordon/elm-color-extra": "1.0.2", | |
| "robinheghan/fnv1a": "1.0.0", | |
| "robinheghan/murmur3": "1.0.0", | |
| "rtfeldman/elm-css": "18.0.0", | |
| "rtfeldman/elm-hex": "1.0.0", | |
| "rtfeldman/elm-iso8601-date-strings": "1.1.4", | |
| "stil4m/elm-syntax": "7.3.9", | |
| "stil4m/structured-writer": "1.0.3", | |
| "the-sett/elm-pretty-printer": "3.1.1", | |
| "the-sett/elm-syntax-dsl": "6.0.3", | |
| "wolfadex/elm-ansi": "3.0.0" | |
| } | |
| }, | |
| "test-dependencies": { | |
| "direct": {}, | |
| "indirect": {} | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module Main exposing (run) | |
| import BackendTask exposing (BackendTask) | |
| import BackendTask.File as File | |
| import BackendTask.Stream as Stream | |
| import FatalError | |
| import Pages.Script as Script exposing (Script) | |
| import Pages.Script.Spinner as Spinner | |
| {-| Path to the Git pre-push hook file | |
| -} | |
| hookPath : String | |
| hookPath = | |
| ".git/hooks/pre-push" | |
| {-| The content for our Git pre-push hook | |
| -} | |
| hookBranchCheck : String | |
| hookBranchCheck = | |
| """ | |
| # Warn before pushing to protected branches | |
| # Bypass with git push --no-verify | |
| BRANCH=`git rev-parse --abbrev-ref HEAD` | |
| PROTECTED_BRANCHES="^(main|master|envs/*)" | |
| if [[ "$BRANCH" =~ $PROTECTED_BRANCHES ]]; then | |
| read -p "Are you sure you want to push to \\"$BRANCH\\" ? (y/n): " -n 1 -r < /dev/tty | |
| echo | |
| if [[ $REPLY =~ ^[Yy]$ ]]; then | |
| exit 0 | |
| fi | |
| echo "Push aborted." | |
| exit 1 | |
| fi | |
| exit 0 | |
| """ | |
| run : Script | |
| run = | |
| Script.withoutCliOptions | |
| (Spinner.steps | |
| |> Spinner.withStep "Read existing hook file" (\_ -> readFile hookPath) | |
| |> Spinner.withStep "Write pre-push hook" writeHookFile | |
| |> Spinner.withStep "Make hook executable" (\_ -> makeExecutable hookPath) | |
| |> Spinner.runSteps | |
| ) | |
| {-| Write the Git pre-push hook file | |
| -} | |
| writeHookFile : Maybe String -> BackendTask FatalError.FatalError () | |
| writeHookFile maybeExistingHook = | |
| case hookStatus maybeExistingHook of | |
| HookAlreadyHasCheck -> | |
| Script.log "Hook already has check" | |
| HookExistsButNeedsCheck hookBody -> | |
| writeFileContent (hookBody ++ "\n" ++ hookBranchCheck) | |
| |> BackendTask.andThen | |
| (\_ -> | |
| Script.log "Updated existing pre-push hook" | |
| ) | |
| HookDoesntExist -> | |
| writeFileContent ("#!/bin/bash\n" ++ hookBranchCheck) | |
| |> BackendTask.andThen | |
| (\_ -> | |
| Script.log "Created new pre-push hook" | |
| ) | |
| writeFileContent : String -> BackendTask FatalError.FatalError () | |
| writeFileContent hookContent = | |
| Script.writeFile | |
| { path = hookPath | |
| , body = hookContent | |
| } | |
| |> BackendTask.mapError | |
| (\error -> | |
| FatalError.build | |
| { title = "Error writing hook file" | |
| , body = "Failed to write pre-push hook" | |
| } | |
| ) | |
| type HookStatus | |
| = HookAlreadyHasCheck | |
| | HookExistsButNeedsCheck String | |
| | HookDoesntExist | |
| hookStatus : Maybe String -> HookStatus | |
| hookStatus maybeExistingHook = | |
| case maybeExistingHook of | |
| Just hookBody -> | |
| if String.contains "Are you sure you want to push" hookBody then | |
| HookAlreadyHasCheck | |
| else | |
| HookExistsButNeedsCheck hookBody | |
| Nothing -> | |
| HookDoesntExist | |
| {-| Read a file and handle errors gracefully. | |
| Returns Nothing if the file doesn't exist. | |
| -} | |
| readFile : String -> BackendTask FatalError.FatalError (Maybe String) | |
| readFile filePath = | |
| File.rawFile filePath | |
| -- |> Stream.read | |
| |> BackendTask.map (\fileBody -> Just fileBody) | |
| |> BackendTask.onError | |
| (\error -> | |
| case error.recoverable of | |
| File.FileDoesntExist -> | |
| Script.log ("Could not find " ++ filePath ++ "...creating...") | |
| |> BackendTask.map (\_ -> Nothing) | |
| File.FileReadError fileReadError -> | |
| FatalError.build | |
| { title = "File read error" | |
| , body = fileReadError | |
| } | |
| |> BackendTask.fail | |
| File.DecodingError _ -> | |
| FatalError.build | |
| { title = "Decoding error" | |
| , body = "Failed to decode " ++ filePath | |
| } | |
| |> BackendTask.fail | |
| ) | |
| makeExecutable : String -> BackendTask FatalError.FatalError () | |
| makeExecutable hookPath_ = | |
| -- Make the hook file executable | |
| Script.command "chmod" | |
| [ "+x", hookPath_ ] | |
| |> BackendTask.mapError | |
| (\_ -> | |
| FatalError.build | |
| { title = "Chmod error" | |
| , body = "Failed to make pre-push hook executable" | |
| } | |
| ) | |
| |> BackendTask.map (\_ -> ()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment