Skip to content

Commit

Permalink
Merge pull request #1 from roguh/2021.10.31_fix_cicd_and_lint
Browse files Browse the repository at this point in the history
Add unit tests, other changes
  • Loading branch information
roguh authored Nov 1, 2021
2 parents e29b1b5 + 91b4795 commit 30dd887
Show file tree
Hide file tree
Showing 14 changed files with 351 additions and 33 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/on-pr-to-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ name: "On PR or Push to main: Test code"
branches: [main]

jobs:
integration-tests:
unit-tests:

runs-on: ubuntu-20.04

steps:
- uses: actions/checkout@v2

- name: Install dependencies
run: sudo make setup-cicd
run: sudo make setup-cicd-unit-tests

- name: Integration tests on all supported shells
run: make test-all-on-linux
- name: Unit tests on all supported shells
run: make unit-test-all-on-linux

code-check:

Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
test-results*
.test-pass-count
coverage/
tests/shellspec/
28 changes: 21 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
LINUX_SHELLS=dash bash zsh
STRICT_SHELLS=yash ksh
MACOS_SHELLS=bash zsh
SHELLSCRIPTS=gp
ALL_SHELLSCRIPTS=${SHELLSCRIPTS} tests/bash-3.1 test-install.sh $(shell find tests -iname \*.sh)
ALL_SHELLSCRIPTS=${SHELLSCRIPTS} tests/bash-3.1 $(shell ls tests/*.sh)
GITHUB_ACTIONS_FILES=.github/workflows/on-pr-to-main.yml

setup-cicd:
setup-cicd-unit-tests:
apt-get update -y
apt-get install -y shellcheck $(LINUX_SHELLS) $(STRICT_SHELLS)
apt-get install -y $(LINUX_SHELLS) $(STRICT_SHELLS)
make download-shellspec

download-shellspec:
git clone --depth 1 https://github.com/shellspec/shellspec.git tests/shellspec

build-readme:
./utils/generate_readme.py ./README.template.md > ./README.md
Expand Down Expand Up @@ -39,18 +44,27 @@ check-github-actions:
yamllint $(GITHUB_ACTIONS_FILES)

test-on-linux:
./tests/test-all-shells.sh $(LINUX_SHELLS) ./tests/bash-3.1
./tests/test-integration-all-shells.sh $(LINUX_SHELLS) ./tests/bash-3.1

test-on-strict-posix-shells:
./tests/test-all-shells.sh $(STRICT_SHELLS)
./tests/test-integration-all-shells.sh $(STRICT_SHELLS)

test-all-on-linux:
# If this fails, check the tests/test-results.*.txt files
./tests/test-all-shells.sh $(LINUX_SHELLS) $(STRICT_SHELLS) ./tests/bash-3.1
./tests/test-integration-all-shells.sh $(LINUX_SHELLS) $(STRICT_SHELLS) ./tests/bash-3.1

test-on-macos:
# TODO add other shells?
./tests/test-all-shells.sh bash zsh
./tests/test-integration-all-shells.sh $(MACOS_SHELLS)

unit-test-on-linux:
./tests/test-unit-all-shells.sh $(LINUX_SHELLS)

unit-test-all-on-linux:
./tests/test-unit-all-shells.sh $(LINUX_SHELLS) $(STRICT_SHELLS)

unit-test-on-macos:
./tests/test-unit-all-shells.sh $(MACOS_SHELLS)

line-count:
cloc ${SHELLSCRIPTS}
Expand Down
27 changes: 24 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,35 @@ cd gp
make install-to-user
```

## Testing
## Unit Testing

### Linux: Running tests for many shells at once

```
make unit-test-on-linux
```

To include stricter POSIX shells:

```
make unit-test-all-on-linux
```

### Bash: Running tests for many shells at once

```
make unit-test-on-macos
```

## Integration Testing

Testing is a semi-manual process.
Make sure you have permission to push new branches to the remote repository.

If the test script fails, the tests have failed.
Also read the output to determine if `gp` is behaving correctly.

Note the `test-all-shells.sh` script runs the `test-integration.sh` script using the test shell itself.
Note the `test-integration-all-shells.sh` script runs the `test-integration.sh` script using the test shell itself.

### Linux: Running tests for many shells at once

Expand Down Expand Up @@ -145,6 +165,7 @@ make check
- To demonstrate how I would deploy code. Features:
- Linting and other automated checks.
- Thorough tests.
This repo has many integration tests and a way to run them on many different platforms.
- Integration tests and a way to run them on many different platforms.
- Unit tests that run on many shells, even on Bash 2.03
- Good documentation.
- GitHub Actions for running tests and code checks.
27 changes: 24 additions & 3 deletions README.template.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,35 @@ cd gp
make install-to-user
```

## Testing
## Unit Testing

### Linux: Running tests for many shells at once

```
make unit-test-on-linux
```

To include stricter POSIX shells:

```
make unit-test-all-on-linux
```

### Bash: Running tests for many shells at once

```
make unit-test-on-macos
```

## Integration Testing

Testing is a semi-manual process.
Make sure you have permission to push new branches to the remote repository.

If the test script fails, the tests have failed.
Also read the output to determine if `gp` is behaving correctly.

Note the `test-all-shells.sh` script runs the `test-integration.sh` script using the test shell itself.
Note the `test-integration-all-shells.sh` script runs the `test-integration.sh` script using the test shell itself.

### Linux: Running tests for many shells at once

Expand Down Expand Up @@ -130,6 +150,7 @@ make check
- To demonstrate how I would deploy code. Features:
- Linting and other automated checks.
- Thorough tests.
This repo has many integration tests and a way to run them on many different platforms.
- Integration tests and a way to run them on many different platforms.
- Unit tests that run on many shells, even on Bash 2.03
- Good documentation.
- GitHub Actions for running tests and code checks.
38 changes: 22 additions & 16 deletions gp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ usage() {
# Print usage/help
echo "gp: Pull, push, push new branch. Version $VERSION"
echo
echo - If there are changes in the remote branch, pull
echo - If there are changes in the local branch, push
echo - If there is no remote branch, prompt to push a new branch.
echo "- If there are changes in the remote branch, pull"
echo "- If there are changes in the local branch, push"
echo "- If there is no remote branch, prompt to push a new branch."
echo " Skip prompt with gp -f"
echo - If the branches have diverged, do nothing.
echo "- If the branches have diverged, do nothing."
echo " Force push with gp -f"
echo
echo "USAGE: gp [-f|-v|-h|--version]"
Expand All @@ -28,13 +28,22 @@ usage() {
echo " --version Show program version."
}

log() {
echo "$@" >&2
}

verbose() {
# Call to print verbose output
if [ "$VERBOSE" = true ]; then
echo gp: "$@"
log "gp:" "$@"
fi
}

run() {
log "+ " "$@"
"$@"
}

##### Parse arguments
if [ "$#" -gt 1 ]; then
usage
Expand All @@ -61,13 +70,14 @@ else
fi

##### Check if in git repo
git rev-parse --git-dir
if ! git rev-parse --git-dir > /dev/null 2>&1; then
echo fatal: not in a git repo >&2
exit 1
fi

##### Get git status
git remote update
run git remote update

set +e
UPSTREAM='@{u}'
Expand Down Expand Up @@ -106,24 +116,20 @@ if [ "$REMOTE_STATUS" = "No remote" ]; then
exit 1
fi
fi
set -x
git push --set-upstream origin "$(git branch --show-current)"
run git push --set-upstream origin "$(git branch --show-current)"
elif [ "$REMOTE_STATUS" = "Need to pull" ]; then
set -x
git pull
run git pull
elif [ "$REMOTE_STATUS" = "Need to push" ]; then
set -x
git push
run git push
elif [ "$REMOTE_STATUS" = "Diverged" ]; then
if [ "$FORCE" = "true" ]; then
verbose FORCE PUSHING
set -x
git push --force
run git push --force
else
verbose Not running any commands
echo "$REMOTE_STATUS"
log "$REMOTE_STATUS"
fi
else
verbose Not running any commands
echo "$REMOTE_STATUS"
log "$REMOTE_STATUS"
fi
96 changes: 96 additions & 0 deletions tests/git_mock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#!/usr/bin/env python3
import argparse
import sys

# define subcommands to mock git behavior:
# DONE if git rev-parse, if in git-repo exit 0 else exit 1
# DONE if git remote update, do nothing
# DONE if rev-parse @, show local_branch
# DONE if rev-parse @{u}, show remote_branch
# DONE if merge-parse @{u}, show base_branch
# DONE if branch --show-current, print local_branch_name
# DONE if push or pull, print all args

# unit test: define git() as ./this.py <CONFIG ARGS> "$@"


def rev_parse(args):
if args.git_dir:
sys.exit(1 if args.not_in_a_git_repo else 0)
elif args.rev == "@":
print(args.local_branch)
elif args.rev == "@{u}":
print(args.remote_branch)
else:
raise NotImplementedError(f"rev={args.rev}")


def remote(_):
# Do nothing but successfully exit
pass


def merge_base(args):
if args.rev == "@" and args.upstream_rev == "@{u}":
print(args.base_branch)
else:
raise NotImplementedError(f"rev={args.rev} upstream_rev={args.upstream_rev}")


def branch(args):
if args.show_current:
print(args.local_branch_name)
else:
raise NotImplementedError("show_current=False")


def push(args):
pass


def pull(args):
pass


def main():
parser = argparse.ArgumentParser(description="Mocks git subcommands used by gp")

parser.add_argument("--not-in-a-git-repo", action="store_true")
parser.add_argument("--local-branch", default=None)
parser.add_argument("--remote-branch", default=None)
parser.add_argument("--base-branch", default=None)
parser.add_argument("--local-branch-name", default=None)

subparsers = parser.add_subparsers()

rev_parse_parser = subparsers.add_parser("rev-parse")
rev_parse_parser.add_argument("rev", nargs="?")
rev_parse_parser.add_argument("--git-dir", action="store_true")
rev_parse_parser.set_defaults(func=rev_parse)

remote_parser = subparsers.add_parser("remote")
remote_parser.add_argument("remote_update_args", nargs="*")
remote_parser.set_defaults(func=remote)

merge_base_parser = subparsers.add_parser("merge-base")
merge_base_parser.add_argument("rev", type=str)
merge_base_parser.add_argument("upstream_rev", type=str)
merge_base_parser.set_defaults(func=merge_base)

branch_parser = subparsers.add_parser("branch")
branch_parser.add_argument("--show-current", action="store_true", required=True)
branch_parser.set_defaults(func=branch)

push_parser = subparsers.add_parser("push")
push_parser.set_defaults(func=push)

pull_parser = subparsers.add_parser("pull")
pull_parser.set_defaults(func=pull)

# Ignore unknown arguments
args, _ = parser.parse_known_args()
args.func(args)


if __name__ == "__main__":
main()
File renamed without changes.
4 changes: 4 additions & 0 deletions tests/test-integration.sh
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ it handles unrecognized arguments
set +e
set -x
for args in --halp -vf nope '--help too many'; do
# We need to disable the linter warning here because we actually do want
# to pass the $args variable as multiple arguments, not a single argument
# containing spaces.
# shellcheck disable=SC2086
if "$SHELL" gp $args; then
test_echo TEST FAILURE. gp should not have accepted arguments "$args"
exit 1
Expand Down
13 changes: 13 additions & 0 deletions tests/test-unit-all-shells.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh
if [ "$#" = 0 ]; then
echo "USAGE: $0 [SHELLS...]"
echo
echo "SHELLS can be a list of any installed shells"
echo "Examples: bash, zsh, dash, yash"
exit 1
fi

set -e
for shell in "$@"; do
"$(dirname "$0")/test-unit.sh" "$shell"
done
9 changes: 9 additions & 0 deletions tests/test-unit.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/bin/sh
if [ "$#" != 1 ]; then
echo "USAGE: $0 [SHELL]"
echo
echo "SHELL can be any installed shells"
echo "Examples: bash, zsh, dash, yash"
exit 1
fi
"$(dirname "$0")/shellspec/shellspec" --shell "$1" --helperdir tests/unit_tests/spec --sandbox tests/unit_tests/gp_spec.sh
Loading

0 comments on commit 30dd887

Please sign in to comment.