mirror of
https://github.com/Haskell-Things/ImplicitCAD.git
synced 2024-09-11 04:55:41 +03:00
Introduce ormolu CI.
This commit is contained in:
parent
644a63d9f9
commit
ca413cb6dd
51
.github/workflows/ormolu.yaml
vendored
Normal file
51
.github/workflows/ormolu.yaml
vendored
Normal file
@ -0,0 +1,51 @@
|
||||
# FUTUREWORK: add this to `ci.dhall`?
|
||||
|
||||
name: Ormolu
|
||||
on:
|
||||
- pull_request
|
||||
|
||||
jobs:
|
||||
ormolu:
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- uses: "actions/checkout@v1"
|
||||
|
||||
- uses: "actions/setup-haskell@v1.1.4"
|
||||
id: setup-haskell-cabal
|
||||
with:
|
||||
cabal-version: "${{ matrix.cabal }}"
|
||||
enable-stack: false
|
||||
ghc-version: "${{ matrix.ghc }}"
|
||||
|
||||
- uses: "actions/cache@v2"
|
||||
name: Cache
|
||||
with:
|
||||
key: "${{ runner.os }}"
|
||||
path: |
|
||||
"${{ steps.setup-haskell-cabal.outputs.cabal-store }}"
|
||||
~/.cabal/packages
|
||||
~/.cabal/store
|
||||
~/.cabal/bin
|
||||
dist-newstyle
|
||||
~/.local/bin
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
export PATH=$PATH:$HOME/.cabal/bin:$HOME/.local/bin
|
||||
export ORMOLU_VERSION=$(cat ./layout/ormolu.version)
|
||||
(ormolu -v 2>/dev/null | grep -q $ORMOLU_VERSION) || (cabal update && cabal install ormolu --constraint="ormolu ==$ORMOLU_VERSION")
|
||||
test -e $HOME/.local/bin/yq || pip3 install yq
|
||||
shell: bash
|
||||
|
||||
- name: Ormolu
|
||||
run: |
|
||||
export PATH=$PATH:$HOME/.cabal/bin:$HOME/.local/bin
|
||||
./layout/ormolu.sh -c
|
||||
shell: bash
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
cabal:
|
||||
- '3.2'
|
||||
ghc:
|
||||
- '8.10.1'
|
92
layout/ormolu.sh
Executable file
92
layout/ormolu.sh
Executable file
@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd "$( dirname "${BASH_SOURCE[0]}" )"
|
||||
|
||||
command -v grep >/dev/null 2>&1 || { echo >&2 "grep is not installed, aborting."; exit 1; }
|
||||
command -v awk >/dev/null 2>&1 || { echo >&2 "awk is not installed, aborting."; exit 1; }
|
||||
command -v sed >/dev/null 2>&1 || { echo >&2 "sed is not installed, aborting."; exit 1; }
|
||||
command -v yq >/dev/null 2>&1 || { echo >&2 "yq is not installed, aborting. See https://github.com/mikefarah/yq"; exit 1; }
|
||||
|
||||
ORMOLU_VERSION=$(cat ormolu.version)
|
||||
( ormolu -v 2>/dev/null | grep -q $ORMOLU_VERSION ) || ( echo "please install ormolu $ORMOLU_VERSION (eg., run 'cabal install ormolu' and ensure ormolu is on your PATH.)"; exit 1 )
|
||||
echo "ormolu version: $ORMOLU_VERSION"
|
||||
|
||||
ARG_ALLOW_DIRTY_WC="0"
|
||||
ARG_ORMOLU_MODE="inplace"
|
||||
|
||||
USAGE="
|
||||
This bash script can either (a) apply ormolu formatting in-place to
|
||||
all haskell modules in your working copy, or (b) check all modules for
|
||||
formatting and fail if ormolu needs to be applied.
|
||||
|
||||
(a) is mostly for migrating from manually-formatted projects to
|
||||
ormolu-formatted ones; (b) can be run in by a continuous integration
|
||||
service to make sure no branches with non-ormolu formatting make get
|
||||
merged.
|
||||
|
||||
For every-day dev work, consider using one of the ormolu editor
|
||||
integrations (see https://github.com/tweag/ormolu#editor-integration).
|
||||
|
||||
USAGE: $0
|
||||
-h: show this help.
|
||||
-f: run even if working copy is dirty. default: ${ARG_ALLOW_DIRTY_WC}
|
||||
-c: set ormolu mode to 'check'. default: 'inplace'
|
||||
|
||||
"
|
||||
|
||||
# Option parsing:
|
||||
# https://sookocheff.com/post/bash/parsing-bash-script-arguments-with-shopts/
|
||||
while getopts ":fch" opt; do
|
||||
case ${opt} in
|
||||
f ) ARG_ALLOW_DIRTY_WC="1"
|
||||
;;
|
||||
c ) ARG_ORMOLU_MODE="check"
|
||||
;;
|
||||
h ) echo "$USAGE" 1>&2
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
done
|
||||
shift $((OPTIND -1))
|
||||
|
||||
if [ "$#" -ne 0 ]; then
|
||||
echo "$USAGE" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd ".."
|
||||
|
||||
if [ "$(git status -s | grep -v \?\?)" != "" ]; then
|
||||
echo "working copy not clean."
|
||||
if [ "$ARG_ALLOW_DIRTY_WC" == "1" ]; then
|
||||
echo "running with -f. this will mix ormolu and other changes."
|
||||
else
|
||||
echo "run with -f if you want to force mixing ormolu and other changes."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "ormolu mode: $ARG_ORMOLU_MODE"
|
||||
|
||||
FAILURES=0
|
||||
|
||||
for hsfile in $(git ls-files | grep '\.hsc\?$'); do
|
||||
FAILED=0
|
||||
ormolu --mode $ARG_ORMOLU_MODE --check-idempotence $LANGUAGE_EXTS "$hsfile" || FAILED=1
|
||||
if [ "$FAILED" == "1" ]; then
|
||||
((++FAILURES))
|
||||
echo "$hsfile... *** FAILED"
|
||||
else
|
||||
echo "$hsfile... ok"
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$FAILURES" != 0 ]; then
|
||||
echo "ormolu failed on $FAILURES files."
|
||||
if [ "$ARG_ORMOLU_MODE" == "check" ]; then
|
||||
echo -en "\n\nyou can fix this by running 'make format' from the git repo root.\n\n"
|
||||
fi
|
||||
exit 1
|
||||
fi
|
1
layout/ormolu.version
Normal file
1
layout/ormolu.version
Normal file
@ -0,0 +1 @@
|
||||
0.1.4.1
|
125
layout/rebase-onto-formatter.sh
Normal file
125
layout/rebase-onto-formatter.sh
Normal file
@ -0,0 +1,125 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# written by mheinzel
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
command -v sed >/dev/null 2>&1 || { echo >&2 "sed is not installed, aborting."; exit 1; }
|
||||
|
||||
BASE_COMMIT=${1:-}
|
||||
TARGET_COMMIT=${2:-}
|
||||
FORMATTING_COMMAND='make formatf'
|
||||
USAGE="
|
||||
USAGE: $0 BASE_COMMIT TARGET_COMMIT
|
||||
|
||||
BASE_COMMIT:
|
||||
A commit that contains the changes to formatting version and
|
||||
config already from TARGET_COMMIT, but not the automatically
|
||||
applied formatting changes. Must be the first commit on the
|
||||
branch you are about to rebase (not the one returned by
|
||||
git-merge-base). It will be removed from the resulting branch.
|
||||
TARGET_COMMIT:
|
||||
The commit introducing the formatting that you want to rebase onto.
|
||||
|
||||
Rebase a branch onto changes created by an automated formatter. The script
|
||||
will keep the (linear) history of the branch intact and make the commits appear
|
||||
as if the changes had been applied onto the newly-formatted version all along.
|
||||
|
||||
INSTRUCTIONS:
|
||||
1. Make a copy of your branch (or be prepared to salvage it from reflog).
|
||||
$ git branch mybranch-backup
|
||||
2. Find out what the base commit is.
|
||||
3. Rebase onto the base commit yourself.
|
||||
$ git rebase \$BASE_COMMIT
|
||||
4. Make sure the formatting tool is installed with the correct version and settings.
|
||||
$ stack install ormolu
|
||||
5. Run this script.
|
||||
$ $0 \$BASE_COMMIT \$TARGET_COMMIT
|
||||
|
||||
"
|
||||
|
||||
if [ -z "$BASE_COMMIT" ] || [ -z "$TARGET_COMMIT" ] || [ -z "$FORMATTING_COMMAND" ]
|
||||
then
|
||||
echo "$USAGE" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Running the script now. This might take a while..."
|
||||
|
||||
# The general idea is the following:
|
||||
#
|
||||
# We have a branch consisting of commits C1, C2, ... on top of our BASE_COMMIT C0.
|
||||
# Also, from C0 an automated formatting change f was made on some branch (e.g. develop).
|
||||
#
|
||||
# C0 ----> C1 ----> C2 ----> ... ----> Cn
|
||||
# |
|
||||
# f
|
||||
# |
|
||||
# v
|
||||
# C0'
|
||||
#
|
||||
# Now, how do we obtain versions of our commits operating on the formatted code (let's call them Ci')?
|
||||
#
|
||||
# C0 ----> C1 ----> C2 ----> ... ----> Cn
|
||||
# |
|
||||
# f
|
||||
# |
|
||||
# v
|
||||
# C0' ---> C1' ---> C2' ---> ... ----> Cn'
|
||||
#
|
||||
# One useful thing is that since f is defined by an automated tool,
|
||||
# we know f applied at every commit Ci, resulting in a hypothetical Ci'.
|
||||
#
|
||||
# C0 ----> C1 ----> C2 ----> ... ----> Cn
|
||||
# | | | |
|
||||
# f f f f
|
||||
# | | | |
|
||||
# v v v v
|
||||
# C0' C1' C2' Cn'
|
||||
#
|
||||
# And we can also get its inverse g (applied at Ci') by reverting the commit.
|
||||
#
|
||||
# C0 ----> C1 ----> C2 ----> ... ----> Cn
|
||||
# |^ |^ |^ |^
|
||||
# f| f| f| f|
|
||||
# |g |g |g |g
|
||||
# v| v| v| v|
|
||||
# C0' C1' C2' Cn'
|
||||
#
|
||||
# Finally, we can get from C(i-1)' to Ci' by composing three arrows:
|
||||
# - g at C(i-1)
|
||||
# - Ci
|
||||
# - f at C1
|
||||
#
|
||||
# C0 ----> C1 ----> C2 ----> ... ----> Cn
|
||||
# |^ |^ |^ |^
|
||||
# f| f| f| f|
|
||||
# |g |g |g |g
|
||||
# v| v| v| v|
|
||||
# C0' ---> C1' ---> C2' ---> ... ----> Cn'
|
||||
|
||||
set -x
|
||||
|
||||
# edit every commit Ci, adding new commits representing f at Ci and it's inverse g
|
||||
git rebase $BASE_COMMIT~1 --exec "$FORMATTING_COMMAND && git commit -am format && git revert HEAD --no-edit"
|
||||
|
||||
# drop last commit (do not revert formatting at the end of the branch)
|
||||
git reset HEAD~1 --hard
|
||||
|
||||
# now for every Ci, squash with the previous and next commit (i.e. g at C(i-1) and f at Ci).
|
||||
# However, we want to use Ci's commit message and author.
|
||||
# To do this, we run the following command after each group of these 3 commits:
|
||||
# Ci=$(git rev-parse HEAD~1); git reset --soft HEAD~3; git commit --reuse-message $Ci
|
||||
# We do an interactive rebase, but instead of editing the commit sequence manually,
|
||||
# we use sed for that, inserting an `exec` command after every 3 commits.
|
||||
GIT_SEQUENCE_EDITOR='sed -i -e "4~3s/^\(pick \S* format\)$/\1\nexec Ci=\$(git rev-parse HEAD~1); git reset --soft HEAD~3; git commit --reuse-message \$Ci/"' \
|
||||
git rebase --interactive $BASE_COMMIT
|
||||
|
||||
# rebase onto TARGET_COMMIT.
|
||||
# Annoyingly, we still have this first "format" commit that should already be
|
||||
# part of the TARGET_COMMIT. So we drop it.
|
||||
GIT_SEQUENCE_EDITOR='sed -i "1s/pick/drop/"' \
|
||||
git rebase --interactive $BASE_COMMIT --onto $TARGET_COMMIT
|
||||
|
||||
echo "Done."
|
||||
echo "Please check that the history looks as it should and all expected commits are there."
|
Loading…
Reference in New Issue
Block a user