Skip to content

Commit 8dbcc79

Browse files
authored
Fixes/v0.0.2 + Integration tests (#2)
* Fix the behavior when no command is there to undo or to undoundo * minor updates on Makefile. lets not forget our PHONYs * install process fixed: better shell detect + better permissions handling * install process: prettier logs * install process: prettier logs for installing binary * install process: cleaner logs * Uninstall process introduced * better install/uninstall scripts. Use a script generator * Update script logic introduced + fixes on Install & Uninstall logic * Let binary do `self` commands: Go -> shell * rebuild * Refactor & Fixes: on Versioning + Self Update + Self Uninstall * initial CI * skip tests that we are not ready yet * setup Git in CI * fix tests for CI * debug CI * WIP: integration tests * updates & fixes * fix integration tests * make linter happier
1 parent 71b7621 commit 8dbcc79

30 files changed

+2487
-151
lines changed

.github/workflows/ci.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
jobs:
10+
test:
11+
runs-on: ubuntu-latest
12+
13+
strategy:
14+
matrix:
15+
go-version: [1.24]
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Set up Go
21+
uses: actions/setup-go@v5
22+
with:
23+
go-version: ${{ matrix.go-version }}
24+
25+
- name: Configure Git
26+
run: |
27+
git config --global user.email "ci@amberpixels.io"
28+
git config --global user.name "GitHub CI"
29+
git config --global init.defaultBranch main
30+
31+
- name: Cache Go modules
32+
uses: actions/cache@v4
33+
with:
34+
path: |
35+
~/.cache/go-build
36+
~/go/pkg/mod
37+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
38+
restore-keys: |
39+
${{ runner.os }}-go-
40+
41+
- name: Download dependencies
42+
run: go mod download
43+
44+
- name: Verify dependencies
45+
run: go mod verify
46+
47+
- name: Run go vet
48+
run: go vet ./...
49+
50+
- name: Run tests
51+
run: go test -v -count=1 ./...
52+
53+
- name: Debug failing tests (if main tests fail)
54+
if: failure()
55+
run: |
56+
echo "=== Debugging TestUndoLog and TestUndoMerge ==="
57+
go test -v -run "TestGitUndoSuite/(TestUndoLog|TestUndoMerge)" ./internal/app || true
58+
echo "=== Git version and config ==="
59+
git --version
60+
git config --list --show-origin || true
61+
62+
- name: Test build with version info
63+
run: |
64+
TEST_VERSION="v0.0.0-ci-test-$(date +%Y%m%d%H%M%S)"
65+
go build -ldflags "-X main.version=${TEST_VERSION}" -o build/git-undo-versioned ./cmd/git-undo
66+
echo "Built binary with test version: ${TEST_VERSION}"
67+
68+
# Test that the binary outputs the correct version
69+
BINARY_VERSION=$(./build/git-undo-versioned --version 2>/dev/null || echo "version command not found")
70+
echo "Binary reported version: ${BINARY_VERSION}"
71+
72+
# Verify the version matches (allowing for some flexibility in output format)
73+
if echo "${BINARY_VERSION}" | grep -q "${TEST_VERSION}"; then
74+
echo "✅ Version verification successful!"
75+
else
76+
echo "❌ Version verification failed!"
77+
echo "Expected: ${TEST_VERSION}"
78+
echo "Got: ${BINARY_VERSION}"
79+
exit 1
80+
fi

.github/workflows/integration.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Integration Tests
2+
3+
on:
4+
push:
5+
branches: [ main, develop ]
6+
pull_request:
7+
branches: [ main, develop ]
8+
9+
jobs:
10+
integration:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout code
15+
uses: actions/checkout@v4
16+
17+
- name: Set up Docker Buildx
18+
uses: docker/setup-buildx-action@v3
19+
20+
- name: Determine integration test mode
21+
id: test-mode
22+
run: |
23+
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
24+
echo "mode=production" >> $GITHUB_OUTPUT
25+
echo "dockerfile=scripts/integration/Dockerfile" >> $GITHUB_OUTPUT
26+
echo "description=real user experience (published releases)" >> $GITHUB_OUTPUT
27+
else
28+
echo "mode=development" >> $GITHUB_OUTPUT
29+
echo "dockerfile=scripts/integration/Dockerfile.dev" >> $GITHUB_OUTPUT
30+
echo "description=current branch changes" >> $GITHUB_OUTPUT
31+
fi
32+
33+
- name: Build and run integration tests
34+
run: |
35+
echo "🧪 Integration test mode: ${{ steps.test-mode.outputs.mode }}"
36+
echo "📝 Testing: ${{ steps.test-mode.outputs.description }}"
37+
echo "🐳 Using dockerfile: ${{ steps.test-mode.outputs.dockerfile }}"
38+
echo ""
39+
40+
echo "Building integration test image..."
41+
docker build -f "${{ steps.test-mode.outputs.dockerfile }}" -t git-undo-integration:ci .
42+
43+
echo "Running integration tests..."
44+
docker run --rm git-undo-integration:ci
45+
46+
- name: Clean up Docker images
47+
if: always()
48+
run: |
49+
docker rmi git-undo-integration:ci || true

Makefile

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,49 +10,101 @@ MAIN_FILE := $(CMD_DIR)/main.go
1010
BINARY_NAME := git-undo
1111
INSTALL_DIR := $(shell go env GOPATH)/bin
1212

13+
# Build version with git information
14+
VERSION_TAG := $(shell git describe --tags --abbrev=0 2>/dev/null || echo "v0.0.0")
15+
VERSION_BRANCH := $(shell git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "unknown")
16+
VERSION_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown")
17+
VERSION_DATE := $(shell date +%Y%m%d%H%M%S)
18+
19+
# Conditionally include branch in version string
20+
ifeq ($(VERSION_BRANCH),main)
21+
VERSION := $(VERSION_TAG)-$(VERSION_DATE)-$(VERSION_COMMIT)
22+
else ifeq ($(VERSION_BRANCH),unknown)
23+
VERSION := $(VERSION_TAG)-$(VERSION_DATE)-$(VERSION_COMMIT)
24+
else
25+
VERSION := $(VERSION_TAG)-$(VERSION_DATE)-$(VERSION_COMMIT)-$(VERSION_BRANCH)
26+
endif
27+
1328
# Default target
1429
all: build
1530

1631
# Build the binary
32+
.PHONY: build
1733
build:
1834
@mkdir -p $(BUILD_DIR)
19-
@go build -o $(BUILD_DIR)/$(BINARY_NAME) $(MAIN_FILE)
35+
@go build -ldflags "-X main.version=$(VERSION)" -o $(BUILD_DIR)/$(BINARY_NAME) $(MAIN_FILE)
2036

2137
# Run the binary
38+
.PHONY: run
2239
run: build
2340
./$(BUILD_DIR)/$(BINARY_NAME)
2441

2542
# Run tests
43+
.PHONY: test
2644
test:
2745
@go test -v ./...
2846

47+
# Run integration tests in dev mode (test current changes)
48+
.PHONY: integration-test-dev
49+
integration-test-dev:
50+
@./scripts/run-integration.sh --dev
51+
52+
# Run integration tests in production mode (test real user experience)
53+
.PHONY: integration-test-prod
54+
integration-test-prod:
55+
@./scripts/run-integration.sh --prod
56+
57+
# Run integration tests (alias for dev mode)
58+
.PHONY: integration-test
59+
integration-test: integration-test-dev
60+
61+
# Run all tests (unit + integration dev)
62+
.PHONY: test-all
63+
test-all: test integration-test-dev
64+
2965
# Tidy: format and vet the code
66+
.PHONY: tidy
3067
tidy:
3168
@go fmt $(PKGS)
3269
@go vet $(PKGS)
3370
@go mod tidy
3471

3572
# Install golangci-lint only if it's not already installed
73+
.PHONY: lint-install
3674
lint-install:
3775
@if ! [ -x "$(GOLANGCI_LINT)" ]; then \
3876
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest; \
3977
fi
4078

4179
# Lint the code using golangci-lint
4280
# todo reuse var if possible
81+
.PHONY: lint
4382
lint: lint-install
4483
$(shell which golangci-lint) run
4584

46-
# Install the binary globally with aliases
85+
# Install the binary globally with custom version info
86+
.PHONY: binary-install
4787
binary-install:
48-
@go install $(CMD_DIR)
88+
@echo "Installing git-undo with version: $(VERSION)"
89+
@go install -ldflags "-X main.version=$(VERSION)" $(CMD_DIR)
4990

91+
.PHONY: install
5092
install:
5193
./install.sh
5294

95+
.PHONY: uninstall
96+
uninstall:
97+
./uninstall.sh
98+
5399
# Uninstall the binary and remove the alias
100+
.PHONY: binary-uninstall
54101
binary-uninstall:
55102
rm -f $(INSTALL_DIR)/$(BINARY_NAME)
56103

57-
# Phony targets
58-
.PHONY: all build run test tidy lint-install lint binary-install binary-uninstall install
104+
.PHONY: buildscripts
105+
buildscripts:
106+
@./scripts/build.sh
107+
108+
.PHONY: update
109+
update:
110+
./update.sh

README.md

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# git-undo ⏪✨
22

3-
*A universal Ctrl + Z for Git commands.* 🔄
3+
*A universal "Ctrl + Z" for Git commands.* 🔄
44

55
`git-undo` tracks every mutating Git command you run and can roll it back with a single `git undo` 🚀
66
No reflog spelunking, no cherry‑picks—just instant reversal. ⚡
@@ -12,6 +12,7 @@ No reflog spelunking, no cherry‑picks—just instant reversal. ⚡
1212
- [cURL one‑liner](#curl-one-liner-preferred)
1313
- [Manual clone](#manual-clone)
1414
- [Shell‑hook integration](#shell-hook-integration)
15+
- [Using go install](#using-go-install)
1516
4. [Quick Start](#quick-start)
1617
5. [Usage](#usage)
1718
6. [Supported Git Commands](#supported-git-commands)
@@ -61,6 +62,12 @@ and appends a `source` line to your `.zshrc`.
6162
- The installer drops [`scripts/git-undo-hook.bash`](scripts/git-undo-hook.bash) into `~/.config/git-undo/`
6263
and appends a `source` line to your `.bashrc` / `.bash_profile` (depending on your OS).
6364

65+
### Using go install
66+
67+
```bash
68+
go install github.com/amberpixels/git-undo/cmd/git-undo@latest
69+
```
70+
6471
## Quick Start
6572
```bash
6673
git add .
@@ -83,6 +90,33 @@ git undo undo # redo last undo (like Ctrl+Shift+Z)
8390
| `git undo --dry-run` | Print what *would* be executed, do nothing |
8491
| `git undo --log` | Dump your logged command history |
8592

93+
### Version Information
94+
95+
Check the version of git-undo:
96+
97+
```bash
98+
git undo version # Standard version command
99+
git undo self version # The same (just a consistent way for other `git undo self` commands)
100+
```
101+
102+
The version detection works in the following priority:
103+
1. Git tag version (if in a git repository with tags)
104+
2. Build-time version (set during compilation)
105+
3. "unknown" (fallback)
106+
107+
### Self-Management Commands
108+
109+
Update git-undo to the latest version:
110+
111+
```bash
112+
git undo self update
113+
```
114+
115+
Uninstall git-undo:
116+
117+
```bash
118+
git undo self uninstall
119+
```
86120

87121
## Supported Git Commands
88122
* `commit`
@@ -114,6 +148,30 @@ make lint # golangci‑lint
114148
make build # compile to ./build/git-undo
115149
make install # installs Go binary and adds zsh hook
116150
```
151+
152+
## Development
153+
154+
### Building with Version Information
155+
156+
To build git-undo with a specific version:
157+
158+
```bash
159+
# Using git describe
160+
VERSION=$(git describe --tags --always 2>/dev/null || echo "dev")
161+
go build -ldflags "-X main.version=$VERSION" ./cmd/git-undo
162+
163+
# Or manually specify version
164+
go build -ldflags "-X main.version=v1.2.3" ./cmd/git-undo
165+
```
166+
167+
### Testing
168+
169+
Run the test suite:
170+
171+
```bash
172+
go test ./...
173+
```
174+
117175
## Contributing & Feedback
118176
Spotted a bug or missing undo case?
119177
Opening an issue or PR makes the tool better for everyone.

cmd/git-undo/main.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,14 @@ import (
44
"fmt"
55
"os"
66

7+
gitundo "github.com/amberpixels/git-undo"
78
"github.com/amberpixels/git-undo/internal/app"
89
)
910

11+
// Build-time version information
12+
// This can be set during build using: go build -ldflags "-X main.version=v1.0.0".
13+
var version = "dev"
14+
1015
func main() {
1116
var verbose, dryRun bool
1217
for _, arg := range os.Args[1:] {
@@ -18,7 +23,10 @@ func main() {
1823
}
1924
}
2025

21-
application := app.New(".", verbose, dryRun)
26+
application := app.New(".", version, verbose, dryRun)
27+
// Set embedded scripts from root package
28+
app.SetEmbeddedScripts(application, gitundo.GetUpdateScript(), gitundo.GetUninstallScript())
29+
2230
if err := application.Run(os.Args[1:]); err != nil {
2331
_, _ = fmt.Fprintln(os.Stderr, redColor+"git-undo ❌: "+grayColor+err.Error()+resetColor)
2432
os.Exit(1)

embed.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package gitundo
2+
3+
import (
4+
_ "embed"
5+
)
6+
7+
//go:embed update.sh
8+
var updateScript string
9+
10+
//go:embed uninstall.sh
11+
var uninstallScript string
12+
13+
// GetUpdateScript returns the embedded update script content.
14+
func GetUpdateScript() string {
15+
return updateScript
16+
}
17+
18+
// GetUninstallScript returns the embedded uninstall script content.
19+
func GetUninstallScript() string {
20+
return uninstallScript
21+
}

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ module github.com/amberpixels/git-undo
22

33
go 1.24
44

5+
toolchain go1.24.3
6+
57
require (
68
github.com/mattn/go-shellwords v1.0.12
79
github.com/stretchr/testify v1.10.0

0 commit comments

Comments
 (0)