Skip to content

Commit

Permalink
build script update
Browse files Browse the repository at this point in the history
  • Loading branch information
ChunkLightTuna committed Feb 6, 2024
1 parent 448955e commit 45167b0
Show file tree
Hide file tree
Showing 3 changed files with 129 additions and 119 deletions.
231 changes: 121 additions & 110 deletions .github/workflows/foundry_release.py
Original file line number Diff line number Diff line change
@@ -1,27 +1,109 @@
import json
import os
import re
from http.client import HTTPSConnection
from html.parser import HTMLParser
from pprint import pprint, pformat
from time import sleep
from http.client import HTTPSConnection
from pprint import pformat
from urllib.parse import urlencode

from markdown_it import MarkdownIt

# GitHub Action Secrets
# Secrets
FOUNDRY_PACKAGE_RELEASE_TOKEN = os.environ['FOUNDRY_PACKAGE_RELEASE_TOKEN']
FOUNDRY_USERNAME = os.environ['FOUNDRY_USERNAME']
FOUNDRY_PASSWORD = os.environ['FOUNDRY_PASSWORD']
FOUNDRY_AUTHOR = os.environ['FOUNDRY_AUTHOR']
UPDATE_DISCORD_KEY = os.environ['UPDATE_DISCORD_KEY']
SECRETS = [FOUNDRY_PACKAGE_RELEASE_TOKEN, FOUNDRY_USERNAME, FOUNDRY_PASSWORD, FOUNDRY_AUTHOR, UPDATE_DISCORD_KEY]

# Build Variables
# Environment Variables
GITHUB_URL = os.environ['GITHUB_URL']
TAG = os.environ['TAG']
CHANGES = os.environ['CHANGES']
FILES_CHANGED = os.environ['FILES_CHANGED']


def main():
if all(f.startswith('.github') for f in FILES_CHANGED.split()):
SKIP('SKIPPING DEPLOYMENT. ONLY RELEASE CONFIG MODIFIED')
for f in FILES_CHANGED.split():
INFO(f)
return

with open('./module.json', 'r') as file:
module_json = json.load(file)

update_repo_description(module_json)
push_release(module_json)
post_update_to_discord()


def update_repo_description(module_json):
if not any(f in FILES_CHANGED for f in ['README.md', 'module.json', 'foundry_release.py']):
SKIP('SKIPPING REPO DESCRIPTION UPDATE')
return

INFO('Acquiring CSRF tokens')
conn = HTTPSConnection('foundryvtt.com')
conn.request('GET', '/', headers={})
response = conn.getresponse()
if response.status != 200:
BAD(response.reason)
csrf_token = response.getheader('Set-Cookie').split('csrftoken=')[1].split(';')[0].strip()
csrf_middleware_token = re.search(r'name="csrfmiddlewaretoken" value="([^"]+)"', response.read().decode()).group(1)

INFO('Acquiring session id')
conn = HTTPSConnection('foundryvtt.com')
conn.request('POST', '/auth/login/',
headers={
'Referer': 'https://foundryvtt.com/',
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': f'csrftoken={csrf_token}; privacy-policy-accepted=accepted'
},
body=urlencode({
'csrfmiddlewaretoken': csrf_middleware_token,
'username': FOUNDRY_USERNAME,
'password': FOUNDRY_PASSWORD
}))
response = conn.getresponse()
if response.status == 403:
BAD(response.reason)
session_id = response.getheader('Set-Cookie').split('sessionid=')[1].split(';')[0].strip()

INFO('Converting README.md to html')
md = MarkdownIt('commonmark', {'html': True}).enable('table')
with open('./README.md', 'r') as readme_file:
readme_contents = readme_file.read()
readme = md.render(readme_contents)

INFO('Updating Foundry VTT Module Repository Description')
conn = HTTPSConnection('foundryvtt.com')
conn.request('POST', f"/packages/{module_json['id']}/edit",
headers={
'Referer': f"https://foundryvtt.com/packages/{module_json['id']}/edit",
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': f'csrftoken={csrf_token}; privacy-policy-accepted=accepted; sessionid={session_id}',
},
body=urlencode([
('username', FOUNDRY_USERNAME),
('title', module_json['title']),
('description', readme),
('url', module_json['url']),
('csrfmiddlewaretoken', csrf_middleware_token),
('author', FOUNDRY_AUTHOR),
('secret-key', FOUNDRY_PACKAGE_RELEASE_TOKEN),
('requires', 1),
('tags', 15),
('tags', 17)
]))
response = conn.getresponse()
if response.status != 302:
BAD(f'Update Description Failed\n{extract_errorlist_text(response.read().decode())}')
GOOD('REPO DESCRIPTION UPDATED')


def push_release(module_json: dict) -> None:
INFO('Pushing new release to Foundry VTT Module Repository')
conn = HTTPSConnection("api.foundryvtt.com")
conn.request(
"POST", "/_api/packages/release_version/",
Expand All @@ -32,56 +114,37 @@ def push_release(module_json: dict) -> None:
body=json.dumps({
'id': module_json['id'],
'release': {
'version': module_json['version'],
'manifest': f"{module_json['url']}/releases/download/{module_json['version']}/module.json",
'notes': f"{module_json['url']}/releases/tag/{module_json['version']}",
'version': TAG,
'manifest': f"{GITHUB_URL}/releases/download/{TAG}/module.json",
'notes': f"{GITHUB_URL}/releases/tag/{TAG}",
'compatibility': module_json['compatibility']
}
})
)
response_json = json.loads(conn.getresponse().read().decode())
if response_json['status'] != 'success':
pprint(module_json)
raise Exception(pformat(response_json['errors']))
print('✅ MODULE POSTED TO REPO')


def get_readme_as_html() -> str:
md = MarkdownIt('commonmark', {'html': True}).enable('table')
with open('./README.md', 'r') as readme_file:
readme = readme_file.read()
return md.render(readme)
BAD(pformat(response_json['errors']))
GOOD('MODULE POSTED TO REPO')


def get_tokens() -> (str, str):
conn = HTTPSConnection('foundryvtt.com')
conn.request('GET', '/', headers={})
def post_update_to_discord() -> None:
INFO('Notifying Discord of new release')
deduped_changes = '\n'.join(dict.fromkeys(CHANGES.split('\n')))
conn = HTTPSConnection("api.oronder.com")
conn.request(
"POST", '/update_discord',
headers={
'Content-Type': 'application/json',
'Authorization': UPDATE_DISCORD_KEY
},
body=json.dumps({'version': TAG, 'changes': deduped_changes})
)
response = conn.getresponse()
if response.status != 200:
raise Exception(response.reason)
csrf_token = response.getheader('Set-Cookie').split('csrftoken=')[1].split(';')[0].strip()
csrf_middleware_token = re.search(r'name="csrfmiddlewaretoken" value="([^"]+)"', response.read().decode()).group(1)
return csrf_token, csrf_middleware_token


def get_session_id(csrf_token: str, csrf_middleware_token: str) -> str:
body = urlencode({
'csrfmiddlewaretoken': csrf_middleware_token,
'username': FOUNDRY_USERNAME,
'password': FOUNDRY_PASSWORD
})
headers = {
'Referer': 'https://foundryvtt.com/',
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': f'csrftoken={csrf_token}; privacy-policy-accepted=accepted'
}
conn = HTTPSConnection('foundryvtt.com')
conn.request('POST', '/auth/login/', body, headers)
response = conn.getresponse()
if response.status == 403:
raise Exception(response.reason)
cookies = response.getheader('Set-Cookie')
return cookies.split('sessionid=')[1].split(';')[0].strip()
content = response.read().decode()
headers = response.headers.as_string()
BAD(f'Failed to send Update Message to Discord\n{content=}\n{headers=}')
GOOD('DISCORD NOTIFIED OF NEW RELEASE')


def extract_errorlist_text(html_string: str) -> str:
Expand All @@ -108,79 +171,27 @@ def handle_data(self, data):
return parser.errorlist_content


def post_packages_oronder_edit(csrf_token, csrf_middleware_token, session_id, description, module_json) -> None:
conn = HTTPSConnection('foundryvtt.com')
headers = {
'Referer': f"https://foundryvtt.com/packages/{module_json['id']}/edit",
'Content-Type': 'application/x-www-form-urlencoded',
'Cookie': f'csrftoken={csrf_token}; privacy-policy-accepted=accepted; sessionid={session_id}',
}
body = urlencode([
('username', FOUNDRY_USERNAME),
('title', module_json['title']),
('description', description),
('url', module_json['url']),
('csrfmiddlewaretoken', csrf_middleware_token),
('author', FOUNDRY_AUTHOR),
('secret-key', FOUNDRY_PACKAGE_RELEASE_TOKEN),
('requires', 1),
('tags', 15),
('tags', 17)
])
conn.request('POST', f"/packages/{module_json['id']}/edit", body, headers)
response = conn.getresponse()
if response.status != 302:
content = response.read().decode()
raise Exception(f'Update Description Failed\n{extract_errorlist_text(content)}')
def safe_print(s: str):
for secret in SECRETS:
s = s.replace(secret, '*****')
print(s)


def post_update_to_discord(version) -> None:
deduped_changes = '\n'.join(dict.fromkeys(CHANGES.split('\n')))
conn = HTTPSConnection("api.oronder.com")
conn.request(
"POST", '/update_discord',
headers={
'Content-Type': 'application/json',
'Authorization': UPDATE_DISCORD_KEY
},
body=json.dumps({'version': version, 'changes': deduped_changes})
)
response = conn.getresponse()
if response.status != 200:
content = response.read().decode()
headers = response.headers.as_string()
raise Exception(f'Failed to send Update Message to Discord\n{content=}\n{headers=}')
print('✅ DISCORD NOTIFIED OF NEW RELEASE')
def INFO(s: str):
safe_print(f' {s}')


def update_repo_description(module_json):
if any(f in FILES_CHANGED for f in ['README.md', 'module.json']):
csrf_token, csrf_middleware_token = get_tokens()
session_id = get_session_id(csrf_token, csrf_middleware_token)
readme = get_readme_as_html()
post_packages_oronder_edit(csrf_token, csrf_middleware_token, session_id, readme, module_json)
print('✅ REPO DESCRIPTION UPDATED')
for i in range(10):
print('💤' * (10 - i))
sleep(1)
else:
print('🪧 SKIPPING REPO DESCRIPTION UPDATE')
def SKIP(s: str):
safe_print(f'🪧 {s}')


def main():
if all(f.startswith('.github') for f in FILES_CHANGED.split()):
print('\n'.join([
f'⛔ SKIPPING DEPLOYMENT. ONLY RELEASE CONFIG MODIFIED',
*[f" {f}" for f in FILES_CHANGED.split()]
]))
return
def GOOD(s: str):
safe_print(f'✅ {s}')

with open('./module.json', 'r') as file:
module_json = json.load(file)

update_repo_description(module_json)
push_release(module_json)
post_update_to_discord(module_json['version'])
def BAD(s: str):
safe_print(f'❌ {s}')
exit(1)


if __name__ == '__main__':
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
name: Create Module Files For GitHub Release
env:
GITHUB_URL: "https://github.com/${{ github.repository }}"
TAG: ${{ github.event.release.tag_name || github.ref_name }}

on:
Expand All @@ -25,9 +26,7 @@ jobs:
uses: cschleiden/replace-tokens@v1.2
with:
files: 'module.json'
env:
VERSION: ${{ env.TAG }}
URL: "https://github.com/${{ github.repository }}"


- name: Downloading Dependencies
run: npm install --omit=dev
Expand Down
12 changes: 6 additions & 6 deletions module.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"id": "oronder",
"title": "Oronder | Discord Sync",
"description": "Bidirectional Discord Integration for Foundry VTT",
"version": "#{VERSION}#",
"version": "#{TAG}#",
"library": "false",
"manifestPlusVersion": "1.2.0",
"compatibility": {
Expand Down Expand Up @@ -47,11 +47,11 @@
],
"socket": true,
"url": "https://discord.gg/ZggUCHsQqg",
"bugs": "#{URL}#/issues",
"manifest": "#{URL}#/releases/latest/download/module.json",
"download": "#{URL}#/releases/download/#{VERSION}#/module.zip",
"license": "#{URL}#/releases/download/#{VERSION}#/LICENSE",
"readme": "#{URL}#/releases/download/#{VERSION}#/README.md",
"bugs": "#{GITHUB_URL}#/issues",
"manifest": "#{GITHUB_URL}#/releases/latest/download/module.json",
"download": "#{GITHUB_URL}#/releases/download/#{TAG}#/module.zip",
"license": "#{GITHUB_URL}#/releases/download/#{TAG}#/LICENSE",
"readme": "#{GITHUB_URL}#/releases/download/#{TAG}#/README.md",
"media": [
{
"type": "icon",
Expand Down

0 comments on commit 45167b0

Please sign in to comment.