Skip to content

Instantly share code, notes, and snippets.

@mateiidavid
Created January 14, 2022 10:26
Show Gist options
  • Save mateiidavid/a7ded6282ee576359b1214688ade610a to your computer and use it in GitHub Desktop.
Save mateiidavid/a7ded6282ee576359b1214688ade610a to your computer and use it in GitHub Desktop.
Hacky Lua script to confirm any pushes to your main (or protected) git branch
#!/usr/bin/lua
--[[
+-------------------+
+ Lua pre-push hook +
+-------------------+
- Prompts user to confirm remote pushes when working on a
protected branch and pushing to a _protected_ branch.
- Can be installed locally or globally. I usually
keep my config files in a dedicated directory and
create symlinks.
- Locally: you can place the file in your .git/hooks/pre-push
- Globally: create a directory for your hooks, e.g
~/.git/hooks and add it to your global .gitconfig
under [core].
e.g vim ~/.gitconfig
+ [core]
+ hooksPath = /home/matei/.git/hooks
- chmod +x pre-push
- You can add your own protected branches (or repositories) to the
respective maps. If you want it enabled by default, delete the
repository logic.
- I left all my comments in, on the off chance that they're helpful.
NOTE: you need to have a lua interpreter installed to execute this!
https://www.lua.org/pil/1.4.html
Last but not least, I'm still learning Lua, this is just a hacky script! :)
--]]
-- I think technically this will only work if we're on that branch?
-- gotta RTFM.
local CMD_GIT_BRANCH = 'git rev-parse --abbrev-ref HEAD'
local CMD_GIT_REPO = 'git rev-parse --show-toplevel'
local PROTECTED_BRANCHES = {['main'] = true, ['master'] = true, ['add-git-hook'] = true}
local PROTECTED_REPOS = {['linkerd2'] = true, ['linkerd2-proxy'] = true, ['dotfiles'] = true}
local ANSI_RED = "\27[31m"
local ANSI_RESET = "\27[0m"
local ANSI_WHITE_BOLD = "\27[37;1;4m" -- 4 is for underline
local ANSI_BOLD = "\27[1m"
local ANSI_GREEN = "\27[32m"
local HOOK_NAME = "\27[96;4m[git-push-hook-check]\27[0m "
-- Execute takes in a command as a string and calls out into the shell to
-- execute it. We start a sub process using `io.popen` and then use the handle
-- to read the output from the command.
local function execute(command)
local handle = assert(io.popen(command))
-- `*a` reads it all
-- https://www.lua.org/manual/5.1/manual.html#pdf-file:read
local output = handle:read("*a")
handle:close()
return output
end
-- Try execute will execute a command via a protected call (pcall). Pcall
-- will return a success boolean and an error message if the inner call
-- fails. We use it to bubble up errors, e.g socket errors from subprocs.
-- If the call fails, we exit with an error, otherwise, we return the output
-- from 'execute'.
local function try_execute(command)
local success, data = pcall(execute, command)
if not success then
os.exit(2)
end
return data
end
local repo_path = try_execute(CMD_GIT_REPO)
-- Will capture string after last '/' to get the name of the repository.
local repo_name = string.match(repo_path, "/%a+/.+/(%a+)")
if not PROTECTED_REPOS[repo_name] then
os.exit()
end
local branch_name = try_execute(CMD_GIT_BRANCH)
branch_name = string.gsub(branch_name, '\n', '')
if PROTECTED_BRANCHES[branch_name] then
-- colors!
local push_msg = HOOK_NAME..ANSI_GREEN.."\27[4;1mSure\27[0;32m you want to push to ["..ANSI_WHITE_BOLD..branch_name..ANSI_RESET..ANSI_GREEN.."]?"..ANSI_RESET..ANSI_BOLD.." (Y/n)"..ANSI_RESET
local confirm
repeat
print(push_msg)
-- Take input from controlling terminal
local tty_handle = io.open("/dev/tty")
confirm = tty_handle:read(1)
if not confirm then return end -- no input
confirm = confirm:lower()
until confirm == "y" or confirm == "n"
if confirm ~= "y" then
print(HOOK_NAME..ANSI_RED.."Push to ["..ANSI_WHITE_BOLD..branch_name..ANSI_RESET..ANSI_RED.."] aborted"..ANSI_RESET)
os.exit(1)
end
return
end
os.exit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment