Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨Migrate Analytics to GA4 #289

Open
wants to merge 14 commits into
base: develop
Choose a base branch
from
Open
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
3 changes: 3 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ jobs:

- name: Install Requirements
run: python3 -m pip install --upgrade pip && pip3 install wheel && pip3 install -r requirements.txt && pip3 uninstall -y typing

- name: Write secrets to config file
run: echo "[analytics]\napi_key=${{ secrets.GA4_SECRET_CLI}}" > config.ini

- name: Build Wheel
run: python3 setup.py bdist_wheel
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include config.ini
2 changes: 2 additions & 0 deletions config.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[analytics]
api_key={{ secrets.GA4_API_KEY}}
16 changes: 12 additions & 4 deletions pros/cli/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def make(project: c.Project, build_args):
"""
Build current PROS project or cwd
"""
analytics.send("make")
analytics.send("make", dict.fromkeys(build_args))
exit_code = project.compile(build_args)
if exit_code != 0:
logger(__name__).error(f'Failed to make project: Exit Code {exit_code}', extra={'sentry': False})
Expand All @@ -35,7 +35,11 @@ def make(project: c.Project, build_args):
@project_option()
@click.pass_context
def make_upload(ctx, project: c.Project, build_args: List[str], **upload_args):
analytics.send("make-upload")
options = dict.fromkeys(build_args)
# add target, after, icon, and slot from upload_args to options. dont include other keys from upload_args
options.update({k: v for k, v in upload_args.items() if k in ['target', 'after', 'icon', 'slot']})
analytics.send("make_upload", options)

ctx.invoke(make, project=project, build_args=build_args)
ctx.invoke(upload, project=project, **upload_args)

Expand All @@ -46,7 +50,11 @@ def make_upload(ctx, project: c.Project, build_args: List[str], **upload_args):
@project_option()
@click.pass_context
def make_upload_terminal(ctx, project: c.Project, build_args, **upload_args):
analytics.send("make-upload-terminal")
options = dict.fromkeys(build_args)
# add target, after, icon, and slot from upload_args to options. dont include other keys from upload_args
options.update({k: v for k, v in upload_args.items() if k in ['target', 'after', 'icon', 'slot']})
analytics.send("make_upload_terminal", options)

from .terminal import terminal
ctx.invoke(make, project=project, build_args=build_args)
ctx.invoke(upload, project=project, **upload_args)
Expand All @@ -67,7 +75,7 @@ def build_compile_commands(project: c.Project, suppress_output: bool, compile_co
Build a compile_commands.json compatible with cquery
:return:
"""
analytics.send("build-compile-commands")
analytics.send("build_compile_commands", dict.fromkeys(build_args).update({'suppress_output': suppress_output, 'sandbox': sandbox, 'compile_commands': 1 if compile_commands else 0}))
exit_code = project.make_scan_build(build_args, cdb_file=compile_commands, suppress_output=suppress_output,
sandbox=sandbox)
if exit_code != 0:
Expand Down
40 changes: 31 additions & 9 deletions pros/cli/conductor.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,16 @@ def fetch(query: c.BaseTemplate):

Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more
"""
analytics.send("fetch-template")


# query identifier can be a path to a local template, or just the template name@version. we want to check if it's a path, and if it is, extract the name@version from the full path
# we do this so that we don't send user's full paths to analytics, as that's a bit of a privacy concern (could contain username, etc.)
name_version = query.identifier
if os.path.exists(query.identifier):
name_version = os.path.basename(query.identifier)
analytics.send("fetch_template", {'template': name_version.replace("@", "_")})


template_file = None
if os.path.exists(query.identifier):
template_file = query.identifier
Expand Down Expand Up @@ -102,7 +111,12 @@ def apply(project: c.Project, query: c.BaseTemplate, **kwargs):

Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more
"""
analytics.send("apply-template")
# query identifier can be a path to a local template, or just the template name@version. we want to check if it's a path, and if it is, extract the name@version from the full path
# we do this so that we don't send user's full paths to analytics, as that's a bit of a privacy concern (could contain username, etc.)
name_version = query.identifier
if os.path.exists(query.identifier):
name_version = os.path.basename(query.identifier)
analytics.send("apply_template", {'template': name_version.replace("@", "_"), "beta": kwargs.get('beta'), "upgrade_ok": kwargs.get('upgrade_ok'), "install_ok": kwargs.get('install_ok')})
return c.Conductor().apply_template(project, identifier=query, **kwargs)


Expand All @@ -127,7 +141,9 @@ def install(ctx: click.Context, **kwargs):

Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more
"""
analytics.send("install-template")
# im gonna have analytics on this for now, just to prove that this command is not used. all it is is a wrapper for apply with install_ok=True,
# however, install_ok is True by default, so this command is literally useless
analytics.send("install_template")
return ctx.invoke(apply, install_ok=True, **kwargs)


Expand All @@ -154,7 +170,9 @@ def upgrade(ctx: click.Context, project: c.Project, query: c.BaseTemplate, **kwa

Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more
"""
analytics.send("upgrade-project")
templatename = query.name if query.name else "All"
print(kwargs)
analytics.send("upgrade_template", {"template_name": templatename, "beta": kwargs.get('beta'), "download_ok": kwargs.get('download_ok'), "install_ok": kwargs.get('install_ok')})
if not query.name:
for template in project.templates.keys():
click.secho(f'Upgrading {template}', color='yellow')
Expand All @@ -180,7 +198,9 @@ def uninstall_template(project: c.Project, query: c.BaseTemplate, remove_user: b

Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more
"""
analytics.send("uninstall-template")
templatename = query.name if query.name else "All"
analytics.send("uninstall_template", {"template_name": templatename, "remove_user": remove_user, "remove_empty_dirs": remove_empty_directories, "no_make_clean": no_make_clean})

c.Conductor().remove_template(project, query, remove_user=remove_user,
remove_empty_directories=remove_empty_directories)
if no_make_clean:
Expand Down Expand Up @@ -210,14 +230,16 @@ def uninstall_template(project: c.Project, query: c.BaseTemplate, remove_user: b
@default_options
def new_project(ctx: click.Context, path: str, target: str, version: str,
force_user: bool = False, force_system: bool = False,
no_default_libs: bool = False, compile_after: bool = True, build_cache: bool = None, **kwargs):
no_default_libs: bool = False, compile_after: bool = True, build_cache: bool = None, beta: bool = False, **kwargs):
"""
Create a new PROS project

Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more
"""
analytics.send("new-project")
analytics.send("new_project", {"version": version, "no_default_libs": no_default_libs, "compile_after": compile_after, "build_cache": build_cache, "beta": beta})

version_source = version.lower() == 'latest'

if version.lower() == 'latest' or not version:
version = '>0'
if not force_system and c.Project.find_project(path) is not None:
Expand Down Expand Up @@ -270,7 +292,7 @@ def query_templates(ctx, query: c.BaseTemplate, allow_offline: bool, allow_onlin

Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more
"""
analytics.send("query-templates")
analytics.send("query_templates", {"allow_offline": allow_offline, "allow_online": allow_online, "force_refresh": force_refresh, "limit": limit, "beta": beta})
if limit < 0:
limit = 15
templates = c.Conductor().resolve_templates(query, allow_offline=allow_offline, allow_online=allow_online,
Expand Down Expand Up @@ -313,7 +335,7 @@ def info_project(project: c.Project, ls_upgrades):

Visit https://pros.cs.purdue.edu/v5/cli/conductor.html to learn more
"""
analytics.send("info-project")
analytics.send("info_project")
from pros.conductor.project import ProjectReport
report = ProjectReport(project)
_conductor = c.Conductor()
Expand Down
4 changes: 2 additions & 2 deletions pros/cli/conductor_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def create_template(ctx, path: str, destination: str, do_zip: bool, **kwargs):

pros conduct create-template . libblrs 2.0.1 --system "firmware/*.a" --system "include/*.h"
"""
analytics.send("create-template")
analytics.send("create_template", {"kernels": kwargs['supported_kernels'], "target": kwargs['target'], "zip": do_zip, "name": kwargs['name']})
project = c.Project.find_project(path, recurse_times=1)
if project:
project = c.Project(project)
Expand Down Expand Up @@ -152,7 +152,7 @@ def filename_remap(file_path: str) -> str:
@template_query(required=False)
@default_options
def purge_template(query: c.BaseTemplate, force):
analytics.send("purge-template")
analytics.send("purge_template", {"template": query.identifier if query else None, "force": force})
if not query:
force = click.confirm('Are you sure you want to remove all cached templates? This action is non-reversable!',
abort=True)
Expand Down
13 changes: 13 additions & 0 deletions pros/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,17 @@ def use_analytics(ctx: click.Context, param, value):
ui.echo('Analytics set to : {}'.format(analytics.useAnalytics))
ctx.exit(0)

def show_analytics(ctx: click.Context, param, value):
ctx.ensure_object(dict)
# if analytics are currently enabled
if(analytics.useAnalytics):
ui.echo('\nAnalytics are currently ENABLED.\n')
ui.echo('DATA currently being collected is as follows:\n 1) Commands being run\n 2) Non identifying command arguments')
else:
ui.echo('\nAnalytics are currently DISABLED.')

ctx.exit(0)


@click.command('pros',
cls=PROSCommandCollection,
Expand All @@ -112,6 +123,8 @@ def use_analytics(ctx: click.Context, param, value):
callback=version)
@click.option('--use-analytics', help='Set analytics usage (True/False).', type=str, expose_value=False,
is_eager=True, default=None, callback=use_analytics)
@click.option('--show-analytics', help='Show current analytics usage.', is_flag=True, expose_value=False,
is_eager=True, default=False, callback=show_analytics)
def cli(ctx):
pros.common.sentry.register()
ctx.call_on_close(after_command)
Expand Down
5 changes: 4 additions & 1 deletion pros/cli/misc_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,15 @@ def upgrade(force_check, no_install):
"""
Check for updates to the PROS CLI
"""

analytics.send("upgrade", {"force_check": force_check, "no_install": no_install})

with ui.Notification():
ui.echo('The "pros upgrade" command is currently non-functioning. Did you mean to run "pros c upgrade"?', color='yellow')

return # Dead code below

analytics.send("upgrade")

from pros.upgrade import UpgradeManager
manager = UpgradeManager()
manifest = manager.get_manifest(force_check)
Expand Down
2 changes: 1 addition & 1 deletion pros/cli/terminal.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def terminal(port: str, backend: str, **kwargs):

Note: share backend is not yet implemented.
"""
analytics.send("terminal")
analytics.send("terminal", {"raw": kwargs.get('raw', False), "hex": kwargs.get('hex', False), "banner": kwargs.get('request_banner', True), "output": True if kwargs.get('output', None) else False})
from pros.serial.devices.vex.v5_user_device import V5UserDevice
from pros.serial.terminal import Terminal
is_v5_user_joystick = False
Expand Down
10 changes: 7 additions & 3 deletions pros/cli/upload.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ def upload(path: Optional[str], project: Optional[c.Project], port: str, **kwarg
[PORT] may be any valid communication port file, such as COM1 or /dev/ttyACM0. If left blank, then a port is
automatically detected based on the target (or as supplied by the PROS project)
"""
analytics.send("upload")
# send analytics with target, after, slot, and icon
analytics.send('upload', {"target": kwargs.get('target', None), "after": kwargs.get('after', None), "slot": kwargs.get('slot', None), "icon": kwargs.get('icon', None)})

import pros.serial.devices.vex as vex
from pros.serial.ports import DirectPort
kwargs['ide_version'] = project.kernel if not project==None else "None"
Expand Down Expand Up @@ -164,7 +166,7 @@ def ls_usb(target):
"""
List plugged in VEX Devices
"""
analytics.send("ls-usb")
analytics.send("ls_usb")
from pros.serial.devices.vex import find_v5_ports, find_cortex_ports

class PortReport(object):
Expand Down Expand Up @@ -204,7 +206,9 @@ def __str__(self):
@shadow_command(upload)
@click.pass_context
def make_upload_terminal(ctx, **upload_kwargs):
analytics.send("upload-terminal")
# send analytics with target, after, slot, and icon
analytics.send_analytics('upload_terminal', {"target": upload_kwargs.get('target', None), "after": upload_kwargs.get('after', None), "slot": upload_kwargs.get('slot', None), "icon": upload_kwargs.get('icon', None)})

from .terminal import terminal
ctx.invoke(upload, **upload_kwargs)
ctx.invoke(terminal, request_banner=False)
2 changes: 1 addition & 1 deletion pros/cli/user_script.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def user_script(script_file):
"""
Run a script file with the PROS CLI package
"""
analytics.send("user-script")
analytics.send("user_script")
import os.path
import importlib.util
package_name = os.path.splitext(os.path.split(script_file)[0])[0]
Expand Down
19 changes: 12 additions & 7 deletions pros/cli/v5_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def ls_files(port: str, vid: int, options: int):
"""
List files on the flash filesystem
"""
analytics.send("ls-files")
analytics.send("ls_files")
from pros.serial.devices.vex import V5Device
from pros.serial.ports import DirectPort
port = resolve_v5_port(port, 'system')[0]
Expand All @@ -72,7 +72,7 @@ def read_file(file_name: str, port: str, vid: int, source: str):
"""
Read file on the flash filesystem to stdout
"""
analytics.send("read-file")
analytics.send("read_file")
from pros.serial.devices.vex import V5Device
from pros.serial.ports import DirectPort
port = resolve_v5_port(port, 'system')[0]
Expand All @@ -98,7 +98,7 @@ def write_file(file, port: str, remote_file: str, **kwargs):
"""
Write a file to the V5.
"""
analytics.send("write-file")
analytics.send("write_file")
from pros.serial.ports import DirectPort
from pros.serial.devices.vex import V5Device
port = resolve_v5_port(port, 'system')[0]
Expand All @@ -121,7 +121,7 @@ def rm_file(file_name: str, port: str, vid: int, erase_all: bool):
"""
Remove a file from the flash filesystem
"""
analytics.send("rm-file")
analytics.send("rm_file")
from pros.serial.devices.vex import V5Device
from pros.serial.ports import DirectPort
port = resolve_v5_port(port, 'system')[0]
Expand All @@ -142,7 +142,7 @@ def cat_metadata(file_name: str, port: str, vid: int):
"""
Print metadata for a file
"""
analytics.send("cat-metadata")
analytics.send("cat_metadata")
from pros.serial.devices.vex import V5Device
from pros.serial.ports import DirectPort
port = resolve_v5_port(port, 'system')[0]
Expand All @@ -162,6 +162,7 @@ def rm_program(slot: int, port: str, vid: int):
"""
Remove a program from the flash filesystem
"""
analytics.send("rm_program")
from pros.serial.devices.vex import V5Device
from pros.serial.ports import DirectPort
port = resolve_v5_port(port, 'system')[0]
Expand All @@ -182,7 +183,7 @@ def rm_all(port: str, vid: int):
"""
Remove all user programs from the V5
"""
analytics.send("rm-all")
analytics.send("rm_all")
from pros.serial.devices.vex import V5Device
from pros.serial.ports import DirectPort
port = resolve_v5_port(port, 'system')[0]
Expand All @@ -207,7 +208,7 @@ def run(slot: str, port: str):
"""
Run a V5 program
"""
analytics.send("run")
analytics.send("run", {"slot": slot})
from pros.serial.devices.vex import V5Device
from pros.serial.ports import DirectPort
file = f'slot_{slot}.bin'
Expand All @@ -232,6 +233,7 @@ def stop(port: str):

If FILE is unspecified or is a directory, then attempts to find the correct filename based on the PROS project
"""
analytics.send("stop")
from pros.serial.devices.vex import V5Device
from pros.serial.ports import DirectPort
port = resolve_v5_port(port, 'system')[0]
Expand All @@ -251,6 +253,7 @@ def capture(file_name: str, port: str, force: bool = False):
"""
Take a screen capture of the display
"""
analytics.send("capture_screen", {"force": force})
from pros.serial.devices.vex import V5Device
from pros.serial.ports import DirectPort
import png
Expand Down Expand Up @@ -297,6 +300,7 @@ def capture(file_name: str, port: str, force: bool = False):
@click.argument('port', type=str, default=None, required=False)
@default_options
def set_variable(variable, value, port):
analytics.send("set_variable", {"variable": value})
import pros.serial.devices.vex as vex
from pros.serial.ports import DirectPort

Expand All @@ -313,6 +317,7 @@ def set_variable(variable, value, port):
@click.argument('port', type=str, default=None, required=False)
@default_options
def read_variable(variable, port):
analytics.send("read_variable", {"variable": variable})
import pros.serial.devices.vex as vex
from pros.serial.ports import DirectPort

Expand Down
Loading
Loading