Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ gitbackup
dist/

testdata/**expected

# Integration test secrets
test/.env
1 change: 1 addition & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ func newForgejoClient(gitHostURLParsed *url.URL) *forgejo.Client {
}

gitHostToken = forgejoToken

log.Println("Creating forgejo client", url)
client, err := forgejo.NewClient(url, forgejo.SetToken(forgejoToken), forgejo.SetForgejoVersion(""))
if err != nil {
Expand Down
8 changes: 8 additions & 0 deletions test/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copy this file to test/.env and fill in your tokens.
# See test/INTEGRATION_TESTING.md for setup instructions.

GITHUB_TOKEN=
GITLAB_TOKEN=
BITBUCKET_USERNAME=
BITBUCKET_TOKEN=
FORGEJO_TOKEN=
59 changes: 59 additions & 0 deletions test/INTEGRATION_TESTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Integration Testing

Manual integration test script for verifying gitbackup works end-to-end against real git hosting services before releases.

## Prerequisites

- Go toolchain
- Git
- SSH keys configured for the services you want to test (unless testing HTTPS-only)

## Test Account Setup

Each contributor creates their own test accounts. The script expects a standard set of repos on each service.

### GitHub

1. Create a [personal access token](https://github.com/settings/tokens) with `repo` scope
2. Create two repositories:
- `gitbackup-test-public` (public)
- `gitbackup-test-private` (private)

### GitLab

1. Create a [personal access token](https://gitlab.com/-/user_settings/personal_access_tokens) with `read_api` scope
2. Create two projects:
- `gitbackup-test-public` (public)
- `gitbackup-test-private` (private)

### Bitbucket

1. Create an [API token](https://bitbucket.org/account/settings/app-passwords/) with `read:user:bitbucket`, `read:workspace:bitbucket`, and `read:repository:bitbucket` scopes
2. Create a workspace and two repositories:
- `gitbackup-test-public` (public)
- `gitbackup-test-private` (private)

### Forgejo (Codeberg)

1. Create an [access token](https://codeberg.org/user/settings/applications) with `read:repository` permission
2. Create two repositories:
- `gitbackup-test-public` (public)
- `gitbackup-test-private` (private)

## Environment Setup

```
cp test/.env.example test/.env
```

Fill in your tokens in `test/.env`.

## Running the Tests

From the repository root:

```
bash test/integration-test.sh
```

Any services with missing environment variables will be skipped automatically.
248 changes: 248 additions & 0 deletions test/integration-test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
#!/usr/bin/env bash
set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
BINARY="$REPO_ROOT/gitbackup"

# Load env vars
if [[ -f "$SCRIPT_DIR/.env" ]]; then
set -a
source "$SCRIPT_DIR/.env"
set +a
fi

VERBOSE=false
SERVICES=()

for arg in "$@"; do
case "$arg" in
-v|--verbose) VERBOSE=true ;;
*) SERVICES+=("$arg") ;;
esac
done

if [[ ${#SERVICES[@]} -eq 0 ]]; then
SERVICES=(github gitlab bitbucket forgejo)
fi

# Expected repo names (same across all services)
EXPECTED_REPOS="gitbackup-test-public gitbackup-test-private"

# --- Helpers ---

pass() {
echo " PASS: $1"
RESULTS+=("PASS: $1")
PASSED=$((PASSED + 1))
}

fail() {
echo " FAIL: $1"
RESULTS+=("FAIL: $1")
FAILED=$((FAILED + 1))
}

check_env() {
local service="$1"
shift
for var in "$@"; do
if [[ -z "${!var:-}" ]]; then
echo "Skipping $service: $var is not set"
return 1
fi
done
return 0
}

is_git_repo() {
git -C "$1" rev-parse 2>/dev/null
}

is_bare_repo() {
[[ "$(git -C "$1" rev-parse --is-bare-repository 2>/dev/null)" == "true" ]]
}

# Check that a repo with the given name exists under the backup dir and is a valid git repo
check_repo_exists() {
local backup_dir="$1"
local repo_name="$2"
local dir
dir=$(find "$backup_dir" -type d -name "$repo_name" -maxdepth 4 2>/dev/null | head -1)
[[ -n "$dir" ]] && is_git_repo "$dir"
}

# Check that a bare repo with the given name exists under the backup dir
check_bare_repo_exists() {
local backup_dir="$1"
local repo_name="$2"
local dir
dir=$(find "$backup_dir" -type d -name "${repo_name}.git" -maxdepth 4 2>/dev/null | head -1)
[[ -n "$dir" ]] && is_bare_repo "$dir"
}

run_gitbackup() {
if $VERBOSE; then
$BINARY "$@" 2>&1
else
$BINARY "$@" >/dev/null 2>&1
fi
}

run_service_tests() {
local service="$1"
local label="$2"
local extra_flags="${3:-}"
local tmpdir

echo ""
echo "=== $service ($label) ==="

# Test 1: Fresh clone
tmpdir=$(mktemp -d)
trap "rm -rf $tmpdir" RETURN

echo " Running fresh clone..."
if run_gitbackup -service "$service" -backupdir "$tmpdir" $extra_flags; then
all_found=true
for repo_name in $EXPECTED_REPOS; do
if check_repo_exists "$tmpdir" "$repo_name"; then
echo " Found $repo_name"
else
echo " Missing $repo_name"
all_found=false
fi
done
if $all_found; then
pass "$service ($label): fresh clone"
else
fail "$service ($label): fresh clone — expected repos not found"
fi
else
fail "$service ($label): fresh clone — gitbackup exited with error"
fi

# Test 2: Update (run again into same directory)
echo " Running update..."
if run_gitbackup -service "$service" -backupdir "$tmpdir" $extra_flags; then
all_found=true
for repo_name in $EXPECTED_REPOS; do
if ! check_repo_exists "$tmpdir" "$repo_name"; then
all_found=false
fi
done
if $all_found; then
pass "$service ($label): update"
else
fail "$service ($label): update — repos missing after update"
fi
else
fail "$service ($label): update — gitbackup exited with error"
fi

rm -rf "$tmpdir"

# Test 3: Bare clone
tmpdir=$(mktemp -d)

echo " Running bare clone..."
if run_gitbackup -service "$service" -backupdir "$tmpdir" -bare $extra_flags; then
all_found=true
for repo_name in $EXPECTED_REPOS; do
if check_bare_repo_exists "$tmpdir" "$repo_name"; then
echo " Found ${repo_name}.git (bare)"
else
echo " Missing ${repo_name}.git (bare)"
all_found=false
fi
done
if $all_found; then
pass "$service ($label): bare clone"
else
fail "$service ($label): bare clone — expected bare repos not found"
fi
else
fail "$service ($label): bare clone — gitbackup exited with error"
fi

rm -rf "$tmpdir"

# Test 4: Ignore private
tmpdir=$(mktemp -d)

echo " Running ignore-private clone..."
if run_gitbackup -service "$service" -backupdir "$tmpdir" -ignore-private $extra_flags; then
if check_repo_exists "$tmpdir" "gitbackup-test-public"; then
echo " Found gitbackup-test-public"
else
echo " Missing gitbackup-test-public"
fail "$service ($label): ignore-private — public repo not found"
rm -rf "$tmpdir"
trap - RETURN
return
fi
if check_repo_exists "$tmpdir" "gitbackup-test-private"; then
echo " Found gitbackup-test-private (unexpected)"
fail "$service ($label): ignore-private — private repo should have been skipped"
else
echo " Correctly skipped gitbackup-test-private"
pass "$service ($label): ignore-private"
fi
else
fail "$service ($label): ignore-private — gitbackup exited with error"
fi

rm -rf "$tmpdir"
trap - RETURN
}

# --- Main ---

PASSED=0
FAILED=0
RESULTS=()

echo "Building gitbackup..."
(cd "$REPO_ROOT" && go build -o "$BINARY" .)

for service in "${SERVICES[@]}"; do
case "$service" in
github)
check_env github GITHUB_TOKEN || continue
run_service_tests github "SSH"
run_service_tests github "HTTPS" "-use-https-clone"
;;
gitlab)
check_env gitlab GITLAB_TOKEN || continue
run_service_tests gitlab "SSH" "-gitlab.projectVisibility all -gitlab.projectMembershipType owner"
run_service_tests gitlab "HTTPS" "-gitlab.projectVisibility all -gitlab.projectMembershipType owner -use-https-clone"
;;
bitbucket)
check_env bitbucket BITBUCKET_USERNAME BITBUCKET_TOKEN || continue
run_service_tests bitbucket "SSH"
run_service_tests bitbucket "HTTPS" "-use-https-clone"
;;
forgejo)
check_env forgejo FORGEJO_TOKEN || continue
run_service_tests forgejo "SSH" "-githost.url https://codeberg.org"
run_service_tests forgejo "HTTPS" "-githost.url https://codeberg.org -use-https-clone"
;;
esac
done

# --- Summary (verbose only) ---

if $VERBOSE; then
echo ""
echo "=============================="
echo "Results: $PASSED passed, $FAILED failed"
echo ""
for r in "${RESULTS[@]}"; do
echo " $r"
done
echo "=============================="
fi

if [[ $FAILED -gt 0 ]]; then
exit 1
fi
Loading