#tdd #test #unit-testing #git #tcr

app git-gamble

blend TCR + TDD to make sure to develop the right thing, babystep by babystep

36 releases (10 stable)

2.5.0 Jul 3, 2022
2.3.0 Oct 23, 2021
1.3.0 Mar 12, 2021
1.1.0 May 25, 2020
0.4.0 Mar 31, 2020

#70 in Testing

Download history 11/week @ 2022-11-22 19/week @ 2022-11-29 16/week @ 2022-12-06 7/week @ 2022-12-13 46/week @ 2022-12-20 7/week @ 2022-12-27 8/week @ 2023-01-03 15/week @ 2023-01-10 7/week @ 2023-01-17 8/week @ 2023-01-24 6/week @ 2023-01-31 40/week @ 2023-02-07 89/week @ 2023-02-14 21/week @ 2023-02-21 1/week @ 2023-02-28 2/week @ 2023-03-07

113 downloads per month

ISC license

45KB
418 lines

git-gamble's logo

Git-Gamble

Crate available on Crates.io AppImage available on GitLab Debian available on GitLab

dependency status pipeline status coverage report AppVeyor for Homebrew status

License ISC Contributor Covenant

Blend TCR (test && commit || revert) + TDD (Test Driven Development) to make sure to develop the right thing, babystep by babystep

Original idea by Xavier Detant

Theory

TCR

TCR (test && commit || revert) is cool! It encourages doing baby steps, reducing the waste when we are wrong

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
    });
    

TDD

TDD (Test Driven Development) is cool! It makes sure we develop the right thing, step by step

TCRDD

TCRDD = TCR + TDD

TCRDD blends the constraints of the two methods to benefit from their advantages

Therefore, TCRDD makes sure we develop the right thing, step by step, and we are encouraged to do so by baby steps, reducing the waste when we are wrong

@startuml
skinparam ArrowColor black

start
repeat
	partition "red" #Coral {
		repeat
			:Write a test]
			:Gamble that the tests fail/
			if (Actually run tests) then (Fail)
				-[#Red]->
				:Commit;
				break
			else (Pass)
				-[#Green]->
				:Revert;
			endif
		repeat while (Write another test)
	}
	partition "green" #Lime {
		repeat
			:Write the minimum code]
			:Gamble that the tests pass/
			if (Actually run tests) then (Pass)
				-[#Green]->
				:Commit;
				break
			else (Fail)
				-[#Red]->
				:Revert;
			endif
		repeat while (Try something else)
	}
	partition "refactor" #668cff {
		repeat
			repeat
				:Write code
				without changing the behavior]
				:Gamble that the tests pass/
				if (Actually run tests) then (Pass)
					-[#Green]->
					:Commit;
					break
				else (Fail)
					-[#Tomato]->
					:Revert;
				endif
			repeat while (Change something else)
		repeat while (Another things to refactor ?)
	}
repeat while (Another feature to add ?)
stop
@enduml

If the above diagram is missing, you can see it on GitLab

git-gamble is a tool that helps to use the TCRDD method

How to install

Requirements

git-gamble doesn't repackage git, it uses the one installed on your system

You have to install git manually if you install git-gamble using :

  • AppImage
  • Debian
  • Cargo

Other installation methods include git as a dependency

Make sure it is available in your $PATH, you can check it with this command

git --help

Installation methods

Installations are currently not really convenient, contributions are welcome, feel free to add package to your prefered packages repository

AppImage

  1. Download the latest version

    curl --location "https://gitlab.com/api/v4/projects/pinage404%2Fgit-gamble/packages/generic/git-gamble-AppImage/2.5.0/git-gamble-v2.5.0-x86_64.AppImage" --output git-gamble-v2.5.0-x86_64.AppImage
    
  2. Make it executable

    chmod +x git-gamble-v2.5.0-x86_64.AppImage
    
  3. Put it your $PATH

    # for example
    mkdir -p ~/.local/bin
    ln git-gamble-v2.5.0-x86_64.AppImage ~/.local/bin/git-gamble
    export PATH+=":~/.local/bin"
    

Debian

  1. Go to the package registry page

  2. Go to the latest version of git-gamble-debian

  3. Download the latest version git-gamble_2.5.0_amd64.deb

  4. 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

Mac OS X / Homebrew

Install 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

Windows / Chocolatey

Install Chocolatey

  1. Go to the package registry page

  2. Go to the latest version of git-gamble.portable

  3. Download the latest version git-gamble.portable.2.5.0.nupkg

  4. Install package

    Follow GitLab's documentation and Chocolatey's documentation

    choco install ./git-gamble.portable.2.5.0.nupkg
    

Nix / NixOS

Installation can be done at different levels, see below

It can be done with nix flake or with legacy way, in this case you will have to run command several times to change the sha256 and cargoSha256 by the given one by Nix

Nix 2.4 or higher is required

Nix Flake

Use without installing

nix run gitlab:pinage404/git-gamble -- --help

To install it, see usage example

Project level

In shell.nix

{ pkgs ? import <nixpkgs> {} }:

let
  git-gamble-derivation = pkgs.fetchurl {
    url = "https://gitlab.com/pinage404/git-gamble/-/raw/main/packaging/nix/git-gamble/default.nix";
    sha256 = "0000000000000000000000000000000000000000000000000000";
  };
  git-gamble = pkgs.callPackage git-gamble-derivation {
    version = "2.5.0";
    sha256 = "1111111111111111111111111111111111111111111111111111";
    cargoSha256 = "0000000000000000000000000000000000000000000000000000";
  };
in
pkgs.mkShell {
  buildInputs = [
    git-gamble

    # others dependencies here
    pkgs.nodejs
  ];
}

Then run this command

nix-shell
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
Home-Manager / user level

Install Home Manager

In ~/.config/nixpkgs/home.nix

{ pkgs, ... }:

let
  git-gamble-derivation = pkgs.fetchurl {
    url = "https://gitlab.com/pinage404/git-gamble/-/raw/main/packaging/nix/git-gamble/default.nix";
    sha256 = "0000000000000000000000000000000000000000000000000000";
  };
  git-gamble = pkgs.callPackage git-gamble-derivation {
    version = "2.5.0";
    sha256 = "1111111111111111111111111111111111111111111111111111";
    cargoSha256 = "0000000000000000000000000000000000000000000000000000";
  };
in
{
  home.packages = [
    git-gamble

    # others dependencies here
    pkgs.gitAndTools.git-absorb
  ];
}

Then run this command

home-manager switch
NixOS / system level

In /etc/nixos/configuration.nix

{ pkgs, ... }:

let
  git-gamble-derivation = pkgs.fetchurl {
    url = "https://gitlab.com/pinage404/git-gamble/-/raw/main/packaging/nix/git-gamble/default.nix";
    sha256 = "0000000000000000000000000000000000000000000000000000";
  };
  git-gamble = pkgs.callPackage git-gamble-derivation {
    version = "2.5.0";
    sha256 = "1111111111111111111111111111111111111111111111111111";
    cargoSha256 = "0000000000000000000000000000000000000000000000000000";
  };
in
{
  environment.systemPackages = [
    git-gamble

    # others dependencies here
    pkgs.bat
  ];

  # This value determines the NixOS release with which your system is to be compatible, in order to avoid breaking some software such as database servers
  # You should change this only after NixOS release notes say you should
  system.stateVersion = "20.09";
}

Then run this command

nixos-rebuild switch

Cargo

Install Cargo

cargo install git-gamble

Add ~/.cargo/bin to your $PATH

Fish:

set --export --append PATH ~/.cargo/bin

Bash / ZSH:

export PATH=$PATH:~/.cargo/bin

Download the binary

Only for Linux and Windows x86_64

  1. Download the binary on the release page
  2. Put it in your $PATH

Check the installation

Check if all have been well settled

git gamble

If it has been well settled, it should output this :

error: The following required arguments were not provided:
    <--pass|--fail>
    <TEST_COMMAND>...

USAGE:
    git-gamble [OPTIONS] <--pass|--fail> [--] <TEST_COMMAND>...
    git-gamble [OPTIONS] <SUBCOMMAND>

For more information try --help

If it has been badly settled, it should output this :

git : 'gamble' is not a git command. See 'git --help'.

How to use

To see all available flags and options

git-gamble --help # dash between `git` and `gamble` is only needed for --help
  1. Write a failing test in your codebase, then :

    git gamble --fail -- $YOUR_TEST_COMMAND
    
  2. Write the minimum code to make tests pass, then :

    git gamble --pass -- $YOUR_TEST_COMMAND
    
  3. Refactor your code, then :

    git gamble --pass -- $YOUR_TEST_COMMAND
    

It's a bit tedious to always repeat the test command

So you can set an environment variable with the test command to avoid repeating it all the time

export GAMBLE_TEST_COMMAND="cargo test"
git gamble --pass

Test command must exit with a 0 status when there are 0 failing tests, anything else is considered as a failure

For more detailed example, this the demo

asciicast

Usage

git-gamble --help

git-gamble 2.5.0
Blend TCR (`test && commit || revert`) + TDD (Test Driven Development) to make sure to develop
the right thing, babystep by babystep

USAGE:
    git-gamble [OPTIONS] <--pass|--fail> [--] <TEST_COMMAND>...
    git-gamble [OPTIONS] <SUBCOMMAND>

ARGS:
    <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]

    -C, --repository-path <REPOSITORY_PATH>
            Repository path [default: .]

    -e, --edit
            Open editor to edit commit's message

        --fixup <FIXUP>
            Fixes up commit

    -h, --help
            Print help information

    -m, --message <MESSAGE>
            Commit's message [default: ]

    -n, --dry-run
            Do not make any changes

        --no-verify
            Do not run git hooks

        --squash <SQUASH>
            Construct a commit message for use with `rebase --autosquash`

    -V, --version
            Print version information

SUBCOMMANDS:
    generate-shell-completions    
    help                          Print this message or the help of the given subcommand(s)

Any contributions (feedback, bug report, merge request ...) are welcome
https://gitlab.com/pinage404/git-gamble

Shells completions

To manually generate shell completions you can use this command

git gamble generate-shell-completions --help

git-gamble-generate-shell-completions 

USAGE:
    git-gamble generate-shell-completions <SHELL>

ARGS:
    <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 information

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> is pass or fail
  • <ACTUAL> is pass or fail

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
  • 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.sample is specially adapted to near real-time collaboration
  • post-gamble is a simple assistant that displays tips based on the result of the gamble

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;

When to use it ?

Backlog

  • when revert -> git clean #3
  • git workspace support
    • git 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
  • 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 ?
  • stash instead of revert ?
  • shell completion
    • in the package ?
      • Cargo
      • AppImage
      • Chocolatey
    • for git gamble not only git-gamble

Distribution / publishing backlog

Adding package to the X packages repository

Where the X packages 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

CheckList

  • package in local
  • package in CI
  • upload
  • make public available
  • complete how to install
  • manual test
  • update backlog

Technical improvement opportunities

Reinvent the wheel

Why reinvent the wheel?

This script already works well

Because i would like to learn Rust ¯\_()_/¯

Contributing

Contributor Covenant

Any contributions (feedback, bug report, merge request ...) are welcome

Respect the code of conduct

Follow Keep a Changelog

Development

Setup

To contribute with merge request

Gitpod

Open in Gitpod

Simple

Install Direnv

Install Nix

Let direnv automagically set up the environment by executing the following command in the project directory

direnv 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

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

Deployment

Just run cargo release (in a wide terminal, in order to have --help not truncated in the usage section)

cargo release

Dependencies

~3.5–9MB
~179K SLoC