From 82da68e721020cb0ff3adc9bd6eac80805f13f2b Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 14 Dec 2022 02:15:12 -0800 Subject: [PATCH 01/10] added new type to process siteUser grahQL type -- still needing to change in utility functions --- cmd/src/users_clean.go | 48 +++++++++++++++++++++++++++--------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/cmd/src/users_clean.go b/cmd/src/users_clean.go index 4651383dc4..3a34cc1d72 100644 --- a/cmd/src/users_clean.go +++ b/cmd/src/users_clean.go @@ -51,7 +51,7 @@ Examples: client := cfg.apiClient(apiFlags, flagSet.Output()) currentUserQuery := ` -query { +query getCurrentUser { currentUser { username } @@ -68,23 +68,37 @@ query { return err } - usersQuery := ` -query Users() { - users() { - nodes { - ...UserFields - } - } + getInactiveUsersQuery := ` +query getInactiveUsers { + site { + users { + nodes { + username + email + siteAdmin + lastActiveAt + } + } + } } -` + userFragment +` + + // This isnt the full SiteUser available in the graphQL API and shoul only be used in this command + type SiteUser struct { + Username string + Email string + SiteAdmin bool + lastActiveAt string + } + - // get users to delete var usersResult struct { Users struct { - Nodes []User + Nodes []SiteUser } } - if ok, err := client.NewRequest(usersQuery, nil).Do(ctx, &usersResult); err != nil || !ok { + + if ok, err := client.NewRequest(getInactiveUsersQuery, nil).Do(ctx, &usersResult); err != nil || !ok { return err } @@ -146,13 +160,13 @@ query Users() { } // computes days since last usage from current day and time and UsageStatistics.LastActiveTime, uses time.Parse -func computeDaysSinceLastUse(user User) (timeDiff int, wasLastActive bool, _ error) { +func computeDaysSinceLastUse(user SiteUser) (timeDiff int, wasLastActive bool, _ error) { // handle for null lastActiveTime returned from - if user.UsageStatistics.LastActiveTime == "" { + if user.lastActiveAt == "" { wasLastActive = false return 0, wasLastActive, nil } - timeLast, err := time.Parse(time.RFC3339, user.UsageStatistics.LastActiveTime) + timeLast, err := time.Parse(time.RFC3339, user.lastActiveAt) if err != nil { return 0, false, err } @@ -162,7 +176,7 @@ func computeDaysSinceLastUse(user User) (timeDiff int, wasLastActive bool, _ err } // Issue graphQL api request to remove user -func removeUser(user User, client api.Client, ctx context.Context) error { +func removeUser(user SiteUser, client api.Client, ctx context.Context) error { query := `mutation DeleteUser($user: ID!) { deleteUser(user: $user) { alwaysNil @@ -178,7 +192,7 @@ func removeUser(user User, client api.Client, ctx context.Context) error { } type UserToDelete struct { - User User + User SiteUser DaysSinceLastUse int } From 01a9c95a38410bf100c5c68d5636323c68e54331 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 14 Dec 2022 03:26:40 -0800 Subject: [PATCH 02/10] code compiling but not registering users to remove correctly --- cmd/src/users.go | 9 +++++++++ cmd/src/users_clean.go | 33 ++++++++++++--------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/cmd/src/users.go b/cmd/src/users.go index 38d4cfdc00..a5a29a0cfb 100644 --- a/cmd/src/users.go +++ b/cmd/src/users.go @@ -90,3 +90,12 @@ type UserUsageStatistics struct { LastActiveTime string LastActiveCodeHostIntegrationTime string } + +type SiteUser struct { + ID string + Username string + Email string + SiteAdmin bool + LastActiveAt string +} + diff --git a/cmd/src/users_clean.go b/cmd/src/users_clean.go index 3a34cc1d72..d672646e3e 100644 --- a/cmd/src/users_clean.go +++ b/cmd/src/users_clean.go @@ -33,7 +33,7 @@ Examples: var ( daysToDelete = flagSet.Int("days", 60, "Days threshold on which to remove users, must be 60 days or greater and defaults to this value ") removeAdmin = flagSet.Bool("remove-admin", false, "clean admin accounts") - removeNoLastActive = flagSet.Bool("remove-never-active", false, "removes users with null lastActive value") + removeNoLastActive = flagSet.Bool("remove-never-active", false, "removes users with no events registered in the database") skipConfirmation = flagSet.Bool("force", false, "skips user confirmation step allowing programmatic use") apiFlags = api.NewFlags(flagSet) ) @@ -83,15 +83,6 @@ query getInactiveUsers { } ` - // This isnt the full SiteUser available in the graphQL API and shoul only be used in this command - type SiteUser struct { - Username string - Email string - SiteAdmin bool - lastActiveAt string - } - - var usersResult struct { Users struct { Nodes []SiteUser @@ -104,7 +95,7 @@ query getInactiveUsers { usersToDelete := make([]UserToDelete, 0) for _, user := range usersResult.Users.Nodes { - daysSinceLastUse, wasLastActive, err := computeDaysSinceLastUse(user) + daysSinceLastUse, hasLastActive, err := computeDaysSinceLastUse(user) if err != nil { return err } @@ -112,13 +103,13 @@ query getInactiveUsers { if user.Username == currentUserResult.Data.CurrentUser.Username { continue } - if !wasLastActive && !*removeNoLastActive { + if !hasLastActive && !*removeNoLastActive { continue } if !*removeAdmin && user.SiteAdmin { continue } - if daysSinceLastUse <= *daysToDelete && wasLastActive { + if daysSinceLastUse <= *daysToDelete && hasLastActive { continue } deleteUser := UserToDelete{user, daysSinceLastUse} @@ -160,13 +151,13 @@ query getInactiveUsers { } // computes days since last usage from current day and time and UsageStatistics.LastActiveTime, uses time.Parse -func computeDaysSinceLastUse(user SiteUser) (timeDiff int, wasLastActive bool, _ error) { - // handle for null lastActiveTime returned from - if user.lastActiveAt == "" { - wasLastActive = false - return 0, wasLastActive, nil +func computeDaysSinceLastUse(user SiteUser) (timeDiff int, hasLastActive bool, _ error) { + // handle for null LastActiveAt returned from + if user.LastActiveAt == "" { + hasLastActive = false + return 0, hasLastActive, nil } - timeLast, err := time.Parse(time.RFC3339, user.lastActiveAt) + timeLast, err := time.Parse(time.RFC3339, user.LastActiveAt) if err != nil { return 0, false, err } @@ -203,8 +194,8 @@ func confirmUserRemoval(usersToRemove []UserToDelete) (bool, error) { t.SetOutputMirror(os.Stdout) t.AppendHeader(table.Row{"Username", "Email", "Days Since Last Active"}) for _, user := range usersToRemove { - if len(user.User.Emails) > 0 { - t.AppendRow([]interface{}{user.User.Username, user.User.Emails[0].Email, user.DaysSinceLastUse}) + if user.User.Email != "" { + t.AppendRow([]interface{}{user.User.Username, user.User.Email, user.DaysSinceLastUse}) t.AppendSeparator() } else { t.AppendRow([]interface{}{user.User.Username, "", user.DaysSinceLastUse}) From d545ac9fbaa4b2c51533eb43295c91d9c1159af2 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Wed, 14 Dec 2022 15:03:17 -0800 Subject: [PATCH 03/10] correctly structured json response --- cmd/src/users_clean.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmd/src/users_clean.go b/cmd/src/users_clean.go index d672646e3e..7390ddafbb 100644 --- a/cmd/src/users_clean.go +++ b/cmd/src/users_clean.go @@ -84,17 +84,20 @@ query getInactiveUsers { ` var usersResult struct { + Site struct { Users struct { Nodes []SiteUser } + } } if ok, err := client.NewRequest(getInactiveUsersQuery, nil).Do(ctx, &usersResult); err != nil || !ok { return err } + fmt.Printf("\n request returns -- \n\n%v\n\n", usersResult) usersToDelete := make([]UserToDelete, 0) - for _, user := range usersResult.Users.Nodes { + for _, user := range usersResult.Site.Users.Nodes { daysSinceLastUse, hasLastActive, err := computeDaysSinceLastUse(user) if err != nil { return err From 6f5e4a2ddbdd016b472cc69424e70b88c162da15 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 15 Dec 2022 02:16:28 -0800 Subject: [PATCH 04/10] remove debugging log --- cmd/src/users_clean.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/src/users_clean.go b/cmd/src/users_clean.go index 7390ddafbb..4f60ea7900 100644 --- a/cmd/src/users_clean.go +++ b/cmd/src/users_clean.go @@ -94,7 +94,6 @@ query getInactiveUsers { if ok, err := client.NewRequest(getInactiveUsersQuery, nil).Do(ctx, &usersResult); err != nil || !ok { return err } - fmt.Printf("\n request returns -- \n\n%v\n\n", usersResult) usersToDelete := make([]UserToDelete, 0) for _, user := range usersResult.Site.Users.Nodes { From 8dec9ced4bf861a35befa762cd7b02bc9389357b Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 15 Dec 2022 02:22:41 -0800 Subject: [PATCH 05/10] rename command src users clean to src users prune --- cmd/src/{users_clean.go => users_prune.go} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename cmd/src/{users_clean.go => users_prune.go} (95%) diff --git a/cmd/src/users_clean.go b/cmd/src/users_prune.go similarity index 95% rename from cmd/src/users_clean.go rename to cmd/src/users_prune.go index 4f60ea7900..23ffe9a1e0 100644 --- a/cmd/src/users_clean.go +++ b/cmd/src/users_prune.go @@ -19,12 +19,12 @@ This command removes users from a Sourcegraph instance who have been inactive fo Examples: - $ src users clean -days 182 + $ src users prune -days 182 - $ src users clean -remove-admin -remove-never-active + $ src users prune -remove-admin -remove-never-active ` - flagSet := flag.NewFlagSet("clean", flag.ExitOnError) + flagSet := flag.NewFlagSet("prune", flag.ExitOnError) usageFunc := func() { fmt.Fprintf(flag.CommandLine.Output(), "Usage of 'src users %s':\n", flagSet.Name()) flagSet.PrintDefaults() @@ -32,7 +32,7 @@ Examples: } var ( daysToDelete = flagSet.Int("days", 60, "Days threshold on which to remove users, must be 60 days or greater and defaults to this value ") - removeAdmin = flagSet.Bool("remove-admin", false, "clean admin accounts") + removeAdmin = flagSet.Bool("remove-admin", false, "prune admin accounts") removeNoLastActive = flagSet.Bool("remove-never-active", false, "removes users with no events registered in the database") skipConfirmation = flagSet.Bool("force", false, "skips user confirmation step allowing programmatic use") apiFlags = api.NewFlags(flagSet) From 20a30d8405899f75ba182ee8f26006326e1bb105 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 15 Dec 2022 02:51:34 -0800 Subject: [PATCH 06/10] rename null flag --- cmd/src/users_prune.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/src/users_prune.go b/cmd/src/users_prune.go index 23ffe9a1e0..a3d0814162 100644 --- a/cmd/src/users_prune.go +++ b/cmd/src/users_prune.go @@ -21,7 +21,7 @@ Examples: $ src users prune -days 182 - $ src users prune -remove-admin -remove-never-active + $ src users prune -remove-admin -remove-null-users ` flagSet := flag.NewFlagSet("prune", flag.ExitOnError) @@ -33,7 +33,7 @@ Examples: var ( daysToDelete = flagSet.Int("days", 60, "Days threshold on which to remove users, must be 60 days or greater and defaults to this value ") removeAdmin = flagSet.Bool("remove-admin", false, "prune admin accounts") - removeNoLastActive = flagSet.Bool("remove-never-active", false, "removes users with no events registered in the database") + removeNoLastActive = flagSet.Bool("remove-null-users", false, "removes users with no last active value") skipConfirmation = flagSet.Bool("force", false, "skips user confirmation step allowing programmatic use") apiFlags = api.NewFlags(flagSet) ) From 9d29a240d82f45c0a300d84094d073daa9177667 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 15 Dec 2022 02:59:32 -0800 Subject: [PATCH 07/10] changelog entry --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a99d32e31..788350d236 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,8 +15,12 @@ All notable changes to `src-cli` are documented in this file. ### Changed +- Renamed `src users clean` command to `src users prune` [#901](https://github.com/sourcegraph/src-cli/pull/901) + ### Fixed +- Fix network timeout in `src users clean` occuring in instances with many users [#901](https://github.com/sourcegraph/src-cli/pull/901) + ### Removed ## 4.3.0 From 4504fbe5ae5ee87f89a55cc0652eb11faabaea81 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 15 Dec 2022 10:43:37 -0800 Subject: [PATCH 08/10] correct json formating --- cmd/src/users_prune.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/src/users_prune.go b/cmd/src/users_prune.go index a3d0814162..54bd05c87e 100644 --- a/cmd/src/users_prune.go +++ b/cmd/src/users_prune.go @@ -85,9 +85,9 @@ query getInactiveUsers { var usersResult struct { Site struct { - Users struct { - Nodes []SiteUser - } + Users struct { + Nodes []SiteUser + } } } From c1dd0ee17a1a6b37427ffd8a005070d0f4438aae Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 15 Dec 2022 10:47:31 -0800 Subject: [PATCH 09/10] correct command name in users general help --- cmd/src/users.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/src/users.go b/cmd/src/users.go index a5a29a0cfb..352e60c192 100644 --- a/cmd/src/users.go +++ b/cmd/src/users.go @@ -20,7 +20,7 @@ The commands are: get gets a user create creates a user account delete deletes a user account - clean deletes inactive users + prune deletes inactive users tag add/remove a tag on a user Use "src users [command] -h" for more information about a command. From ed3d2294893ae9afe009e7f024de985cc3fd9b01 Mon Sep 17 00:00:00 2001 From: DaedalusG Date: Thu, 15 Dec 2022 11:02:30 -0800 Subject: [PATCH 10/10] style correct users.go --- cmd/src/users.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/cmd/src/users.go b/cmd/src/users.go index 352e60c192..20c2810120 100644 --- a/cmd/src/users.go +++ b/cmd/src/users.go @@ -92,10 +92,9 @@ type UserUsageStatistics struct { } type SiteUser struct { - ID string - Username string - Email string - SiteAdmin bool + ID string + Username string + Email string + SiteAdmin bool LastActiveAt string } -