Forked from maxmarkus/pre-commit-hook-merge-conflicts.sh
Last active
November 16, 2023 05:24
-
-
Save thattomperson/7a8127ac306bb2e58c24ba16a521b621 to your computer and use it in GitHub Desktop.
My Everyday Git hooks `nix-shell -p nodejs_18 --run "curl -L gist.githubusercontent.com/thattomperson/7a8127ac306bb2e58c24ba16a521b621/raw/%255Bpost-commit%255D-update-hooks.js | node"`
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
| #! /usr/bin/env nix-shell | |
| ` | |
| #! nix-shell --packages nodejs_18 -i node | |
| ` | |
| const https = require('https'); | |
| const path = require('path'); | |
| const fs = require('fs'); | |
| const util = require('util'); | |
| const readline = require('readline') | |
| const spawn = require('child_process').spawnSync; | |
| const mkdir = util.promisify(fs.mkdir); | |
| const writeFile = util.promisify(fs.writeFile); | |
| const chmod = util.promisify(fs.chmod); | |
| const readFile = util.promisify(fs.readFile); | |
| const gistId = '7a8127ac306bb2e58c24ba16a521b621'; | |
| const updateFile = path.join('.git', 'ttp-hooks-last-update'); | |
| const yes = process.argv.includes('-y') | |
| function get(url) { | |
| let content = ''; | |
| return new Promise((resolve, reject) => { | |
| https.get( | |
| url, | |
| { | |
| headers: { | |
| 'User-Agent': 'node-git-hooks-downloader', | |
| }, | |
| }, | |
| (res) => { | |
| res.on('data', (data) => { | |
| content += data; | |
| }); | |
| res.on('close', () => { | |
| resolve(content); | |
| }); | |
| res.on('error', reject); | |
| } | |
| ); | |
| }); | |
| } | |
| async function getContent({ truncated, content, raw_url }) { | |
| return truncated ? await get(raw_url) : content; | |
| } | |
| async function write(filepath, file) { | |
| const content = await getContent(file); | |
| return writeFile(filepath, content); | |
| } | |
| async function writeAliases(aliases) { | |
| const content = await getContent(aliases); | |
| const lines = content.split('\n'); | |
| lines.map(line => { | |
| const [name, body] = line.split(/=(.*)/s).map(p => p.trim()); | |
| console.log(`\tAdding ${name} alias`); | |
| return exec('git', 'config', '--replace-all', `alias.${name}`, body); | |
| }) | |
| } | |
| function exec(command, ...args) { | |
| spawn(command, args) | |
| } | |
| function groupHooks(files) { | |
| const groups = { | |
| hooks: {}, | |
| ungrouped: {}, | |
| }; | |
| Object.values(files).forEach((file) => { | |
| let matches = /\[(.+?)\]-(.*)/.exec(file.filename); | |
| if (matches) { | |
| groups.hooks[matches[1]] = groups.hooks[matches[1]] || {}; | |
| groups.hooks[matches[1]][matches[2]] = file; | |
| } else if (file.filename === 'aliases') { | |
| groups.aliases = file | |
| } else { | |
| groups.ungrouped[file.filename] = file; | |
| } | |
| }); | |
| return groups; | |
| } | |
| async function writeAll(groups) { | |
| console.log("Writing hooks") | |
| await Promise.all( | |
| Object.keys(groups.hooks).map(async (hook) => { | |
| await Promise.all( | |
| Object.keys(groups.hooks[hook]).map(async (filename) => { | |
| console.log(`\tWriting ${hook} ${filename}`) | |
| const folder = path.join('.git', 'hooks', 'hooks.d', hook); | |
| const filepath = path.join(folder, filename); | |
| await mkdir(folder, { recursive: true }); | |
| await write(filepath, groups.hooks[hook][filename]); | |
| await chmod(filepath, '775'); | |
| }) | |
| ); | |
| const filepath = path.join('.git', 'hooks', hook); | |
| const content = Object.keys(groups.hooks[hook]).reduce( | |
| (contents, filename) => { | |
| const folder = path.join('hooks', 'hooks.d', hook); | |
| const filepath = path.join(folder, filename); | |
| return `${contents}\n $GIT_COMMON_DIR/${filepath}\n`; | |
| }, | |
| '#!/usr/bin/env sh\nset -e\n\n GIT_COMMON_DIR=$(git rev-parse --git-common-dir);\n\n' | |
| ); | |
| await writeFile(filepath, content); | |
| await chmod(filepath, '775'); | |
| }) | |
| ); | |
| console.log('Writing aliases'); | |
| await writeAliases(groups.aliases) | |
| console.log('Writing additional files'); | |
| await Promise.all( | |
| Object.keys(groups.ungrouped).map(async (filename) => { | |
| console.log(`\tWriting ${filename}`) | |
| const folder = path.join('.git'); | |
| const filepath = path.join(folder, filename); | |
| await mkdir(folder, { recursive: true }); | |
| await write(filepath, groups.ungrouped[filename]); | |
| }) | |
| ); | |
| } | |
| async function checkUpdatedTime(response) { | |
| try { | |
| const lastUpdatedAt = (await readFile(updateFile)).toString().trim(); | |
| if (response.updated_at !== lastUpdatedAt) { | |
| response.local_updated_at = lastUpdatedAt; | |
| return response | |
| } | |
| } catch { | |
| response.local_updated_at = '1970-01-01T00:00:00Z'; | |
| return response | |
| } | |
| throw 'no-updates'; | |
| } | |
| function askForUpdate(response) { | |
| if (yes) { | |
| return Promise.resolve(response) | |
| } | |
| return new Promise((resolve, reject) => { | |
| const rl = readline.createInterface({ | |
| input: process.stdin, | |
| output: process.stdout | |
| }); | |
| const ac = new AbortController(); | |
| const signal = ac.signal; | |
| const timeout = setTimeout(() => { | |
| ac.abort() | |
| rl.close() | |
| console.log('Took too long to answer, aborting update') | |
| reject(); | |
| }, 10e3) | |
| console.log('There is an update to your githooks available') | |
| rl.question('Would you like to update [Y/n]', { signal }, function (answer) { | |
| console.log({ answer }) | |
| clearTimeout(timeout); | |
| if (answer === '' || answer.charAt(0).toLowerCase() === 'y') { | |
| resolve(response) | |
| } | |
| rl.close(); | |
| }) | |
| }); | |
| } | |
| async function updateUpdatedAt(response) { | |
| await writeFile(updateFile, response.updated_at); | |
| return response; | |
| } | |
| // 1 in 100 chance to check for updates | |
| const num = Math.round(Math.random() * 100); | |
| if (num === 1 || yes) { | |
| get(`https://api.github.com/gists/${gistId}`) | |
| .then((content) => JSON.parse(content)) | |
| .then(checkUpdatedTime) | |
| .then(askForUpdate) | |
| .then(updateUpdatedAt) | |
| .then((response) => response.files) | |
| .then(groupHooks) | |
| .then(writeAll) | |
| .catch((error) => { | |
| // If we have forced updates and there is nothing to do tell the user | |
| if (yes && error === 'no-updates') { | |
| console.log('No updates required') | |
| } | |
| }) | |
| } |
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
| #! /usr/bin/env bash | |
| # Check for merge conflicts | |
| # Tested on Linux and Mac | |
| # Simple check for merge conflics | |
| conflicts=`git diff --cached --name-only -G"<<<<<|=====|>>>>>"` | |
| # Something went wrong | |
| if [[ -n "$conflicts" ]]; then | |
| echo | |
| echo "Unresolved merge conflicts in these files:" | |
| for conflict in $conflicts; do | |
| echo $conflict | |
| done; | |
| exit 1; | |
| fi | |
| exit 0 |
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
| #! /usr/bin/env bash | |
| nix run nixpkgs#php82Packages.phpcs -- --filter=GitStaged --standard=$(git rev-parse --git-common-dir)/phpcs.xml --runtime-set ignore_warnings_on_exit 1 --colors . |
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
| php-lint = !f() { nix run nixpkgs#php82Packages.phpcs -- --filter=GitStaged --standard=$(git rev-parse --git-common-dir)/phpcs.xml --runtime-set ignore_warnings_on_exit 1 --colors ${GIT_PREFIX:-./}; }; f | |
| php-lint-fix = !f() { nix run nixpkgs#php82Packages.phpcbf -- --filter=GitStaged --standard=$(git rev-parse --git-common-dir)/phpcs.xml --runtime-set ignore_warnings_on_exit 1 --colors ${GIT_PREFIX:-./}; }; f | |
| update-hooks = !f() { $(git rev-parse --git-common-dir)/hooks/hooks.d/post-commit/update-hooks.js -y; }; f |
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
| <?xml version="1.0"?> | |
| <ruleset name="Thirty4"> | |
| <exclude-pattern type="relative">^lib/model/migration/*</exclude-pattern> | |
| <exclude-pattern type="relative">^lib/model/om/*</exclude-pattern> | |
| <exclude-pattern type="relative">^lib/model/map/*</exclude-pattern> | |
| <exclude-pattern type="relative">^lib/*/base</exclude-pattern> | |
| <exclude-pattern type="relative">^cache/*</exclude-pattern> | |
| <exclude-pattern type="relative">*.css</exclude-pattern> | |
| <exclude-pattern type="relative">*.js</exclude-pattern> | |
| <rule ref="Generic.Arrays.DisallowLongArraySyntax" /> | |
| <rule ref="Generic.CodeAnalysis" /> | |
| <rule ref="Squiz.Arrays.ArrayDeclaration.NoComma" /> | |
| <rule ref="Squiz.Functions.MultiLineFunctionDeclaration"> | |
| <properties> | |
| <property name="indent" value="2" /> | |
| </properties> | |
| </rule> | |
| <rule ref="PSR12"/> | |
| <rule ref="Generic.WhiteSpace.ScopeIndent"> | |
| <properties> | |
| <property name="indent" value="2" /> | |
| </properties> | |
| </rule> | |
| <rule ref="PSR2.Methods.FunctionCallSignature"> | |
| <properties> | |
| <property name="indent" value="2" /> | |
| </properties> | |
| </rule> | |
| <rule ref="PSR12.ControlStructures.ControlStructureSpacing"> | |
| <properties> | |
| <property name="indent" value="2" /> | |
| </properties> | |
| </rule> | |
| <rule ref="PSR2.ControlStructures.SwitchDeclaration"> | |
| <properties> | |
| <property name="indent" value="2" /> | |
| </properties> | |
| </rule> | |
| <rule ref="PSR1.Classes.ClassDeclaration.MissingNamespace"> | |
| <severity>0</severity> | |
| </rule> | |
| <rule ref="Squiz.Classes.ValidClassName.NotCamelCaps"> | |
| <type>warning</type> | |
| </rule> | |
| <rule ref="PSR1.Methods.CamelCapsMethodName.NotCamelCaps"> | |
| <type>warning</type> | |
| </rule> | |
| <rule ref="Squiz.WhiteSpace.ControlStructureSpacing.SpacingBeforeClose"> | |
| <type>warning</type> | |
| </rule> | |
| <rule ref="Generic.CodeAnalysis.EmptyStatement.DetectedCatch"> | |
| <type>warning</type> | |
| </rule> | |
| <rule ref="Squiz.Commenting.EmptyCatchComment"> | |
| <type>error</type> | |
| </rule> | |
| </ruleset> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment