better README, hooks ...
This commit is contained in:
parent
1e8bbcb006
commit
cb940dc6e1
4 changed files with 292 additions and 51 deletions
186
README.org
186
README.org
|
@ -8,7 +8,7 @@ everything...
|
||||||
|
|
||||||
* Git Project Manager
|
* Git Project Manager
|
||||||
|
|
||||||
Put a project management tool in git.
|
Put a project management tool in your git repository.
|
||||||
|
|
||||||
In general each project in git also need a lot of meta data informations.
|
In general each project in git also need a lot of meta data informations.
|
||||||
Most of them related to project management:
|
Most of them related to project management:
|
||||||
|
@ -28,6 +28,180 @@ thousands of small commit related to project management.
|
||||||
An easy way to have best of both world is simply to create a branch
|
An easy way to have best of both world is simply to create a branch
|
||||||
dedicated to project management only.
|
dedicated to project management only.
|
||||||
|
|
||||||
|
** Installation
|
||||||
|
|
||||||
|
For now you should simply clone it, install stack and build it.
|
||||||
|
|
||||||
|
** Usage
|
||||||
|
|
||||||
|
*** Quick
|
||||||
|
|
||||||
|
#+BEGIN_SRC
|
||||||
|
> cd $HOME/my-git-repo
|
||||||
|
> gpm init
|
||||||
|
...
|
||||||
|
> gpm new-issue -i
|
||||||
|
...
|
||||||
|
> gpm serve start
|
||||||
|
...
|
||||||
|
> open http://localhost:1234
|
||||||
|
...
|
||||||
|
> cd /tmp; git clone git://localhost:9418/my-git-repo.git my-git-repo
|
||||||
|
...
|
||||||
|
> cd my-git-repo
|
||||||
|
> git checkout -b new-feature
|
||||||
|
> ... /hack/ ...
|
||||||
|
> git commit
|
||||||
|
> ...
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
*** Detailled
|
||||||
|
|
||||||
|
The easiest way would be to launch =gpm= or =gpm --help= to have the list of
|
||||||
|
commands.
|
||||||
|
|
||||||
|
#+BEGIN_SRC
|
||||||
|
Git Project Manager
|
||||||
|
|
||||||
|
Usage: gpm (init | new-issue | review | serve | hooks)
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
-h,--help Show this help text
|
||||||
|
|
||||||
|
Available commands:
|
||||||
|
init Initialize gpm
|
||||||
|
new-issue Create a new Issue
|
||||||
|
review Review (use current branch by default)
|
||||||
|
serve Serve the git to the web
|
||||||
|
hooks Handle hooks for this git repository
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
*** Init
|
||||||
|
|
||||||
|
#+BEGIN_SRC
|
||||||
|
> gpm init --help
|
||||||
|
Usage: gpm init
|
||||||
|
Initialize gpm
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
-h,--help Show this help text
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
*** New Issue
|
||||||
|
|
||||||
|
#+BEGIN_SRC
|
||||||
|
> gpm new-issue --help
|
||||||
|
Usage: gpm new-issue [-i|--interactive] [-p|--priority PRIORITY]
|
||||||
|
[-s|--status STATUS] [-t|--title TITLE]
|
||||||
|
[-c|--creator CREATOR] [-b|--branch BRANCH]
|
||||||
|
[-g|--tags TAGS] [-a|--assignee ASSIGNEE]
|
||||||
|
[-r|--reviewers REVIEWERS] [-d|--descr DESCR]
|
||||||
|
Create a new Issue
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
-i,--interactive Interactive mode
|
||||||
|
-p,--priority PRIORITY Priority A,B,C
|
||||||
|
-s,--status STATUS The status of the issue (TODO, QUESTION, ...)
|
||||||
|
-t,--title TITLE The status title
|
||||||
|
-c,--creator CREATOR The user that created the issue
|
||||||
|
-b,--branch BRANCH The branch related to the issue
|
||||||
|
-g,--tags TAGS comma separated tags
|
||||||
|
-a,--assignee ASSIGNEE Assignee
|
||||||
|
-r,--reviewers REVIEWERS comma separated reviewers
|
||||||
|
-d,--descr DESCR Long issue description
|
||||||
|
-h,--help Show this help text
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
To edit an issue, manually change your branch to =gpm= and edit the =issues.org=
|
||||||
|
file.
|
||||||
|
|
||||||
|
*** Review
|
||||||
|
|
||||||
|
You can start a review, it will handle the task of creating a file where you can
|
||||||
|
annotate your comments. It will then create a file in
|
||||||
|
=reviews/<branch-name>-<reviewer>.org=.
|
||||||
|
|
||||||
|
The review process is quite open even if some helpers are provided.
|
||||||
|
|
||||||
|
#+BEGIN_SRC
|
||||||
|
> gpm review --help
|
||||||
|
Usage: gpm review (accept | feedback | question | request-change | reject |
|
||||||
|
start | end | show | retrieve)
|
||||||
|
Review (use current branch by default)
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
-h,--help Show this help text
|
||||||
|
|
||||||
|
Available commands:
|
||||||
|
accept Accept the merge
|
||||||
|
feedback Provide a feedback
|
||||||
|
question Ask a question
|
||||||
|
request-change Request some Changes to merge
|
||||||
|
reject Reject the merge
|
||||||
|
start Start a new review
|
||||||
|
end End a review
|
||||||
|
show Show the review
|
||||||
|
retrieve Retrieve all the reviews for current branch
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
*** Serve
|
||||||
|
|
||||||
|
Expose a minimal read-only web interface of your repositories.
|
||||||
|
And serve the repository using =git= protocol.
|
||||||
|
|
||||||
|
- Web interface http://localhost:1234
|
||||||
|
- Git repository =git://localhost:9418/your-repo-name=
|
||||||
|
|
||||||
|
#+BEGIN_SRC
|
||||||
|
> gpm serve --help
|
||||||
|
Usage: gpm serve (start | stop | update | path)
|
||||||
|
Serve the git to the web
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
-h,--help Show this help text
|
||||||
|
|
||||||
|
Available commands:
|
||||||
|
start Start to serve all gpm tracked repositories
|
||||||
|
stop Stop to serve all gpm tracked repositories
|
||||||
|
update Update the served git repository
|
||||||
|
path Show the path of the bare repository
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
*** Hooks
|
||||||
|
|
||||||
|
Synchronize hooks in all your repositories.
|
||||||
|
|
||||||
|
#+BEGIN_SRC
|
||||||
|
> gpm hooks --help
|
||||||
|
Usage: gpm hooks sync
|
||||||
|
Handle hooks for this git repository
|
||||||
|
|
||||||
|
Available options:
|
||||||
|
-h,--help Show this help text
|
||||||
|
|
||||||
|
Available commands:
|
||||||
|
sync Synchronize hooks from gpm branch
|
||||||
|
#+END_SRC
|
||||||
|
|
||||||
|
* Considerations
|
||||||
|
|
||||||
|
One of the goal of this project is to handle a lot of things handled by github
|
||||||
|
but with minimality. Everything used here is open source and really easy to use.
|
||||||
|
|
||||||
|
** No Push?
|
||||||
|
|
||||||
|
I tend to prefer pull request only, that is far easier not to handle identities
|
||||||
|
through web system. There is a manually provided hooks to only accepts push/pull
|
||||||
|
if all the commit are signed via a list of authorized GPG keys.
|
||||||
|
|
||||||
|
** Ops?
|
||||||
|
|
||||||
|
Managing the CI/CD through another 3rd party parallel branch is not simple.
|
||||||
|
Mainly part of the CI/CD script directly depends on some code change, and as so,
|
||||||
|
should be present in the dev branches. But also part of the code should be
|
||||||
|
independant. So the question on how to handle ops code is still open for me.
|
||||||
|
|
||||||
|
* About
|
||||||
** Project Management Format
|
** Project Management Format
|
||||||
|
|
||||||
As one goal is also to provide minimal friction I wouldn't advise to use
|
As one goal is also to provide minimal friction I wouldn't advise to use
|
||||||
|
@ -146,14 +320,13 @@ Starting with only basic features (TODO / INPROGRESS / DONE)
|
||||||
Then, priority, multiple users, tags, many meta infos by task.
|
Then, priority, multiple users, tags, many meta infos by task.
|
||||||
Task organized as tree of tasks and subtasks.
|
Task organized as tree of tasks and subtasks.
|
||||||
|
|
||||||
* Why is this important?
|
** Why is this important?
|
||||||
It is very important to put all those meta-data about your project inside the
|
It is very important to put all those meta-data about your project inside the
|
||||||
repository because:
|
repository because:
|
||||||
- you are no more dependant on any 3rd party tool to manage your project
|
- you are no more dependant on any 3rd party tool to manage your project
|
||||||
- you can easily change how you host your git project
|
- you can easily change how you host your git project
|
||||||
- anyone with just a text editor can manage those tasks.
|
- anyone with just a text editor can manage those tasks.
|
||||||
|
** After that
|
||||||
* After that
|
|
||||||
|
|
||||||
A goal is to complete the =gpm= tool with a few other one all isolated but which
|
A goal is to complete the =gpm= tool with a few other one all isolated but which
|
||||||
could all work together.
|
could all work together.
|
||||||
|
@ -161,11 +334,12 @@ could all work together.
|
||||||
- hook handling (so all your team member can share nice hooks, for example,
|
- hook handling (so all your team member can share nice hooks, for example,
|
||||||
preformat commit messages, launch tests before publishing a pull request,
|
preformat commit messages, launch tests before publishing a pull request,
|
||||||
etc...)
|
etc...)
|
||||||
- minimal web interface to navigate your project files, commits, branches, etc...
|
- minimal web interface to navigate your project management related files,
|
||||||
|
commits, branches, etc...
|
||||||
- identity handling so hand in hand with hook handle and web interface provide
|
- identity handling so hand in hand with hook handle and web interface provide
|
||||||
the ability to manage how contributor can access your tool
|
the ability to manage how contributor can access your tool
|
||||||
|
|
||||||
** Identfy users, allow access and trust them
|
*** Identfy users, allow access and trust them
|
||||||
|
|
||||||
With this system it will be more about a pull from other than wait for them to push.
|
With this system it will be more about a pull from other than wait for them to push.
|
||||||
The identity system should be decentralized and based on GPG keys.
|
The identity system should be decentralized and based on GPG keys.
|
||||||
|
|
|
@ -21,11 +21,11 @@ where
|
||||||
import Protolude hiding (ask, die, stdout, (%))
|
import Protolude hiding (ask, die, stdout, (%))
|
||||||
import Turtle
|
import Turtle
|
||||||
|
|
||||||
|
import GPM.Helpers (debug_, getGPMDataDir, getGitUser, green)
|
||||||
|
|
||||||
import qualified Data.Char as Char
|
import qualified Data.Char as Char
|
||||||
import Data.FileEmbed (embedStringFile)
|
import Data.FileEmbed (embedStringFile)
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
import GPM.Helpers (debug_, getGPMDataDir, getGitUser, green,
|
|
||||||
green)
|
|
||||||
import qualified System.Directory as Directory
|
import qualified System.Directory as Directory
|
||||||
import Text.Mustache
|
import Text.Mustache
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{-# LANGUAGE NoImplicitPrelude #-}
|
{-# LANGUAGE NoImplicitPrelude #-}
|
||||||
|
{-# LANGUAGE TemplateHaskell #-}
|
||||||
{-|
|
{-|
|
||||||
module : GPM.Serve
|
module : GPM.Serve
|
||||||
Description : GPM review related commands
|
Description : GPM review related commands
|
||||||
|
@ -23,6 +24,7 @@ import GPM.Helpers (debug, debug_, getGPMDataDir,
|
||||||
|
|
||||||
-- | External Lib Imports
|
-- | External Lib Imports
|
||||||
import qualified Data.Text as Text
|
import qualified Data.Text as Text
|
||||||
|
import Data.FileEmbed (embedStringFile)
|
||||||
|
|
||||||
-- | Retrieve a public dir to serve git repositories
|
-- | Retrieve a public dir to serve git repositories
|
||||||
getPublicDir :: IO Turtle.FilePath
|
getPublicDir :: IO Turtle.FilePath
|
||||||
|
@ -66,9 +68,11 @@ init = do
|
||||||
debug_ (format ("git clone --mirror "%fp%" "%fp)
|
debug_ (format ("git clone --mirror "%fp%" "%fp)
|
||||||
repoRoot
|
repoRoot
|
||||||
publicProjectDir)
|
publicProjectDir)
|
||||||
inDir publicProjectDir $ do
|
inDir (publicProjectDir </> "hooks") $ do
|
||||||
mv ("hooks" </> "post-update.sample") ("hooks" </> "post-update")
|
mv "post-update.sample" "post-update"
|
||||||
_ <- chmod executable ("hooks" </> "post-update")
|
_ <- chmod executable "post-update"
|
||||||
|
writeFile "pre-receive-hooks" $(embedStringFile "templates/pre-receive-hooks")
|
||||||
|
_ <- chmod executable "pre-receive-hooks"
|
||||||
debug_ "git update-server-info"
|
debug_ "git update-server-info"
|
||||||
|
|
||||||
-- | Serve command
|
-- | Serve command
|
||||||
|
@ -121,11 +125,10 @@ handleProjectDir = getPublicDir >>= putText . format fp
|
||||||
dirServe :: Turtle.FilePath -> IO ()
|
dirServe :: Turtle.FilePath -> IO ()
|
||||||
dirServe pubdir = do
|
dirServe pubdir = do
|
||||||
gpmDataDir <- getGPMDataDir
|
gpmDataDir <- getGPMDataDir
|
||||||
let pidfiledir = gpmDataDir </> "procs"
|
|
||||||
debug_ $
|
debug_ $
|
||||||
format ("git daemon --detach --pid-file="%fp
|
format ("git daemon --detach --pid-file="%fp
|
||||||
%" --reuseaddr --export-all --base-path="%fp%" "%fp)
|
%" --reuseaddr --export-all --base-path="%fp%" "%fp)
|
||||||
(pidfiledir </> "gitServePID")
|
(gpmDataDir </> "git-daemon-pid")
|
||||||
pubdir
|
pubdir
|
||||||
pubdir
|
pubdir
|
||||||
|
|
||||||
|
@ -133,7 +136,7 @@ dirStopServe :: IO ()
|
||||||
dirStopServe = do
|
dirStopServe = do
|
||||||
gpmDataDir <- getGPMDataDir
|
gpmDataDir <- getGPMDataDir
|
||||||
inDir gpmDataDir $ do
|
inDir gpmDataDir $ do
|
||||||
pidtxt <- readTextFile (gpmDataDir </>"procs" </> "gitServePID")
|
pidtxt <- readTextFile (gpmDataDir </> "git-daemon-pid")
|
||||||
if Text.null pidtxt
|
if Text.null pidtxt
|
||||||
then putErrText "git daemon doesn't appear to be running"
|
then putErrText "git daemon doesn't appear to be running"
|
||||||
else debug_ ("kill " <> pidtxt)
|
else debug_ ("kill " <> pidtxt)
|
||||||
|
|
64
templates/pre-receive-hooks
Normal file
64
templates/pre-receive-hooks
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
!/usr/bin/env bash
|
||||||
|
|
||||||
|
#
|
||||||
|
# Pre-receive hook that will block any unsigned commits and tags when pushed.
|
||||||
|
# It will also only accept a list of predefined GPG keys fingerprints (your team)
|
||||||
|
#
|
||||||
|
# More details on GPG commit and tag signing can be found on
|
||||||
|
#
|
||||||
|
# https://help.github.com/articles/signing-commits-using-gpg/
|
||||||
|
#
|
||||||
|
|
||||||
|
# Use your authorized fingerprints!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
authorized_keys_fingerprints=(
|
||||||
|
"0000000000000000000000000000000000000000"
|
||||||
|
"0000000000000000000000000000000000000001"
|
||||||
|
)
|
||||||
|
|
||||||
|
function join_by { local IFS="$1"; shift; echo "$*"; }
|
||||||
|
fingerprints_regex="($(join_by '|' ${authorized_keys_fingerprints[@]}))"
|
||||||
|
|
||||||
|
zero_commit="0000000000000000000000000000000000000000"
|
||||||
|
|
||||||
|
# we have to change the home directory of GPG
|
||||||
|
# as in the default environment, /root/.gnupg is not writeable
|
||||||
|
export GNUPGHOME=/tmp/
|
||||||
|
|
||||||
|
# Do not traverse over commits that are already in the repository
|
||||||
|
# (e.g. in a different branch)
|
||||||
|
# This prevents funny errors if pre-receive hooks got enabled after some
|
||||||
|
# commits got already in and then somebody tries to create a new branch
|
||||||
|
# If this is unwanted behavior, just set the variable to empty
|
||||||
|
excludeExisting="--not --all"
|
||||||
|
|
||||||
|
while read oldrev newrev refname; do
|
||||||
|
# echo "payload"
|
||||||
|
echo $refname $oldrev $newrev
|
||||||
|
|
||||||
|
# branch or tag get deleted
|
||||||
|
if [ "$newrev" = "$zero_commit" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for new branch or tag
|
||||||
|
if [ "$oldrev" = "$zero_commit" ]; then
|
||||||
|
span=`git rev-list $newrev $excludeExisting`
|
||||||
|
else
|
||||||
|
span=`git rev-list $oldrev..$newrev $excludeExisting`
|
||||||
|
fi
|
||||||
|
|
||||||
|
for COMMIT in $span;
|
||||||
|
do
|
||||||
|
signed=$(git verify-commit --raw $COMMIT 2>&1 | grep -E "VALIDSIG $authorized_keys_fingerprints ")
|
||||||
|
if test -n "$signed"; then
|
||||||
|
echo Commit $COMMIT was signed by a GPG key: $signed
|
||||||
|
else
|
||||||
|
echo Commit $COMMIT was not signed by a GPG key, rejecting push
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
done
|
||||||
|
exit 0
|
Loading…
Reference in a new issue