Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions .github/actions/publish-apps/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: Publish Apps

inputs:
sdk_version:
description: The SDK version that determines the path on the CDN
required: true

Comment thread
KenVanHoeylandt marked this conversation as resolved.
runs:
using: 'composite'
steps:
- name: 'Download cdn-files'
uses: actions/download-artifact@v4
with:
name: 'cdn-files'
path: cdn_files
- name: 'Install boto3'
shell: bash
run: pip install boto3
- name: 'Upload files'
shell: bash
run: python Buildscripts/CDN/upload-app-files.py cdn_files ${{ inputs.sdk_version }} ${{ env.CDN_ID }} ${{ env.CDN_TOKEN_NAME }} ${{ env.CDN_TOKEN_VALUE }}
Comment thread
KenVanHoeylandt marked this conversation as resolved.
10 changes: 9 additions & 1 deletion .github/actions/release-apps/action.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
name: Release Apps

outputs:
sdk_version:
description: 'Common SDK version shared by all bundled apps'
value: ${{ steps.release.outputs.sdk_version }}

Comment thread
KenVanHoeylandt marked this conversation as resolved.
runs:
using: 'composite'
steps:
Expand All @@ -11,8 +16,11 @@ runs:
run: rsync -av downloaded_apps/*/*.app cdn_files/
shell: bash
- name: 'Create CDN release files'
run: python release.py cdn_files/
id: release
shell: bash
run: |
python release.py cdn_files/
echo "sdk_version=$(cat sdk_version.txt)" >> "$GITHUB_OUTPUT"
- name: 'Upload Artifact'
uses: actions/upload-artifact@v4
with:
Expand Down
21 changes: 21 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,35 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: "Build"
uses: ./.github/actions/build-app
with:
app_name: ${{ matrix.app_name }}
Bundle:
runs-on: ubuntu-latest
needs: [Build]
outputs:
sdk_version: ${{ steps.release.outputs.sdk_version }}
steps:
- uses: actions/checkout@v4
Comment thread
KenVanHoeylandt marked this conversation as resolved.
- name: "Build"
id: release
uses: ./.github/actions/release-apps
PublishApps:
runs-on: ubuntu-latest
needs: [Bundle]
if: (github.event_name == 'push' && github.ref == 'refs/heads/main')
steps:
- uses: actions/checkout@v4
with:
persist-credentials: false
- name: "Publish Apps"
env:
CDN_ID: ${{ secrets.CDN_ID }}
CDN_TOKEN_NAME: ${{ secrets.CDN_TOKEN_NAME }}
CDN_TOKEN_VALUE: ${{ secrets.CDN_TOKEN_VALUE }}
uses: ./.github/actions/publish-apps
with:
sdk_version: ${{ needs.Bundle.outputs.sdk_version }}
70 changes: 70 additions & 0 deletions Buildscripts/CDN/upload-app-files.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import os
import sys
import boto3

SHELL_COLOR_RED = "\033[91m"
SHELL_COLOR_ORANGE = "\033[93m"
SHELL_COLOR_RESET = "\033[m"

def print_warning(message):
print(f"{SHELL_COLOR_ORANGE}WARNING: {message}{SHELL_COLOR_RESET}")

def print_error(message):
print(f"{SHELL_COLOR_RED}ERROR: {message}{SHELL_COLOR_RESET}")

def print_help():
print("Usage: python upload-app-files.py [path] [sdkVersion] [cloudflareAccountId] [cloudflareTokenName] [cloudflareTokenValue]")
print("")
print("Options:")
print(" --index-only Upload only apps.json")

def exit_with_error(message):
print_error(message)
sys.exit(1)

def main(path: str, sdk_version: str, cloudflare_account_id, cloudflare_token_name: str, cloudflare_token_value: str, index_only: bool):
if not os.path.exists(path):
exit_with_error(f"Path not found: {path}")
s3 = boto3.client(
service_name="s3",
endpoint_url=f"https://{cloudflare_account_id}.r2.cloudflarestorage.com",
aws_access_key_id=cloudflare_token_name,
aws_secret_access_key=cloudflare_token_value,
region_name="auto"
)
Comment thread
KenVanHoeylandt marked this conversation as resolved.
files_to_upload = os.listdir(path)
if index_only:
files_to_upload = [f for f in files_to_upload if f == 'apps.json']
else:
# Ensure apps.json is uploaded last so it never references files that
# haven't finished uploading yet.
files_to_upload.sort(key=lambda f: f == 'apps.json')
counter = 1
total = len(files_to_upload)
for file_name in files_to_upload:
object_path = f"apps/{sdk_version}/{file_name}"
print(f"[{counter}/{total}] Uploading {file_name} to {object_path}")
file_path = os.path.join(path, file_name)
try:
s3.upload_file(file_path, "tactility", object_path)
except Exception as e:
exit_with_error(f"Failed to upload {file_name}: {str(e)}")
counter += 1

if __name__ == "__main__":
print("Tactility CDN Apps Uploader")
if "--help" in sys.argv:
print_help()
sys.exit()
# Argument validation
if len(sys.argv) < 6:
print_help()
sys.exit(1)
main(
path=sys.argv[1],
sdk_version=sys.argv[2],
cloudflare_account_id=sys.argv[3],
cloudflare_token_name=sys.argv[4],
cloudflare_token_value=sys.argv[5],
index_only="--index-only" in sys.argv
)
29 changes: 25 additions & 4 deletions release.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import json
import subprocess
import tarfile
import os
import tempfile
import sys
from datetime import datetime, UTC

def read_properties_file(path):
properties = {}
Expand Down Expand Up @@ -81,6 +83,17 @@ def get_os_version(manifest):
else:
return sdk

def check_and_get_sdk_version(manifest_map):
"""Ensure all apps target the same (simplified) SDK version and return it."""
versions = {get_os_version(manifest) for manifest in manifest_map.values()}
if len(versions) != 1:
print(f"ERROR: Apps target multiple SDK versions: {sorted(versions)}. All apps must target the same SDK version.")
sys.exit(1)
return next(iter(versions))
Comment thread
KenVanHoeylandt marked this conversation as resolved.

def get_git_commit_hash():
return subprocess.check_output(['git', 'rev-parse', 'HEAD']).decode('ascii').strip()

def manifest_config_to_flat_json(manifest):
"""Convert a flat (V2) manifest dict into a flat JSON-like dict.

Expand Down Expand Up @@ -136,15 +149,23 @@ def write_json(filepath, data):
sys.exit()
app_directory = sys.argv[1]
manifest_map = {}
output_json = {
"apps": []
}
any_manifest = None
if os.path.exists(app_directory):
for file in os.listdir(app_directory):
if file.endswith(".app"):
file_path = os.path.join(app_directory, file)
manifest_map[file_path] = get_manifest(file_path)
# All bundled apps must target the same SDK version; this becomes the CDN path segment
sdk_version = check_and_get_sdk_version(manifest_map)
with open("sdk_version.txt", "w") as f:
f.write(sdk_version)
print(f"SDK version: {sdk_version}")
output_json = {
"sdkVersion": sdk_version,
"created": datetime.now(UTC).strftime('%Y-%m-%dT%H:%M:%SZ'),
"gitCommit": get_git_commit_hash(),
"apps": []
}
# Rename files and collect manifest data into output json object
for file_path in manifest_map.keys():
print(f"Processing {file_path}: {manifest_map[file_path]}")
Expand All @@ -158,4 +179,4 @@ def write_json(filepath, data):
any_manifest = manifest
# Write JSON
output_json_path = os.path.join(app_directory, "apps.json")
write_json(output_json_path, output_json)
write_json(output_json_path, output_json)
Loading