From 8b03835ffb3253f41f579689608d0ff8786d2fab Mon Sep 17 00:00:00 2001 From: John Kisor Date: Sun, 22 Jan 2023 10:34:29 -0500 Subject: [PATCH 1/2] Action to maintain Servers.xml --- .../actions/expire-servers/Dockerfile | 8 ++++ .../workflows/actions/expire-servers/Gemfile | 3 ++ .../actions/expire-servers/Gemfile.lock | 15 ++++++ .../actions/expire-servers/action.yml | 5 ++ .../workflows/actions/expire-servers/main.rb | 47 +++++++++++++++++++ .github/workflows/maintenance.yml | 25 ++++++++++ 6 files changed, 103 insertions(+) create mode 100644 .github/workflows/actions/expire-servers/Dockerfile create mode 100644 .github/workflows/actions/expire-servers/Gemfile create mode 100644 .github/workflows/actions/expire-servers/Gemfile.lock create mode 100644 .github/workflows/actions/expire-servers/action.yml create mode 100644 .github/workflows/actions/expire-servers/main.rb create mode 100644 .github/workflows/maintenance.yml diff --git a/.github/workflows/actions/expire-servers/Dockerfile b/.github/workflows/actions/expire-servers/Dockerfile new file mode 100644 index 0000000..5d3ac5b --- /dev/null +++ b/.github/workflows/actions/expire-servers/Dockerfile @@ -0,0 +1,8 @@ +FROM ruby:3.2.0 + +COPY Gemfile Gemfile.lock ./ +RUN bundle install + +COPY main.rb ./ + +ENTRYPOINT ["ruby", "/main.rb"] diff --git a/.github/workflows/actions/expire-servers/Gemfile b/.github/workflows/actions/expire-servers/Gemfile new file mode 100644 index 0000000..3338203 --- /dev/null +++ b/.github/workflows/actions/expire-servers/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gem 'nokogiri', '1.14.0' diff --git a/.github/workflows/actions/expire-servers/Gemfile.lock b/.github/workflows/actions/expire-servers/Gemfile.lock new file mode 100644 index 0000000..fd50fe5 --- /dev/null +++ b/.github/workflows/actions/expire-servers/Gemfile.lock @@ -0,0 +1,15 @@ +GEM + remote: https://rubygems.org/ + specs: + nokogiri (1.14.0-x86_64-linux) + racc (~> 1.4) + racc (1.6.2) + +PLATFORMS + x86_64-linux + +DEPENDENCIES + nokogiri (= 1.14.0) + +BUNDLED WITH + 2.4.1 diff --git a/.github/workflows/actions/expire-servers/action.yml b/.github/workflows/actions/expire-servers/action.yml new file mode 100644 index 0000000..6d741fe --- /dev/null +++ b/.github/workflows/actions/expire-servers/action.yml @@ -0,0 +1,5 @@ +name: 'Expire servers' +description: 'Produces a new Servers.xml with expired servers removed and opens a pull request' +runs: + using: 'docker' + image: 'Dockerfile' diff --git a/.github/workflows/actions/expire-servers/main.rb b/.github/workflows/actions/expire-servers/main.rb new file mode 100644 index 0000000..62bb152 --- /dev/null +++ b/.github/workflows/actions/expire-servers/main.rb @@ -0,0 +1,47 @@ +require 'uri' +require 'net/http' +require 'nokogiri' +require 'json' +require 'date' + +WORKSPACE_DIR = '/github/workspace' +MONTHS_UNTIL_EXPIRED = 3 + +class FetchTreeStatsServers + def call + response = submit_request + parse(response) + end + + private + + def submit_request + Net::HTTP.get_response(URI('https://servers.treestats.net/api/servers/')) + end + + def parse(response) + JSON + .parse(response.body) + .map do |server| + { + id: server['guid'], + last_seen: DateTime.parse(server.dig('status','last_seen')) + } + end + end +end + +servers = FetchTreeStatsServers.new.call + +expire_time = DateTime.now.prev_month(MONTHS_UNTIL_EXPIRED) +expired_servers = servers.select { |s| s[:last_seen] <= expire_time} +expired_server_ids = expired_servers.map { |s| s[:id] } + +contents = File.read("#{WORKSPACE_DIR}/Servers.xml") +doc = Nokogiri::XML(contents) + +doc.css("ArrayOfServerItem ServerItem") + .select { |element| expired_server_ids.include?(element.at_css('id').content) } + .each(&:remove) + +File.write("#{WORKSPACE_DIR}/Servers.xml", doc.to_s) diff --git a/.github/workflows/maintenance.yml b/.github/workflows/maintenance.yml new file mode 100644 index 0000000..0a529ff --- /dev/null +++ b/.github/workflows/maintenance.yml @@ -0,0 +1,25 @@ +name: Maintenance + +on: + schedule: + - cron: '0 0 1 * *' + + workflow_dispatch: + +jobs: + + build: + + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v3 + - name: Expire servers + uses: ./.github/workflows/actions/expire-servers + - name: Create Pull Request + uses: peter-evans/create-pull-request@v4 + with: + branch: remove-expired-servers + delete-branch: true + title: 'Remove expired servers' From adbe15be42d1a0b092d5f8c8f43acf2fdd4017cb Mon Sep 17 00:00:00 2001 From: John Kisor Date: Fri, 3 Feb 2023 22:54:01 -0500 Subject: [PATCH 2/2] Refactor and do not expire servers in the keep file --- .../workflows/actions/expire-servers/main.rb | 94 +++++++++++++------ keep | 2 + 2 files changed, 66 insertions(+), 30 deletions(-) create mode 100644 keep diff --git a/.github/workflows/actions/expire-servers/main.rb b/.github/workflows/actions/expire-servers/main.rb index 62bb152..a7e1ed4 100644 --- a/.github/workflows/actions/expire-servers/main.rb +++ b/.github/workflows/actions/expire-servers/main.rb @@ -1,47 +1,81 @@ +require 'nokogiri' + +class ServerList + def initialize(xml) + @doc = Nokogiri::XML(xml) + end + + def remove(ids) + @doc + .css("ArrayOfServerItem ServerItem") + .select { |e| ids.include?(e.at_css('id').content) } + .each(&:remove) + end + + def to_xml + @doc.to_s + end +end + require 'uri' require 'net/http' -require 'nokogiri' require 'json' + require 'date' -WORKSPACE_DIR = '/github/workspace' -MONTHS_UNTIL_EXPIRED = 3 +class Server + MONTHS_TIL_EXPIRED = 3 + attr_reader :id, :last_seen -class FetchTreeStatsServers - def call - response = submit_request - parse(response) + def initialize(id: , last_seen:) + @id = id + @last_seen = last_seen end - private - - def submit_request - Net::HTTP.get_response(URI('https://servers.treestats.net/api/servers/')) + def expired? + @last_seen <= DateTime.now.prev_month(MONTHS_TIL_EXPIRED) end +end + +module TreeStats + class Servers + def self.all + response = fetch + parse(response.body) + end - def parse(response) - JSON - .parse(response.body) - .map do |server| - { - id: server['guid'], - last_seen: DateTime.parse(server.dig('status','last_seen')) - } - end + def self.expired + all.select(&:expired?) + end + + def self.fetch + Net::HTTP.get_response(URI('https://servers.treestats.net/api/servers/')) + end + + def self.parse(body) + JSON + .parse(body) + .map do |server| + Server.new( + id: server['guid'], + last_seen: DateTime.parse(server.dig('status', 'last_seen')) + ) + end + end end end -servers = FetchTreeStatsServers.new.call +FILE_PATH = '/github/workspace/Servers.xml' +KEEP_PATH = '/github/workspace/keep' -expire_time = DateTime.now.prev_month(MONTHS_UNTIL_EXPIRED) -expired_servers = servers.select { |s| s[:last_seen] <= expire_time} -expired_server_ids = expired_servers.map { |s| s[:id] } +xml = File.read(FILE_PATH) +server_list = ServerList.new(xml) +expired = TreeStats::Servers.expired -contents = File.read("#{WORKSPACE_DIR}/Servers.xml") -doc = Nokogiri::XML(contents) +require 'csv' +keep_ids = CSV.read(KEEP_PATH).flatten -doc.css("ArrayOfServerItem ServerItem") - .select { |element| expired_server_ids.include?(element.at_css('id').content) } - .each(&:remove) +ids = expired.map(&:id).reject { |id| keep_ids.include?(id) } +server_list.remove(ids) -File.write("#{WORKSPACE_DIR}/Servers.xml", doc.to_s) +File.write(FILE_PATH, server_list.to_xml) diff --git a/keep b/keep new file mode 100644 index 0000000..1c55cdc --- /dev/null +++ b/keep @@ -0,0 +1,2 @@ +26D70BC9-78E9-4DDC-BCFF-7D5B36F6AC17 +ce4ae843-7afa-48ea-82bb-21b25301e1c9