git-gamble
git-gamble
is a tool that helps to develop the right thing π, baby step by baby step πΆπ¦Άgit-gamble
use the TCRDD methodgit-gamble
is agit
addon
Install the tool
Read about the usage
Watch the demo
Theory
Alternatively : you can watch the slides about the theory
TDD
TDD (Test Driven Development) is cool!
It makes sure we develop the right thing, step by step
Short version
flowchart TB start([Start]) ==> red([Write only 1 failing test]) ==> green([Make all tests pass]) ==> refactor([Refactor]) ==> finish([Finish]) refactor -.->|Incomplete ?| red classDef red_phase font-weight:bold,color:black,fill:coral; class red red_phase classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase classDef refactor_phase font-weight:bold,color:black,fill:#668cff; class refactor refactor_phase
Long version
flowchart TB subgraph red[Red] direction LR fix_layout(( )) ==> write_a_test write_a_test[Write only 1 failing test] ==> run_tests{{Run tests}} run_tests -.->|Pass\nWrite another test| write_a_test end start([Start]) === fix_layout run_tests ==>|Fail| green([Green]) classDef red_phase font-weight:bold,color:black,fill:coral; class red red_phase classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase classDef refactor_phase font-weight:bold,color:black,fill:#668cff; class refactor refactor_phase classDef fix_layout stroke:white,fill:transparent; class fix_layout fix_layout
flowchart TB subgraph green[Green] direction LR fix_layout(( )) ==> write_the_minimum_code write_the_minimum_code[Write the minimum code\nto make all tests pass] ==> run_tests{{Run tests}} run_tests -.->|Fail\nTry something else| write_the_minimum_code end red([Red]) === fix_layout run_tests ==>|Pass| refactor([Refactor]) classDef red_phase font-weight:bold,color:black,fill:coral; class red red_phase classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase classDef refactor_phase font-weight:bold,color:black,fill:#668cff; class refactor refactor_phase classDef fix_layout stroke:white,fill:transparent; class fix_layout fix_layout
flowchart TB subgraph refactor[Refactor] direction LR rewrite_code[Rewrite code\nwithout changing the behavior] ==> run_tests{{Run tests}} -.->|Pass\nAnother things to refactor ?| rewrite_code run_tests -->|Fail\nChange something else| rewrite_code end green([Green]) ==> rewrite_code run_tests ==>|Pass| finish([Finish]) run_tests -.->|Pass\nAnother feature to add ?| red([Red]) classDef red_phase font-weight:bold,color:black,fill:coral; class red red_phase classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase classDef refactor_phase font-weight:bold,color:black,fill:#668cff; class refactor refactor_phase classDef fix_layout stroke:white,fill:transparent; class fix_layout fix_layout
TCR
TCR (test && commit || revert
) is cool!
It encourages doing baby steps, reducing the waste when we are wrong
flowchart TB gamble{{Gambling on test results}} gamble ==>|Pass| commit(Commit) gamble -->|Fail| revert(Revert)
flowchart TB start([Start]) ==> green([Change some code]) ==> finish([Finish]) green -.->|Incomplete ?| green classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase
But it doesn't allow us to see the tests failing
So:
-
Maybe we test nothing (assert forgotten)
def test_should_be_Buzz_given_5(): input = 5 actual = fizz_buzz(input) # Oops! Assert has been forgotten
-
Maybe we are testing something that is not the thing we should be testing
it("should be Fizz given 3", () => { const input = 3; const actual = fizzBuzz(input); expect(input).toBe("Fizz"); // Oops! Asserts on the input value instead of the actual value });
Detailed view
flowchart TB subgraph green[Green] direction TB start([Start]) ==> change_code[Change some code] ==> run_tests{{"Run tests\n<code>test && commit || revert</code>"}} ==>|Pass| commit(Commit) ==> finish([Finish]) commit -->|Another things to change ?| change_code run_tests -.->|Fail| revert(Revert) -.->|Try something else| change_code end classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase
TCRDD
TCRDD = TCR + TDD
TCRDD blends the constraints of the two methods to benefit from their advantages
flowchart TB red{{Write only 1 failing test}} green{{Make all tests pass}} refactor{{Refactor}} red ==>|Fail| red_commit(Commit) ==> green green ==>|Pass| green_commit(Commit) ==> refactor refactor ==>|Pass| refactor_commit(Commit) red -->|Pass| red_revert(Revert) --> red green -->|Fail| green_revert(Revert) --> green refactor -->|Fail| refactor_revert(Revert) --> refactor classDef red_phase font-weight:bold,color:black,fill:coral; class red red_phase classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase classDef refactor_phase font-weight:bold,color:black,fill:#668cff; class refactor refactor_phase
flowchart TB subgraph red[Red] direction LR fix_layout(( )) ==> write_a_test write_a_test[Write only 1 test] ==> gamble[/Gamble that the test fail\n<code>git gamble --red</code>/] ==> run_tests{{Actually run tests}} ==>|Fail| commit(Commit) run_tests -->|Pass| revert(Revert) -->|Write another test| write_a_test end start([Start]) ==> fix_layout commit ==> green([Green]) classDef red_phase font-weight:bold,color:black,fill:coral; class red red_phase classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase classDef refactor_phase font-weight:bold,color:black,fill:#668cff; class refactor refactor_phase classDef fix_layout stroke:white,fill:transparent; class fix_layout fix_layout
flowchart TB subgraph green[Green] direction LR fix_layout(( )) ==> write_the_minimum_code write_the_minimum_code[Write the minimum code] ==> gamble[/Gamble that the tests pass\n<code>git gamble --green</code>/] ==> run_tests{{Actually run tests}} ==>|Pass| commit(Commit) run_tests -->|Fail| revert(Revert) -->|Try something else| write_the_minimum_code end red([Red]) ==> fix_layout commit ==> refactor([Refactor]) classDef red_phase font-weight:bold,color:black,fill:coral; class red red_phase classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase classDef refactor_phase font-weight:bold,color:black,fill:#668cff; class refactor refactor_phase classDef fix_layout stroke:white,fill:transparent; class fix_layout fix_layout
flowchart TB subgraph refactor[Refactor] direction LR rewrite_code[Rewrite code\nwithout changing the behavior] ==> gamble[/Gamble that the tests pass\n<code>git gamble --refactor</code>/] ==> run_tests{{Actually run tests}} ==>|Pass| commit(Commit) -.->|Another things to refactor ?| rewrite_code run_tests -->|Fail| revert(Revert) -->|Change something else| rewrite_code end green([Green]) ==> rewrite_code commit ==> finish([Finish]) commit -.->|Another feature to add ?| red([Red]) classDef red_phase font-weight:bold,color:black,fill:coral; class red red_phase classDef green_phase font-weight:bold,color:black,fill:#1cba1c; class green green_phase classDef refactor_phase font-weight:bold,color:black,fill:#668cff; class refactor refactor_phase classDef fix_layout stroke:white,fill:transparent; class fix_layout fix_layout
git-gamble
is a tool that helps to use the TCRDD method
History of TCRDD
timeline title History of TCRDD 2018 : TCR `test && commit || revert` Article by Kent Beck 2018-09-28 : TCRDD _TDD is dead, long live TCR?_ Article by Xavier Detant 2018-12-03 2019 : Xavier's TCRDD First commit 2019-08-26 : git-gamble First commit 2019-12-07 2021 : Murex's TCR First commit 2021-06-16
- test && commit || revert
- TDD is dead, long live TCR?
- Xavier's TCRDD first commit
- git-gamble's first commit
- Murex's TCR first commit
Similar projects
Reinvent the wheel
Why reinvent the wheel?
The script of Xavier Detant already works well
Because i would like to learn Rust Β―\_(γ)_/Β―
Installation
There is several methods to install depending on your operating system
Improving installation
Installation is currently not really convenient, so contributions are welcome
Feel free to add package to your favorite package repository
Methods
Improving installation
Installation is currently not really convenient, so contributions are welcome
Feel free to add package to your favorite package repository
Nix / NixOS
Install Nix
Use without installing
export NIX_CONFIG="extra-experimental-features = flakes nix-command"
nix run gitlab:pinage404/git-gamble -- --help
To install it at
-
project level with
flake.nix
, see exampleTL;DR
export NIX_CONFIG="extra-experimental-features = flakes nix-command" nix flake init --template gitlab:pinage404/git-gamble
-
project level with
shell.nix
, see example -
user level with Home Manager, see example
DirEnv
To automate the setup of the environment it's recommanded to install DirEnv
Add in .envrc
use nix
Then run this command
direnv allow
Cachix
If you want to avoid rebuilding from scratch, you can use Cachix
cachix use git-gamble
Update
export NIX_CONFIG="extra-experimental-features = flakes nix-command"
nix flake update
AppImage
Requirements
git-gamble
doesn't repackage git
, it uses the one installed on your system
You have to install git
manually
Make sure it is available in your $PATH
, you can check it with this command
git --help
Install latest main version
-
Download the latest main version
curl --location "https://gitlab.com/pinage404/git-gamble/-/jobs/artifacts/main/raw/target%2Fgit-gamble-v-x86_64.AppImage?job=package%20AppImage" --output git-gamble-x86_64.AppImage
-
Make it executable
chmod +x git-gamble-x86_64.AppImage
-
Put it your
$PATH
# for example mkdir -p ~/.local/bin ln git-gamble-x86_64.AppImage ~/.local/bin/git-gamble export PATH+=":~/.local/bin"
Install latest released version
-
Download the latest released version
curl --location "https://gitlab.com/api/v4/projects/pinage404%2Fgit-gamble/packages/generic/git-gamble-AppImage/2.7.0/git-gamble-v2.7.0-x86_64.AppImage" --output git-gamble-v2.7.0-x86_64.AppImage
-
Make it executable
chmod +x git-gamble-v2.7.0-x86_64.AppImage
-
Put it your
$PATH
# for example mkdir -p ~/.local/bin ln git-gamble-v2.7.0-x86_64.AppImage ~/.local/bin/git-gamble export PATH+=":~/.local/bin"
Update
There is no update mechanism
Uninstall
Just remove the binary from your $PATH
Debian
Requirements
git-gamble
doesn't repackage git
, it uses the one installed on your system
You have to install git
manually
Make sure it is available in your $PATH
, you can check it with this command
git --help
Install
-
Go to the latest version of
git-gamble-debian
-
Download the latest version
git-gamble_2.7.0_amd64.deb
-
Install package
As root
dpkg --install git-gamble*.deb
This is not really convenient but a better way will come when GitLab Debian Package Manager MVC will be available
Improving installation
Installation is currently not really convenient, so contributions are welcome
Feel free to add package to your favorite package repository
Update
There is no update mechanism
Uninstall
As root
dpkg --remove git-gamble
Mac OS X / Homebrew
brew tap pinage404/git-gamble https://gitlab.com/pinage404/git-gamble.git
brew install --HEAD git-gamble
Upgrade
git-gamble
has not yet been packaged by Homebrew
To upgrade git-gamble
, run this command
brew reinstall git-gamble
Improving installation
Installation is currently not really convenient, so contributions are welcome
Feel free to add package to your favorite package repository
Uninstall
brew uninstall git-gamble
brew untap pinage404/git-gamble
Windows / Chocolatey
Requirements
git-gamble
doesn't repackage git
, it uses the one installed on your system
You have to install git
manually
Make sure it is available in your $PATH
, you can check it with this command
git --help
Install
-
Go to the latest version of
git-gamble.portable
-
Download the latest version
git-gamble.portable.2.7.0.nupkg
-
Install package
Follow GitLab's documentation and Chocolatey's documentation
choco install ./git-gamble.portable.2.7.0.nupkg
Improving installation
Installation is currently not really convenient, so contributions are welcome
Feel free to add package to your favorite package repository
Update
choco upgrade git-gamble
Uninstall
choco uninstall git-gamble
Cargo
Requirements
git-gamble
doesn't repackage git
, it uses the one installed on your system
You have to install git
manually
Make sure it is available in your $PATH
, you can check it with this command
git --help
Install
cargo install git-gamble
Add ~/.cargo/bin
to your $PATH
Fish:
set --export --append PATH ~/.cargo/bin
Bash / ZSH:
export PATH=$PATH:~/.cargo/bin
Update
cargo update --package git-gamble
Uninstall
cargo uninstall git-gamble
Download the binary
Requirements
git-gamble
doesn't repackage git
, it uses the one installed on your system
You have to install git
manually
Make sure it is available in your $PATH
, you can check it with this command
git --help
Install
Only for Linux and Windows x86_64
- Download the binary on the release page
- Put it in your
$PATH
Update
There is no update mechanism
Uninstall
Just remove the binary from your $PATH
Check the installation
Check if all have been well settled
git gamble -version
If it has been well settled , it should output this :
git-gamble 2.7.0
If it has been badly settled , it should output this :
git : 'gamble' is not a git command. See 'git --help'.
Usage
How to use ?
To see all available flags and options
git-gamble --help # dash between `git` and `gamble` is only needed for --help
There are two ways to run your tests using git gamble :
In both cases, the test command must exit with a 0 status when there are 0 failed tests, anything else is considered as a failure
Environment variable
Setting an environment variable and run only the git command
command
-
Start by setting a environment variable with the test command :
The example below is for running your tests for a Rust project
export GAMBLE_TEST_COMMAND="cargo test"
-
Write a failing test in your codebase, then :
git gamble --red # or git gamble --fail
-
Write the minimum code to make tests pass, then :
git gamble --green # or git gamble --pass
-
Refactor your code, then :
git gamble --refactor # or git gamble --pass
Repeating the test command
Typing the git gamble
command with your test command repetitively
-
Write a failing test in your codebase, then :
git gamble --red -- $YOUR_TEST_COMMAND
-
Write the minimum code to make tests pass, then :
git gamble --green -- $YOUR_TEST_COMMAND
-
Refactor your code, then :
git gamble --refactor -- $YOUR_TEST_COMMAND
Demo
For more detailed example, this the demo
When to use it ?
- You want to :
- learn nor practice TDD
- learn nor practice TCR without the drawbacks
- practice a new language
- be driven by a strong methodology
- be carried along by the strong methodology
- practice breaking down your steps to achieve baby steps, using, for example :
- You follow the Test F.I.R.S.T. Principles
When NOT to use it ?
- You don't really want to try this methodology
- You will eventually cheat and lose the benefits while keeping some of the drawbacks
- You don't know what you want to do
- Your tests :
- ran very slowly
- are flaky
- are not self-validating
- You want to use double-loop TDD
- unless you don't run tests on bigger loops when you run smaller loops
Demo
git-gamble
's demo to develop using TCRDD by doing baby steps
on a simple program
git-gamble
works with all languages and tools and editors
for this example, i use python
with pytest
and nano
export GAMBLE_TEST_COMMAND='pytest --quiet'
note : for a simpler demo, test code and production code are in the same file
Alternatively : you can also watch the slides about the demo
First TDD loop β°
Write a program that says
Hello world
First, π΄ Red phase : write a test that fails for the good reason
Alternative text
nano test_hello.py
def hello():
pass
def test_say_hello_world():
assert hello() == 'Hello world'
Then, gamble that the tests fail
git gamble --red
βοΈ Committed
Second, π’ Green phase : write the minimum code to pass the tests
Let's fake it
Alternative text
nano test_hello.py
def hello():
return 'Hello word'
Then, gamble that the tests pass
git gamble --green
β Reverted
Oh no !
I made a typo
def hello():
- return 'Hello word'
+ return 'Hello world'
Try again
Let's fake it without typo
Alternative text
nano test_hello.py
def hello():
return 'Hello world'
Gamble again that the tests pass
git gamble --green
βοΈ Committed
Yeah !
Third, π Refactor phase : Nothing to refactor yet
Then π Repeat β°
Second TDD loop βΏ
Write a program that says
Hello
to the given name when a name is given
π΄ Red phase
Alternative text
nano test_hello.py
def test_say_hello_name_given_a_name():
assert hello('Jon') == 'Hello Jon'
git gamble --red
βοΈ Committed
π’ Green phase
Add a simple condition to handle both cases
Alternative text
nano test_hello.py
def hello(arg=None):
if arg:
return f'Hello {arg}'
return 'Hello world'
git gamble --green
βοΈ Committed
π Refactor loop β°
π Refactor phase
It can be simplified
Alternative text
nano test_hello.py
def hello(arg='world'):
return f'Hello {arg}'
git gamble --refactor
βοΈ Committed
Still π Refactor phase : i have something else to refactor βΏ
Better naming
Alternative text
nano test_hello.py
def hello(name='world'):
return f'Hello {name}'
git gamble --refactor
βοΈ Committed
And so on... βΏ
π Repeat until you have tested all the rules, are satisfied and enougth confident
Command Line Interface
git-gamble --help
Blend TCR (`test && commit || revert`) + TDD (Test Driven Development) to make sure to develop
the right thing π, baby step by baby step πΆπ¦Ά
Usage: git-gamble [OPTIONS] <--pass|--fail> -- <TEST_COMMAND>...
git-gamble [OPTIONS] <COMMAND>
Commands:
generate-shell-completions
help Print this message or the help of the given subcommand(s)
Arguments:
<TEST_COMMAND>... The command to execute to know the result [env: GAMBLE_TEST_COMMAND=]
Options:
-g, --pass Gamble that tests should pass [aliases: green, refactor]
-r, --fail Gamble that tests should fail [aliases: red]
-n, --dry-run Do not make any changes
--no-verify Do not run git hooks
-C, --repository-path <REPOSITORY_PATH> Repository path [default: .]
-m, --message <MESSAGE> Commit's message [default: ]
-e, --edit Open editor to edit commit's message
--fixup <FIXUP> Fixes up commit
--squash <SQUASH> Construct a commit message for use with `rebase --autosquash`
-h, --help Print help
-V, --version Print version
Any contributions (feedback, bug report, merge request ...) are welcome
https://pinage404.gitlab.io/git-gamble/contributing/index.html
Shell completions
To manually generate shell completions you can use this command
git gamble generate-shell-completions --help
Usage: git-gamble generate-shell-completions [SHELL]
Arguments:
[SHELL]
Put generated file here :
* Fish https://fishshell.com/docs/current/completions.html#where-to-put-completions
* Others shells ; Don't know, MR are welcome
[possible values: bash, elvish, fish, powershell, zsh]
Options:
-h, --help
Print help (see a summary with '-h')
Usage examples
There is several examples with several languages in the nix-sandboxes repository
In each language folder, there is a .envrc
file, which contains the variable GAMBLE_TEST_COMMAND
, that mainly refers to mask
commands that are described in the sibling file maskfile.md
Refactoring session
Install watchexec
, then :
watchexec -- git gamble --refactor
This is just TCR (without TDD)
Git Aliases
~/.gitconfig
or .git/config
[alias]
# git-gamble aliases
fail = gamble --fail
pass = gamble --pass
faile = gamble --fail --edit
passe = gamble --pass --edit
# git-gamble TDD's aliases
red = gamble --red
green = gamble --green
refactor = gamble --refactor
rede = gamble --red --edit
If you use Fish Shell, it works very well with the Oh My Fish plugin enlarge_your_git_alias
Hooks
git-gamble
provides his own custom hooks :
pre-gamble <GAMBLED>
pre-gamble
hook is executed with one argument<GAMBLED>
post-gamble <GAMBLED> <ACTUAL>
post-gamble
hook is executed with two arguments<GAMBLED>
and<ACTUAL>
Where :
<GAMBLED>
ispass
orfail
<ACTUAL>
ispass
orfail
Custom hooks of git-gamble
are like any other client-side hooks :
- a hook is a file
- a hook must be in the
$GIT_DIR/hooks/
folder- or in the folder configured by
git config core.hooksPath
- or in the folder configured by
- a hook must be executable (
chmod +x .git/hooks/*-gamble
) - will not be executed if any of these options are used:
--no-verify
--dry-run
Check the hooks
' folder for examples of use
post-gamble.real_time_collaboration.sample.sh
is specially adapted to near real-time collaborationpost-gamble.assistant.sample.sh
is a simple assistant that displays tips based on the result of the gamble- If you are using
git-time-keeper
The following diagram shows when custom hooks are executed in relation to normal git hooks
flowchart LR subgraph git-gamble's hooks' lifecyle direction TB git-gamble([git-gamble\n--pass OR --fail]) --> pre-gamble[pre-gamble\npass OR fail]:::gitGambleHookStyle --> GAMBLE_TEST_COMMAND([exec $GAMBLE_TEST_COMMAND]):::gitGambleInternalStyle --> gamble{Result ?}:::gitGambleInternalStyle gamble -->|Success| Success subgraph Success direction TB git_add([git add --all]):::gitGambleInternalStyle --> git_commit([git commit]):::gitGambleInternalStyle --> pre-commit:::gitHookStyle --> prepare-commit-msg[prepare-commit-msg\n$GIT_DIR/COMMIT_EDITMSG\nmessage]:::gitHookStyle --> commit-msg[commit-msg\n$GIT_DIR/COMMIT_EDITMSG]:::gitHookStyle --> post-commit:::gitHookStyle post-commit --> rewritten? rewritten?{{"Last commit rewritten ?\nWhen gambling fail\nafter another gamble fail"}}:::gitGambleInternalStyle rewritten? -->|Yes| post-rewrite[post-rewrite\namend]:::gitHookStyle --> post-gamble-success rewritten? -->|No| post-gamble-success post-gamble-success[post-gamble\npass OR fail\nsuccess]:::gitGambleHookStyle end gamble -->|Error| Error subgraph Error direction TB git_reset([git reset --hard]):::gitGambleInternalStyle --> post-gamble-error[post-gamble\npass OR fail\nerror]:::gitGambleHookStyle end end subgraph Legend direction TB subgraph Legend_[" "] direction LR command([Command executed by user]) git-gamble_command([Command executed by git-gamble]):::gitGambleInternalStyle condition{Condition ?}:::gitGambleInternalStyle end subgraph Hooks direction LR hook[git's hook]:::gitHookStyle hook_with_argument[git's hook\nfirst argument\nsecond argument]:::gitHookStyle git-gamble_hook_with_argument[git-gamble's hook\nfirst argument\nsecond argument]:::gitGambleHookStyle end end classDef gitHookStyle fill:#f05133,color:black,stroke:black; classDef gitGambleHookStyle fill:#5a3730,color:white,stroke:white; classDef gitGambleInternalStyle fill:#411d16,color:white,stroke:white;
VSCode
If you want to run git-gamble
from VSCode
Add this in your .vscode/tasks.json
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "Gamble fail",
"type": "shell",
"command": "direnv exec . git gamble --fail",
"group": "test",
},
{
"label": "Gamble pass",
"type": "shell",
"command": "direnv exec . git gamble --pass",
"group": "test",
},
{
"label": "Gamble red",
"type": "shell",
"command": "direnv exec . git gamble --red",
"group": "test",
},
{
"label": "Gamble green",
"type": "shell",
"command": "direnv exec . git gamble --green",
"group": "test",
},
{
"label": "Gamble refactor",
"type": "shell",
"command": "direnv exec . git gamble --refactor",
"group": "test",
},
]
}
Give Love β€οΈ nor Give Feedbacks π£οΈ
Do you like this project ?
- If yes, please add a star on GitLab
- If no, please open an issue to give your feedbacks
Contributing
Any contributions (feedback, bug report, merge request ...) are welcome
Respect the code of conduct
Follow Keep a Changelog
Add to a package repository
Adding package to the X
package repository where the X
package repository is e.g. Nixpgks, Debian, Homebrew, Chocolatey ...
Feel free to do it, we don't plan to do it at the moment, it's too long to learn and understand how each of them works
If you do it, please file an issue or open an MR to update the documentation
Development
The following sections will help you to contribute with a merge request
The coverage report is low because there are mainly end-to-end tests that are not taken into account
Development Setup
Gitpod
You can contribute with just your web browser, directly from Gitpod
Nix
The easiest way to get everything you need is to use Nix
-
Install Nix
-
Install DirEnv
-
Let
direnv
automagically set up the environment by executing the following command in the project directorydirenv allow
Troubleshooting
If you get an error like this one when entering in the folder
direnv: loading ~/Project/git-gamble/.envrc
direnv: using nix
direnv: using cached derivation
direnv: eval /home/pinage404/Project/git-gamble/.direnv/cache-.336020.2128d0aa28e
direnv: loading ./script/setup_variables.sh
Compiling git-gamble v2.4.0-alpha.0 (/home/pinage404/Project/git-gamble)
direnv: ([/nix/store/19arfqh2anf3cxzy8zsiqp08xv6iq6nl-direnv-2.29.0/bin/direnv export fish]) is taking a while to execute. Use CTRL-C to give up.
error: linker `cc` not found
|
= note: No such file or directory (os error 2)
error: could not compile `git-gamble` due to previous error
Just run the following command to fix it
direnv reload
Help wanted to permanently fix this
Manual
- Install Rustup
- Install everything that should normally be installed by DirEnv
Commands
Or just execute
mask help
Debug
There are some logs in the programs, pretty_env_logger
is used to display them
There are 5 levels of logging (from the lightest to the most verbose) :
error
warn
info
debug
trace
The git-gamble
logs are "hidden" behind the with_log
feature
The option --features with_log
(or --all-features
) must be added to each cargo
command for which you want to see logs (e.g.) :
cargo build --all-features
cargo run --all-features
cargo test --all-features
Then, to display logs, add this environment variable :
export RUST_LOG="git_gamble=debug"
To display really everything :
export RUST_LOG="trace"
There are other possibilities for logging in the env_logger
documentation
You can also uncomment variables in the setup script
There is also a command that executes a test with all the outputs displayed
mask test rust debug <the test to filter>
Exemple
mask test rust debug commit_when_tests_fail
Check that the code is properly tested
To verify that the code is actually tested by the tests, run the following command :
mask test mutants
Refactoring session
At the beginning of your session, just run the following command :
cargo watch -- git gamble --refactor
This is just TCR (without TDD)
Deployment
Just run cargo release (in a wide terminal, in order to have --help
not truncated in the usage section)
cargo release
Architectural Decisions Records
The following pages records architectural decisions
Binaries organisation
Story
We (a colleague [referred to as "he" in the following text] and pinage404) used git-gamble
at work
He was not used to using TDD nor TCR
The fear of losing code led to an anti-pattern : before gambling, he took a lot of time to read the code carefully, compile it and execute it in his head, which slowed down the group
This strong methodology should lead you to let yourself be carried along by the tools
He recommended limiting the duration of iterations
git-gamble
has been used by several groups and pinage404 has seen this anti-pattern several times
Context and Problem Statement
To solve the problem of iteration duration, another tool has been created since 2022-07-11, but it is neither documented nor easily distributed
The first version of git-time-keeper
was written in Bash, and works most of the time, in order to have a more stable experience, it will be rewritten in Rust
git-gamble
and git-time-keeper
are tools that work independently and can be used together for an optimal experience
How to create, maintain and distribute several tools ?
Decision Drivers
- from the maintainer's point of view
- easy to set up
- easy to maintain
- easy to distribute
- avoid duplication of configuration and utilities
- from the user's point of view
- easy to install
- easy to use
- easy to understand that each tool can be used separately
- easy to use tools together for an optimal experience
Considered Options
- Repos : several independent repositories
- Workspaces : 1 repository with several Cargo workspaces
- Binaries : 1 repository with 1 crate containing several binaries
Decision Outcome
Chosen option: "Binaries", because this solution seems to have the fewest downsides, see the table below
Pros and Cons of the Options
Repos | Workspaces | Binaries | |
---|---|---|---|
Maintainer | |||
easy to set up | Good, easiest, just git clone | Bad, need a little of work | Neutral, Good if every tools support it |
easy to maintain | Bad, need several maitainance | Good, that's what workspaces are for | Neutral, easy but risk of confusion between what belongs to which tool |
easy to distribute | Bad, need to resetup external platforms | Neutral if every tools support it | Neutral, Good if every tools support it |
avoid duplication | Bad | Neutral, can have a shared Crate | Good |
User | |||
easy to install | Bad, need several installations | Neutral | Neutral, Good if every tools support it |
easy to use | Neutral | Neutral | Neutral |
understand tools are independent | Good | Neutral | Neutral |
easy to use tools together | Bad | Neutral | Neutral |
Total | Good 2 Neutral 1 Bad 5 = -3 | Good 1 Neutral 6 Bad 1 = 0 | Good 1 Neutral 7 Bad 0 = +1 |
Not yet published - Work In Progress
The following pages document work in progress that has not yet been published
All or part of it is subject to change without notice
git-time-keeper
git-time-keeper
is a tool that helps to take baby steps πΆπ¦Ά
Setup
With git-gamble
# git config --local core.hooksPath ./hooks # if you want to versionate hooks
HOOKS_PATH=$(git rev-parse --git-path hooks)
mkdir -p "$HOOKS_PATH"
echo "git-time-keeper 'stop'" >>"$HOOKS_PATH/pre-gamble"
echo "git-time-keeper 'start' 'git-gamble --pass'" >>"$HOOKS_PATH/post-gamble"
chmod +x "$HOOKS_PATH"/{pre,post}-gamble
With git
Without git-gamble
# git config --local core.hooksPath ./hooks # if you want to versionate hooks
HOOKS_PATH=$(git rev-parse --git-path hooks)
mkdir -p "$HOOKS_PATH"
echo "git-time-keeper 'stop'" >>"$HOOKS_PATH/pre-commit"
echo "git-time-keeper 'start'" >>"$HOOKS_PATH/post-commit"
chmod +x "$HOOKS_PATH"/{pre,post}-commit
Set iteration duration
export TIME_KEEPER_MAXIMUM_ITERATION_DURATION=$((3 * 60)) # 3 minutes
How to use ?
When being on time
sequenceDiagram actor Dev participant git participant hooks participant git-time-keeper Dev->>git: git commit git->>hooks: git hook run pre-commit hooks-xgit-time-keeper: git time-keeper stop git->>hooks: git hook run post-commit hooks-)+git-time-keeper: git time-keeper start Dev->>git: git commit git->>hooks: git hook run pre-commit hooks-)git-time-keeper: git time-keeper stop git-time-keeper-->-hooks: timer stopped git->>hooks: git hook run post-commit hooks-xgit-time-keeper: git time-keeper start
When the countdown is missed
sequenceDiagram actor Dev participant git participant hooks participant git-time-keeper Dev->>git: git commit git->>hooks: git hook run pre-commit hooks-xgit-time-keeper: git time-keeper stop git->>hooks: git hook run post-commit hooks-)+git-time-keeper: git time-keeper start git-time-keeper-)git-time-keeper: time limit passed git-time-keeper-)-git: git restore .
To see all available flags and options
git-time-keeper --help # dash between `git` and `time-keeper` is only needed for --help
Usage
git-time-keeper --help
Usage: git-time-keeper [OPTIONS]
Options:
-h, --help Print help
-V, --version Print version
Any contributions (feedback, bug report, merge request ...) are welcome
https://gitlab.com/pinage404/git-gamble
Possible states
stateDiagram state "Timer is running" as running state "git restore ." as clean [*] --> running : start running --> [*] : stop running --> clean : time limit passed clean --> [*] running --> running : start [*] --> [*] : stop
Limitation
Unix compatible only (Linux / Mac OS X) : need sh
and kill
Slides why
You can watch the slides about why baby steps are important
Backlog
- when revert ->
git clean
#3 git workspace
supportgit update-ref
should contain an unique identifier to the workspace- branche name ?
- folder path ?
- gamble hooks
- branch based developement
git commit --fixup
git rebase --autosquash
- optional hook to revert if not gambled in a delay
git-time-keeper
- document
- package
- distribute
- branch based developement
- like git, flags & options & arguments should be retrieved from CLI or environment variable or config's file
- re-use
git config
to store in file ? - repository level config using direnv and environment variable ?
- re-use
- stash instead of revert ?
- shell completion
- in the package ?
- Cargo
- AppImage
- Chocolatey
- for
git gamble
not onlygit-gamble
- in the package ?
- https://docs.gitlab.com/ee/ci/runners/saas/macos_saas_runner.html
- https://gitlab.com/gitlab-org/security-products/analyzers
- https://gitlab.com/gitlab-org/security-products/ci-templates
- https://medium.com/@tdeniffel/tcr-variants-test-commit-revert-bf6bd84b17d3
- https://svgfilters.com/
- https://github.com/sourcefrog/cargo-mutants
- https://github.com/llogiq/mutagen
Distribution / publishing backlog
- OS distribution
- Linux
- RPM
cargo-rpm
nix bundle
- make AppImage updatable
- bintray-zsync|pinage404|git-gamble-AppImages|git-gamble|git-gamble-_latestVersion-x86_64.AppImage.zsync
- SnapCraft ?
- FlatPak ?
fpm
: tool that help to generate to several packages- document AppImage with firejail ?
- document AppImage with bubblewrap ?
- Open Build Service seems to be a service that build for every Linux targets
- it can be use
- thougth REST
- badly documented
- with
ocs
a CLI who seems to be a VCS like SVN (commit = commit + push)- who use the REST API under the hood
- thougth REST
- it can be use
- RPM
- Mac OS X
- experiment GitLab Runner on Mac OS X
- run tests
- precompile
- experiment GitLab Runner on Mac OS X
- try to distribute OS less binaries
- Container Image (Docker) ?
- Awesome Rust Deployment
- Awesome Rust Platform Specific
- Linux
- permanent URL to download latest version
- symlinks to URL containing the version name ?
- using GitLab Pages ?
- versioned Homebrew Formula
- Use Cargo-Release to bump version
- how to update sha256 in the versioned file ?
CheckList
- package in local
- package in CI
- upload
- make public available
- complete how to install
- manual test
- update backlog
Technical improvement opportunities
- licence check
- cargo license
- cargo deny
- smaller binary
- cargo bloat
- cargo deps
- refactor to iterate over
Shell
enum
's values instead of having an hard-coded array