Skip to content

Commit 0476543

Browse files
authored
Rename users clean or prune -- use aggregated user statistics (#901)
* added new type to process siteUser grahQL type -- still needing to change in utility functions * code compiling but not registering users to remove correctly * correctly structured json response * remove debugging log * rename command src users clean to src users prune * rename null flag * changelog entry * correct json formating * correct command name in users general help * style correct users.go
1 parent a2de954 commit 0476543

File tree

3 files changed

+52
-33
lines changed

3 files changed

+52
-33
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,12 @@ All notable changes to `src-cli` are documented in this file.
1515

1616
### Changed
1717

18+
- Renamed `src users clean` command to `src users prune` [#901](https://github.com/sourcegraph/src-cli/pull/901)
19+
1820
### Fixed
1921

22+
- Fix network timeout in `src users clean` occuring in instances with many users [#901](https://github.com/sourcegraph/src-cli/pull/901)
23+
2024
### Removed
2125

2226
## 4.3.0

cmd/src/users.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ The commands are:
2020
get gets a user
2121
create creates a user account
2222
delete deletes a user account
23-
clean deletes inactive users
23+
prune deletes inactive users
2424
tag add/remove a tag on a user
2525
2626
Use "src users [command] -h" for more information about a command.
@@ -90,3 +90,11 @@ type UserUsageStatistics struct {
9090
LastActiveTime string
9191
LastActiveCodeHostIntegrationTime string
9292
}
93+
94+
type SiteUser struct {
95+
ID string
96+
Username string
97+
Email string
98+
SiteAdmin bool
99+
LastActiveAt string
100+
}

cmd/src/users_clean.go renamed to cmd/src/users_prune.go

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,21 @@ This command removes users from a Sourcegraph instance who have been inactive fo
1919
2020
Examples:
2121
22-
$ src users clean -days 182
22+
$ src users prune -days 182
2323
24-
$ src users clean -remove-admin -remove-never-active
24+
$ src users prune -remove-admin -remove-null-users
2525
`
2626

27-
flagSet := flag.NewFlagSet("clean", flag.ExitOnError)
27+
flagSet := flag.NewFlagSet("prune", flag.ExitOnError)
2828
usageFunc := func() {
2929
fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src users %s':\n", flagSet.Name())
3030
flagSet.PrintDefaults()
3131
fmt.Println(usage)
3232
}
3333
var (
3434
daysToDelete = flagSet.Int("days", 60, "Days threshold on which to remove users, must be 60 days or greater and defaults to this value ")
35-
removeAdmin = flagSet.Bool("remove-admin", false, "clean admin accounts")
36-
removeNoLastActive = flagSet.Bool("remove-never-active", false, "removes users with null lastActive value")
35+
removeAdmin = flagSet.Bool("remove-admin", false, "prune admin accounts")
36+
removeNoLastActive = flagSet.Bool("remove-null-users", false, "removes users with no last active value")
3737
skipConfirmation = flagSet.Bool("force", false, "skips user confirmation step allowing programmatic use")
3838
apiFlags = api.NewFlags(flagSet)
3939
)
@@ -51,7 +51,7 @@ Examples:
5151
client := cfg.apiClient(apiFlags, flagSet.Output())
5252

5353
currentUserQuery := `
54-
query {
54+
query getCurrentUser {
5555
currentUser {
5656
username
5757
}
@@ -68,43 +68,50 @@ query {
6868
return err
6969
}
7070

71-
usersQuery := `
72-
query Users() {
73-
users() {
74-
nodes {
75-
...UserFields
76-
}
77-
}
71+
getInactiveUsersQuery := `
72+
query getInactiveUsers {
73+
site {
74+
users {
75+
nodes {
76+
username
77+
email
78+
siteAdmin
79+
lastActiveAt
80+
}
81+
}
82+
}
7883
}
79-
` + userFragment
84+
`
8085

81-
// get users to delete
8286
var usersResult struct {
83-
Users struct {
84-
Nodes []User
87+
Site struct {
88+
Users struct {
89+
Nodes []SiteUser
90+
}
8591
}
8692
}
87-
if ok, err := client.NewRequest(usersQuery, nil).Do(ctx, &usersResult); err != nil || !ok {
93+
94+
if ok, err := client.NewRequest(getInactiveUsersQuery, nil).Do(ctx, &usersResult); err != nil || !ok {
8895
return err
8996
}
9097

9198
usersToDelete := make([]UserToDelete, 0)
92-
for _, user := range usersResult.Users.Nodes {
93-
daysSinceLastUse, wasLastActive, err := computeDaysSinceLastUse(user)
99+
for _, user := range usersResult.Site.Users.Nodes {
100+
daysSinceLastUse, hasLastActive, err := computeDaysSinceLastUse(user)
94101
if err != nil {
95102
return err
96103
}
97104
// never remove user issuing command
98105
if user.Username == currentUserResult.Data.CurrentUser.Username {
99106
continue
100107
}
101-
if !wasLastActive && !*removeNoLastActive {
108+
if !hasLastActive && !*removeNoLastActive {
102109
continue
103110
}
104111
if !*removeAdmin && user.SiteAdmin {
105112
continue
106113
}
107-
if daysSinceLastUse <= *daysToDelete && wasLastActive {
114+
if daysSinceLastUse <= *daysToDelete && hasLastActive {
108115
continue
109116
}
110117
deleteUser := UserToDelete{user, daysSinceLastUse}
@@ -146,13 +153,13 @@ query Users() {
146153
}
147154

148155
// computes days since last usage from current day and time and UsageStatistics.LastActiveTime, uses time.Parse
149-
func computeDaysSinceLastUse(user User) (timeDiff int, wasLastActive bool, _ error) {
150-
// handle for null lastActiveTime returned from
151-
if user.UsageStatistics.LastActiveTime == "" {
152-
wasLastActive = false
153-
return 0, wasLastActive, nil
156+
func computeDaysSinceLastUse(user SiteUser) (timeDiff int, hasLastActive bool, _ error) {
157+
// handle for null LastActiveAt returned from
158+
if user.LastActiveAt == "" {
159+
hasLastActive = false
160+
return 0, hasLastActive, nil
154161
}
155-
timeLast, err := time.Parse(time.RFC3339, user.UsageStatistics.LastActiveTime)
162+
timeLast, err := time.Parse(time.RFC3339, user.LastActiveAt)
156163
if err != nil {
157164
return 0, false, err
158165
}
@@ -162,7 +169,7 @@ func computeDaysSinceLastUse(user User) (timeDiff int, wasLastActive bool, _ err
162169
}
163170

164171
// Issue graphQL api request to remove user
165-
func removeUser(user User, client api.Client, ctx context.Context) error {
172+
func removeUser(user SiteUser, client api.Client, ctx context.Context) error {
166173
query := `mutation DeleteUser($user: ID!) {
167174
deleteUser(user: $user) {
168175
alwaysNil
@@ -178,7 +185,7 @@ func removeUser(user User, client api.Client, ctx context.Context) error {
178185
}
179186

180187
type UserToDelete struct {
181-
User User
188+
User SiteUser
182189
DaysSinceLastUse int
183190
}
184191

@@ -189,8 +196,8 @@ func confirmUserRemoval(usersToRemove []UserToDelete) (bool, error) {
189196
t.SetOutputMirror(os.Stdout)
190197
t.AppendHeader(table.Row{"Username", "Email", "Days Since Last Active"})
191198
for _, user := range usersToRemove {
192-
if len(user.User.Emails) > 0 {
193-
t.AppendRow([]interface{}{user.User.Username, user.User.Emails[0].Email, user.DaysSinceLastUse})
199+
if user.User.Email != "" {
200+
t.AppendRow([]interface{}{user.User.Username, user.User.Email, user.DaysSinceLastUse})
194201
t.AppendSeparator()
195202
} else {
196203
t.AppendRow([]interface{}{user.User.Username, "", user.DaysSinceLastUse})

0 commit comments

Comments
 (0)