Welcome to mirror list, hosted at ThFree Co, Russian Federation.

delete_user_projects.rb « tools « qa « qa - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 5fe8e30cb66d464d6926eec7fb2880dbf9ec1d59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# frozen_string_literal: true

# This script deletes all projects owned by a given USER_ID or QA_USERNAMES in their personal namespace
# Required environment variables: GITLAB_QA_ACCESS_TOKEN, GITLAB_ADDRESS, and USER_ID or CLEANUP_ALL_QA_USER_PROJECTS
# Run `rake delete_user_projects`

module QA
  module Tools
    class DeleteUserProjects
      include Support::API
      include Lib::Project
      include Ci::Helpers

      # We cannot pass ids because they are different on each live environment
      QA_USERNAMES = %w[gitlab-qa
        gitlab-qa-admin
        gitlab-qa-user1
        gitlab-qa-user2
        gitlab-qa-user3
        gitlab-qa-user4
        gitlab-qa-user5
        gitlab-qa-user6].freeze

      def initialize(delete_before: (Date.today - 3).to_s, dry_run: false)
        %w[GITLAB_ADDRESS GITLAB_QA_ACCESS_TOKEN].each do |var|
          raise ArgumentError, "Please provide #{var} environment variable" unless ENV[var]
        end

        unless ENV['USER_ID'] || ENV['CLEANUP_ALL_QA_USER_PROJECTS']
          raise ArgumentError, "Please provide USER_ID or CLEANUP_ALL_QA_USER_PROJECTS environment variable"
        end

        @delete_before = Date.parse(delete_before)
        @dry_run = dry_run
        @api_client = set_api_client(ENV['GITLAB_QA_ACCESS_TOKEN'])
      end

      # @example
      #   GITLAB_ADDRESS=<address> \
      #   GITLAB_QA_ACCESS_TOKEN=<token> \
      #   USER_ID=<id> bundle exec rake "delete_user_projects[2023-01-01,true]"
      #
      # @example
      #   GITLAB_ADDRESS=<address> \
      #   GITLAB_QA_ACCESS_TOKEN=<token> \
      #   USER_ID=<id> bundle exec rake "delete_user_projects[,true]"
      #
      # @example
      #   GITLAB_ADDRESS=<address> \
      #   GITLAB_QA_ACCESS_TOKEN=<token> \
      #   CLEANUP_ALL_QA_USER_PROJECTS=true bundle exec rake delete_user_projects
      def run
        user_ids = fetch_user_ids
        return 'No users found. Skipping project delete.' if user_ids.empty?

        user_ids.each do |user_id|
          qa_username = fetch_qa_username(user_id)

          api_client = if qa_username == "gitlab-qa-user1" && ENV['GITLAB_QA_USER1_ACCESS_TOKEN']
                         set_api_client(ENV['GITLAB_QA_USER1_ACCESS_TOKEN'])
                       elsif qa_username == "gitlab-qa-user2" && ENV['GITLAB_QA_USER2_ACCESS_TOKEN']
                         set_api_client(ENV['GITLAB_QA_USER2_ACCESS_TOKEN'])
                       else
                         @api_client
                       end

          delete_user_projects(qa_username, user_id, api_client)
        end
      end

      private

      def delete_user_projects(qa_username, user_id, api_client)
        logger.info("Running project delete for user #{qa_username} (#{user_id}) on #{ENV['GITLAB_ADDRESS']}...")

        projects_head_response = head Runtime::API::Request.new(api_client, "/users/#{user_id}/projects",
          per_page: "100").url
        total_project_pages = projects_head_response.headers[:x_total_pages]
        total_projects = projects_head_response.headers[:x_total]

        logger.info("Total projects: #{total_projects}")
        return logger.info("\nDone") if total_projects.to_i == 0

        project_ids = fetch_project_ids(total_project_pages, user_id)
        logger.info("Total projects created before #{@delete_before}: #{project_ids.size}")

        delete_projects(project_ids, api_client, @dry_run) unless project_ids.empty?
        logger.info("\nDone")
      end

      def fetch_project_ids(total_project_pages, user_id)
        projects_ids = []

        total_project_pages.to_i.times do |page_no|
          projects_response = get Runtime::API::Request.new(@api_client, "/users/#{user_id}/projects",
            page: (page_no + 1).to_s, per_page: "100").url
          projects_ids.concat(JSON.parse(projects_response.body)
                                  .select { |project| Date.parse(project["created_at"]) < @delete_before }
                                  .map { |project| project["id"] })
        rescue StandardError => e
          logger.error("Failed to fetch projects for user #{user_id}: #{e.message}")
        end

        projects_ids.uniq
      end

      def fetch_user_ids
        user_ids = ENV['CLEANUP_ALL_QA_USER_PROJECTS'] ? fetch_qa_user_ids : []
        user_ids << ENV['USER_ID'].to_i if ENV['USER_ID']

        user_ids.uniq
      end

      def fetch_qa_user_ids
        logger.info("Fetching QA user ids...")
        user_ids = []

        QA_USERNAMES.each do |qa_username|
          user_response = get Runtime::API::Request.new(@api_client, "/users", username: qa_username).url

          unless user_response.code == HTTP_STATUS_OK
            logger.error("Request for #{qa_username} returned (#{user_response.code}): `#{user_response}` ")
            next
          end

          parsed_response = JSON.parse(user_response.body)

          if parsed_response.empty?
            logger.error("User #{qa_username} not found")
            next
          end

          user_ids << parsed_response.first["id"]
        rescue StandardError => e
          logger.error("Failed to fetch user ID for #{qa_username}: #{e.message}")
        end

        user_ids.uniq
      end

      def fetch_qa_username(user_id)
        response = get Runtime::API::Request.new(@api_client, "/users/#{user_id}").url
        parsed_response = JSON.parse(response.body)
        parsed_response["username"]
      end

      def set_api_client(token)
        Runtime::API::Client.new(ENV['GITLAB_ADDRESS'],
          personal_access_token: token)
      end
    end
  end
end