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..a7e1ed4 --- /dev/null +++ b/.github/workflows/actions/expire-servers/main.rb @@ -0,0 +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 'json' + +require 'date' + +class Server + MONTHS_TIL_EXPIRED = 3 + attr_reader :id, :last_seen + + def initialize(id: , last_seen:) + @id = id + @last_seen = last_seen + end + + 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 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 + +FILE_PATH = '/github/workspace/Servers.xml' +KEEP_PATH = '/github/workspace/keep' + +xml = File.read(FILE_PATH) +server_list = ServerList.new(xml) +expired = TreeStats::Servers.expired + +require 'csv' +keep_ids = CSV.read(KEEP_PATH).flatten + +ids = expired.map(&:id).reject { |id| keep_ids.include?(id) } +server_list.remove(ids) + +File.write(FILE_PATH, server_list.to_xml) 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' 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