Skip to content

Commit f2fd59a

Browse files
feat: add user list and batch delete by prefix with age filtering
Added new commands to list users and batch delete users by username prefix: - `user list`: List all users or search by prefix - `user delete-by-prefix`: Batch delete users with matching prefix Enhanced user cleanup and delete commands with safety features: - Added `--days-old` flag to only delete users created N+ days ago - Default behavior: only delete users created 2+ days ago - Set `--days-old=0` to delete all matching users regardless of age - Added `--dry-run` mode for delete-by-prefix to preview changes Updated components: - internal/cli/cmd.go: Added buildUserListCommand and buildUserDeleteByPrefixCommand - internal/config/config.go: Added DaysOld field to CLIConfig - internal/processor/processor.go: Updated ProcessUserCleanup to support age filtering - pkg/client/client.go: Added ListAllUsers method with pagination support 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
1 parent 4fe7a4c commit f2fd59a

File tree

5 files changed

+497
-8
lines changed

5 files changed

+497
-8
lines changed

CLAUDE.md

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project Overview
6+
7+
This is a GitLab CLI tool built with the official GitLab Go SDK for automating user, group, and project management. The tool uses a layered architecture with clear separation between CLI commands, business logic, and API client operations.
8+
9+
## Build and Development Commands
10+
11+
### Building
12+
```bash
13+
# Build for current platform
14+
make build
15+
16+
# Build for all platforms (Linux, macOS, ARM64/AMD64)
17+
make build-all
18+
19+
# Install to /usr/local/bin
20+
make install
21+
```
22+
23+
### Testing and Quality
24+
```bash
25+
# Run tests
26+
make test
27+
# Or: go test -v -race -coverprofile=coverage.out ./...
28+
29+
# Format code
30+
make fmt
31+
# Or: go fmt ./...
32+
33+
# Run linter (if golangci-lint is installed)
34+
make lint
35+
```
36+
37+
### Running
38+
```bash
39+
# Show help
40+
./bin/gitlab-cli --help
41+
42+
# Create users/groups/projects from config
43+
./bin/gitlab-cli user create -f config.yaml --host https://gitlab.example.com --token <token>
44+
45+
# With output file
46+
./bin/gitlab-cli user create -f config.yaml -o output.yaml
47+
48+
# With custom template
49+
./bin/gitlab-cli user create -f config.yaml -o output.yaml -t template.yaml
50+
51+
# Cleanup users (default: only delete users created 2+ days ago)
52+
./bin/gitlab-cli user cleanup -f config.yaml
53+
./bin/gitlab-cli user cleanup -f config.yaml --days-old 7 # Delete users 7+ days old
54+
./bin/gitlab-cli user cleanup -f config.yaml --days-old 0 # Delete all (ignore date)
55+
56+
# Delete specific users
57+
./bin/gitlab-cli user delete --username user1,user2
58+
59+
# List users by prefix
60+
./bin/gitlab-cli user list --prefix tektoncd
61+
62+
# Delete users by prefix (default: only delete users created 2+ days ago)
63+
./bin/gitlab-cli user delete-by-prefix --prefix tektoncd --dry-run # Preview
64+
./bin/gitlab-cli user delete-by-prefix --prefix tektoncd --days-old 7 # Delete 7+ days old
65+
./bin/gitlab-cli user delete-by-prefix --prefix tektoncd --days-old 0 # Delete all
66+
```
67+
68+
## Architecture
69+
70+
### Layered Structure
71+
72+
The codebase follows a strict layered architecture (top to bottom):
73+
74+
1. **Entry Layer** (`cmd/gitlab-cli/main.go`): Application entry point, minimal logic
75+
2. **Command Layer** (`internal/cli/cmd.go`): Cobra command definitions and orchestration
76+
3. **Business Logic Layer** (`internal/processor/processor.go`): Core resource processing logic
77+
4. **API Client Layer** (`pkg/client/client.go`): GitLab API abstraction
78+
5. **External Service**: GitLab REST API
79+
80+
### Package Visibility
81+
82+
- **`internal/`**: Private to this project only
83+
- `internal/cli`: CLI command builders and flow orchestration
84+
- `internal/config`: Configuration loading and credential management
85+
- `internal/processor`: Business logic for creating/deleting resources
86+
- `internal/template`: Go template rendering for custom output
87+
- `internal/utils`: Utility functions (timestamp generation, visibility conversion)
88+
89+
- **`pkg/`**: Public packages that can be imported by external projects
90+
- `pkg/client`: GitLab API client wrapper (built on official SDK)
91+
- `pkg/types`: Data structure definitions (UserSpec, GroupSpec, ProjectSpec, etc.)
92+
93+
### Key Design Patterns
94+
95+
1. **Dependency Injection**: `ResourceProcessor` receives `GitLabClient` as a field
96+
2. **Idempotent Operations**: `ensure*` methods check existence before creating
97+
3. **Single Responsibility**: Each function does one thing, typically under 50 lines
98+
4. **Builder Pattern**: Commands are built using `build*Command()` functions
99+
100+
### Data Flow
101+
102+
1. User runs CLI command → `cmd/gitlab-cli/main.go`
103+
2. Cobra routes to command handler → `internal/cli/cmd.go`
104+
3. Command handler initializes client and loads config
105+
4. Business logic processes resources → `internal/processor/processor.go`
106+
5. API client makes GitLab API calls → `pkg/client/client.go`
107+
6. Results are collected and optionally saved to YAML/template output
108+
109+
## Important Implementation Details
110+
111+
### Naming Modes
112+
113+
The tool supports two naming modes for resources:
114+
115+
- **`prefix` mode (default)**: Appends timestamp to username/email/group/project paths
116+
- Example: `tektoncd``tektoncd-20251030150000`
117+
- Used for test environments and creating multiple similar resources
118+
- **Important**: Cleanup must use the output file from creation (not config file)
119+
120+
- **`name` mode**: Uses names directly from config file without modification
121+
- Example: `test-user-001``test-user-001`
122+
- Used for production or fixed-name resources
123+
- Can use config file directly for cleanup
124+
125+
### Token Management
126+
127+
- Personal Access Tokens are created with configurable scopes
128+
- If `expires_at` is not specified in config, defaults to 2 days from today
129+
- Token values are included in output files for automation purposes
130+
- The admin token (used for API calls) requires `api` + `sudo` scopes
131+
132+
### Resource Hierarchy
133+
134+
Resources are created in this order:
135+
1. User
136+
2. Personal Access Token (if configured)
137+
3. Groups (with nested projects)
138+
4. User-level projects (projects not belonging to any group)
139+
140+
Deletion happens in reverse order to avoid dependency issues.
141+
142+
### User Age Filtering (Cleanup/Delete Safety Feature)
143+
144+
Both `user cleanup` and `user delete-by-prefix` commands include a safety mechanism to prevent accidental deletion of recently created users:
145+
146+
- **Default behavior**: Only delete users created 2 or more days ago
147+
- **Configurable**: Use `--days-old` flag to adjust the threshold
148+
- `--days-old 7`: Only delete users 7+ days old
149+
- `--days-old 0`: Disable age filtering, delete all matching users
150+
- **Implementation**: Compares user's `CreatedAt` field with current time
151+
- **Logging**: Shows creation date and days since creation for each user
152+
153+
This prevents accidental deletion of users created in recent test runs or CI/CD pipelines.
154+
155+
### Error Handling
156+
157+
- 404 errors from GitLab API are handled specially (resource doesn't exist)
158+
- Each operation includes comprehensive logging with emoji indicators (✓, ⚠)
159+
- Errors are wrapped with context using `fmt.Errorf`
160+
- Failed operations log warnings but don't always stop the entire batch
161+
162+
### Environment Variables
163+
164+
- `GITLAB_URL`: GitLab instance URL (can be overridden by `--host`)
165+
- `GITLAB_TOKEN`: Personal Access Token (can be overridden by `--token`)
166+
- Command-line flags take precedence over environment variables
167+
168+
## Configuration File Structure
169+
170+
YAML files define users with nested groups and projects:
171+
- `nameMode`: "prefix" or "name" (default: "prefix")
172+
- `token`: Optional PAT configuration with scopes and expiration
173+
- `groups[]`: Array of groups, each with their own projects
174+
- `projects[]`: User-level projects (not under any group)
175+
176+
See `examples/user.yaml` for a complete example.
177+
178+
## Template System
179+
180+
The tool supports Go template rendering for custom output formats:
181+
- Template file specified with `-t` flag
182+
- Has access to `OutputConfig` struct with all created resource data
183+
- Dynamic fields available: `$.Endpoint`, `$.Host`, `$.Scheme`, `$.Port`
184+
- User data: `.Username`, `.UserID`, `.Token.Value`, `.Groups`, etc.
185+
186+
See `template-example.yaml` for template syntax.
187+
188+
## CI/CD
189+
190+
GitHub Actions workflow (`.github/workflows/ci.yml`) runs:
191+
- Lint (golangci-lint)
192+
- Test (with race detection and coverage)
193+
- Build (verifies binary creation)
194+
195+
All checks must pass on Go 1.23.
196+
197+
## Adding New Features
198+
199+
### To add a new command:
200+
1. Create `build*Command()` function in `internal/cli/cmd.go`
201+
2. Create `run*()` orchestration function
202+
3. Add business logic method to `ResourceProcessor` in `internal/processor/processor.go`
203+
4. If needed, add new API methods to `pkg/client/client.go`
204+
205+
### To add a new resource type:
206+
1. Define data structures in `pkg/types/types.go`
207+
2. Add API methods in `pkg/client/client.go`
208+
3. Add processing logic in `internal/processor/processor.go`
209+
4. Wire up commands in `internal/cli/cmd.go`
210+
211+
## Code Style
212+
213+
- Package names: lowercase singular (`config`, not `configs`)
214+
- Exported types/functions: PascalCase (`GitLabClient`, `NewGitLabClient`)
215+
- Private functions: camelCase (`ensureUser`, `deleteProjects`)
216+
- Chinese comments are used throughout for team readability
217+
- Log messages use structured format with emoji indicators

0 commit comments

Comments
 (0)