From 369badd56d66de10fd21b98b42c1a0741ecd8702 Mon Sep 17 00:00:00 2001 From: syeopite Date: Mon, 19 Jul 2021 18:41:40 -0700 Subject: [PATCH] Add infrastructure for generating reports Fix workflow Add gh token input to workflow Fix paths and unterminated quotes in py script Escape strikethrough markdown syntax Populate action inputs for PR create --- .github/workflows/ci.yml | 52 ++++++++++++++++++++ src/generate.py | 101 +++++++++++++++++++++++++++++++++++++++ src/known-data.json | 1 + src/requirements.txt | 5 ++ 4 files changed, 159 insertions(+) create mode 100644 .github/workflows/ci.yml create mode 100644 src/generate.py create mode 100644 src/known-data.json create mode 100644 src/requirements.txt diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..eca90bc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,52 @@ +on: + workflow_dispatch: + schedule: + - cron: "30 0 1 * *" + +jobs: + TemplateTransparencyReport: + runs-on: ubuntu-latest + name: Template the transparency report for iv-org + steps: + - uses: actions/checkout@v2 + with: + ref: ${{ github.head_ref }} + + - name: "Fetch data for report" + uses: syeopite/transparency-data-fetcher-for-iv-org@v1.1 + id: data_fetch_step + with: + github-token: ${{ github.token }} + + - name: "Setup python for templating report" + uses: actions/setup-python@v2 + with: + python-version: 3.9.5 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r src/requirements.txt + + - name: Template report + run: | + python src/generate.py '${{ steps.data_fetch_step.outputs.fetched-btc-bounty-data }}' + + # Auto commit resulting md file + - name: "Auto commiting resulting markdown instance list" + uses: stefanzweifel/git-auto-commit-action@v4 + with: + commit_message: Template transparency report for ${date -d "$(date +%Y-%m)-15 last month" '+%Y-%m'} + file_pattern: ${date -d "$(date +%Y-%m)-15 last month" '+%Y-%m'}.md + + # https://github.com/iv-org/invidious/blob/ad7fefae1ca0b734fbe986eb8bb13f1996e2f5f8/.github/workflows/monthly_release.yml#L13 + - id: fetch_date + run: echo ::set-output name=date::$(date -d "$(date +%Y-%m)-15 last month" '+%B-%Y') + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3 + with: + delete-branch: true + body: This is the template for the ${{ steps.fetch_date.outputs.date }} transparency report + title: ${{ steps.fetch_date.outputs.date }} transparency report + branch: ${{ steps.fetch_date.outputs.date }}-Report diff --git a/src/generate.py b/src/generate.py new file mode 100644 index 0000000..2368004 --- /dev/null +++ b/src/generate.py @@ -0,0 +1,101 @@ +import datetime +import json +import re +import sys +from urllib import request + +from dateutil.parser import isoparse +from dateutil.relativedelta import relativedelta +from mdutils.mdutils import MdUtils + +conversation_rate_in_time_regex = re.compile(r"avg: [$€](?P\d+)", re.MULTILINE) + + +def get_coin_conversion_rate(fiat, date=None): + # Request the converstion rate between BTC and the selected fiat currency + url = f"https://{fiat}.rate.sx/" + if date: + date = isoparse(date) + url += f"BTC@{date.strftime('%Y-%m-%d+%Hh%Mm%Ss')}" \ + f"?T&q" + else: + url += "1BTC" + + with request.urlopen(url) as connection: + conversion = connection.read().decode("utf-8") + if date: + return float(conversation_rate_in_time_regex.search(conversion)["rate"]) + else: + return float(conversion) + + +def get_fiat_conversion_rate(fiat_a, fiat_b, date=None): + # Request frankfurter.app for the converstion rate between two currencies. + # + # Parameters: + # fiat_a: Fiat A (to convert from) + # fiat_b: Fiat B (to convert two) + # date: + # If specified, requests the converstion rate between the two given currencies at the given + # + url = f"https://api.frankfurter.app" + if date: + date = isoparse(date) + url += f"/{date.strftime('%Y-%m-%d')}" + else: + url += "/latest" + url += f"?from={fiat_a}&to={fiat_b}" + with request.urlopen(url) as connection: + return json.load(connection)["rates"][fiat_b.upper()] + + +current_time = datetime.datetime.utcnow() +with open("src/known-data.json", "r") as file: + known_data = json.load(file) +new_transparency_data = json.loads(sys.argv[1]) + +# Calculate new funds +current_funds = known_data["total_current_btc_funds"] + new_transparency_data["new_btc_previous_month"] +for bounty in new_transparency_data["bounty_costs"]: + current_funds - float(bounty["bounty_cost_crypto"].strip(" BTC")) + +usd_to_btc = get_coin_conversion_rate("usd") +eur_to_btc = get_coin_conversion_rate("eur") +btc_price_str = f"~€{round(eur_to_btc, 2)} or \~${round(usd_to_btc, 2)}" + +# Create header +md = MdUtils(file_name=f"finance/{(current_time - relativedelta(months=1)).strftime('%Y-%m')}.md") +md.new_header(level=1, title=f"Finances for {(current_time - relativedelta(months=1)).strftime('%B %Y')}") + +# Donations section +md.new_header(level=2, title="Donations:") +if not new_transparency_data["new_btc_previous_month"]: + md.new_paragraph("Bitcoin (BTC): None") +else: + md.new_paragraph(f"Bitcoin (BTC): {new_transparency_data['new_btc_previous_month']} BTC worth" + f" ~€{round(new_transparency_data['new_btc_previous_month'] * eur_to_btc, 2)}" + f" at the time of publishing (Bitcoin price {btc_price_str})") + +md.new_paragraph("Monero (XMR): X XMR worth ~€X at the time of publishing (Monero price \~€X or \~$X)") + +md.new_header(level=2, title="Expenses:") +for bounty in new_transparency_data["bounty_costs"]: + usd_to_btc_rate_at_time = get_coin_conversion_rate("usd", date=bounty['date']) + usd_to_eur_rate_at_time = get_fiat_conversion_rate("usd", "eur", date=bounty['date']) + usd_bounty_cost = float(bounty['bounty_cost_crypto'].strip(' BTC')) * usd_to_btc_rate_at_time + + md.new_paragraph(f"Bounty ({bounty['url']}): {bounty['bounty_cost_crypto']} worth ~ " + f"€{round(usd_bounty_cost * usd_to_eur_rate_at_time, 2)} (~${round(usd_bounty_cost, 2)})") + +md.new_header(level=2, title="Current funds:") +md.new_paragraph(f"Bitcoin (BTC): {current_funds} BTC worth ~€{round(current_funds * eur_to_btc, 2)} " + f"(\~${round(current_funds * usd_to_btc, 2)}) at the time of publishing " + f"(Bitcoin price {btc_price_str})") + +md.new_paragraph("Monero (XMR): X XMR worth ~€X (\~$X) at the time of publishing (Monero price ~€X or \~$X)") +md.create_md_file() + +# Now we update the known data +known_data["total_current_btc_funds"] = current_funds +with open("src/known-data.json", "w") as file: + json.dump(known_data, file) diff --git a/src/known-data.json b/src/known-data.json new file mode 100644 index 0000000..af1299c --- /dev/null +++ b/src/known-data.json @@ -0,0 +1 @@ +{"total_current_btc_funds": 0.30957846} \ No newline at end of file diff --git a/src/requirements.txt b/src/requirements.txt new file mode 100644 index 0000000..3538567 --- /dev/null +++ b/src/requirements.txt @@ -0,0 +1,5 @@ +dateutils==0.6.12 +mdutils==1.3.1 +python-dateutil==2.8.2 +pytz==2021.1 +six==1.16.0