mirror of
https://github.com/bellingcat/octosuite.git
synced 2026-06-12 21:38:34 +03:00
@@ -6,7 +6,6 @@ WORKDIR /app
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN pip install --upgrade pip && pip install build && python -m build
|
||||
RUN pip install dist/*.whl
|
||||
RUN pip install --upgrade pip && pip install build && python -m build && pip install dist/*.whl
|
||||
|
||||
ENTRYPOINT ["octosuite"]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||

|
||||
|
||||
A framework fro gathering osint on GitHub users, repositories and organizations
|
||||
A framework for gathering osint on GitHub users, repositories and organizations
|
||||
|
||||
[](https://github.com/bellingcat/octosuite/actions/workflows/python-publish.yml)
|
||||
[](https://github.com/bellingcat/octosuite/actions/workflows/codeql.yml)
|
||||
|
||||
23
octosuite/banner.py
Normal file
23
octosuite/banner.py
Normal file
@@ -0,0 +1,23 @@
|
||||
import getpass
|
||||
from octosuite.config import red, white, green, reset, Tree
|
||||
|
||||
|
||||
# banner.py
|
||||
# This file holds the program's banner and version tag
|
||||
version_tag = "3.0.0"
|
||||
|
||||
|
||||
def banner():
|
||||
banner_tree = Tree(getpass.getuser())
|
||||
banner_tree.add(f"use ‘{green}help{reset}’ command for usage")
|
||||
banner_tree.add(f"commands are case insensitive\n")
|
||||
return f"""
|
||||
_______ __ _______ __ __
|
||||
| |.----.| |_.-----.| __|.--.--.|__| |_.-----.
|
||||
| - || __|| _| _ ||__ || | || | _| -__|
|
||||
|_______||____||____|_____||_______||_____||__|____|_____|
|
||||
v{version_tag}#dev
|
||||
{white}— Advanced Github {red}OSINT{white} Framework
|
||||
|
||||
|
||||
""", banner_tree
|
||||
@@ -1,44 +0,0 @@
|
||||
import random
|
||||
import getpass
|
||||
from rich.tree import Tree
|
||||
from octosuite.colors import red, white, green, reset
|
||||
|
||||
|
||||
# banners.py
|
||||
# This file holds the program's banners and version tag
|
||||
version_tag = "3.0.0"
|
||||
|
||||
|
||||
def ascii_banner():
|
||||
banner_tree = Tree(getpass.getuser())
|
||||
banner_tree.add(f"use ‘{green}help{reset}’ command for usage")
|
||||
banner_tree.add(f"commands are case insensitive\n")
|
||||
ascii_banners = [
|
||||
"""
|
||||
_______ __ _______ __ __
|
||||
| |.----.| |_.-----.| __|.--.--.|__| |_.-----.
|
||||
| - || __|| _| _ ||__ || | || | _| -__|
|
||||
|_______||____||____|_____||_______||_____||__|____|_____|
|
||||
""",
|
||||
"""
|
||||
╔═╗┌─┐┌┬┐┌─┐╔═╗┬ ┬┬┌┬┐┌─┐
|
||||
║ ║│ │ │ │╚═╗│ ││ │ ├┤
|
||||
╚═╝└─┘ ┴ └─┘╚═╝└─┘┴ ┴ └─┘
|
||||
""",
|
||||
"""
|
||||
░▒█▀▀▀█░█▀▄░▀█▀░▄▀▀▄░▒█▀▀▀█░█░▒█░░▀░░▀█▀░█▀▀
|
||||
░▒█░░▒█░█░░░░█░░█░░█░░▀▀▀▄▄░█░▒█░░█▀░░█░░█▀▀
|
||||
░▒█▄▄▄█░▀▀▀░░▀░░░▀▀░░▒█▄▄▄█░░▀▀▀░▀▀▀░░▀░░▀▀▀
|
||||
""",
|
||||
"""
|
||||
▄▀▄ ▄▀▀ ▀█▀ ▄▀▄ ▄▀▀ █ █ █ ▀█▀ ██▀
|
||||
▀▄▀ ▀▄▄ █ ▀▄▀ ▄██ ▀▄█ █ █ █▄▄
|
||||
"""]
|
||||
ascii_banner = random.choice(ascii_banners)
|
||||
return banner_tree, f"""{ascii_banner} v{version_tag}#dev
|
||||
{white}— Advanced Github {red}OSINT{white} Framework
|
||||
|
||||
|
||||
|
||||
"""
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
import psutil
|
||||
import platform
|
||||
from rich.tree import Tree
|
||||
from datetime import datetime
|
||||
from rich import print as xprint
|
||||
|
||||
|
||||
# This file is responsible for enabling/disabling colors in OctoSuite
|
||||
# This file gets called first at start up before any other file gets called
|
||||
# colors.py is the reason why users get to choose whether to enable/disable colors
|
||||
# delete this file, the entire program breaks
|
||||
system_info = [("RAM", f"{str(round(psutil.virtual_memory().total / (1024.0 ** 3)))}GB"),
|
||||
("Node", platform.node()),
|
||||
("Release", platform.release()),
|
||||
("Version", platform.version()),
|
||||
("Processor", platform.processor()),
|
||||
("Architecture", platform.architecture())]
|
||||
first_banner = f"""
|
||||
OCTOSUITE © 2023 Richard Mwewa
|
||||
{datetime.now().strftime('%A %d %B %Y, %H:%M:%S%p')}
|
||||
|
||||
"""
|
||||
|
||||
print(first_banner)
|
||||
system_tree = Tree(platform.system())
|
||||
for system_key, system_value in system_info:
|
||||
system_tree.add(f"{system_key}: {system_value}")
|
||||
xprint(system_tree)
|
||||
print("\n")
|
||||
while True:
|
||||
try:
|
||||
color_chooser = input(f"[PROMPT] Welcome, would you like to enable colors for this session? (yes/no) ").lower()
|
||||
if color_chooser == "yes":
|
||||
header_title = "bold white"
|
||||
red = "[red]"
|
||||
white = "[white]"
|
||||
green = "[green]"
|
||||
red_bold = "[white bold]"
|
||||
white_bold = "[white bold]"
|
||||
green_bold = "[green bold]"
|
||||
reset = "[/]"
|
||||
break
|
||||
elif color_chooser == "no":
|
||||
header_title = red = white = green = red_bold = white_bold = green_bold = reset = ""
|
||||
break
|
||||
else:
|
||||
print(f"\n[INVALID] Your response '{color_chooser}' is invalid (expected yes or no)")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
exit(f"[WARNING] Process interrupted with Ctrl+C.")
|
||||
|
||||
200
octosuite/config.py
Normal file
200
octosuite/config.py
Normal file
@@ -0,0 +1,200 @@
|
||||
import psutil
|
||||
import platform
|
||||
import argparse
|
||||
from rich.tree import Tree
|
||||
from rich.text import Text
|
||||
from rich.table import Table
|
||||
from datetime import datetime
|
||||
from rich import print as xprint
|
||||
from rich.prompt import Prompt, Confirm
|
||||
|
||||
|
||||
def usage():
|
||||
return """
|
||||
Basic Usage
|
||||
===========
|
||||
|
||||
Get User Profile Info
|
||||
---------------------
|
||||
octosuite --method user_profile --username <username>
|
||||
|
||||
|
||||
Get User Repos
|
||||
--------------
|
||||
octosuite --method user_repos --username <username>
|
||||
|
||||
|
||||
Get Organi[sz]ation Profile Info
|
||||
-----------------------------
|
||||
octosuite --method org_profile --organization <organization_name>
|
||||
|
||||
|
||||
Get Organi[sz]ation Repos
|
||||
-----------------------------
|
||||
octosuite --method org_repos --organization <organization_name>
|
||||
|
||||
|
||||
Get Repo Profile Info
|
||||
---------------------
|
||||
octosuite --method repo_profile --username <username> --repository <repo_name>
|
||||
|
||||
|
||||
Get Repo Forks
|
||||
--------------
|
||||
octosuite --method repo_forks --username <username> --repository <repo_name>
|
||||
|
||||
|
||||
|
||||
Searching
|
||||
=========
|
||||
|
||||
Search Users
|
||||
------------
|
||||
octosuite --method users_search --query <query>
|
||||
|
||||
|
||||
Search Issues
|
||||
-------------
|
||||
octosuite --method issues_search --query <query>
|
||||
|
||||
|
||||
Search Commits
|
||||
--------------
|
||||
octosuite --method commits_search --query <query>
|
||||
|
||||
|
||||
Search Topics
|
||||
-------------
|
||||
octosuite --method topics_search --query <query>
|
||||
|
||||
|
||||
Search Repositories
|
||||
-------------------
|
||||
octosuite --method repos_search --query <query>
|
||||
|
||||
|
||||
|
||||
Log Management
|
||||
==============
|
||||
|
||||
View logs
|
||||
---------
|
||||
octosuite --method view_logs
|
||||
|
||||
|
||||
Read log
|
||||
--------
|
||||
octosuite --method read_log --log_file <log_file>
|
||||
|
||||
|
||||
Delete log
|
||||
----------
|
||||
octosuite --method delete_log --log_file <log_file>
|
||||
|
||||
|
||||
Clear logs
|
||||
----------
|
||||
octosuite --method clear_logs
|
||||
|
||||
|
||||
|
||||
CSV Management
|
||||
==============
|
||||
|
||||
View CSV
|
||||
---------
|
||||
octosuite --method view_csv
|
||||
|
||||
|
||||
Read CSV
|
||||
--------
|
||||
octosuite --method read_csv --csv_file <csv_file>
|
||||
|
||||
|
||||
Delete CSV
|
||||
----------
|
||||
octosuite --method delete_csv --csv_file <csv_file>
|
||||
|
||||
|
||||
Clear CSV's
|
||||
-----------
|
||||
octosuite --method clear_csv
|
||||
"""
|
||||
|
||||
|
||||
def create_parser():
|
||||
parser = argparse.ArgumentParser(description='OCTOSUITE: Advanced GitHub osint framework — by Richard Mwewa | https://about.me/rly0nheart', usage=usage())
|
||||
parser.add_argument('-m', '--method', help='method', choices=['user_profile', 'user_repos', 'user_gists', 'user_orgs', 'user_events',
|
||||
'user_subscriptions', 'user_following', 'user_followers', 'user_follows',
|
||||
'org_profile', 'org_repos', 'org_events', 'org_member',
|
||||
'repo_profile', 'repo_contributors', 'repo_stargazers', 'repo_forks',
|
||||
'repo_issues', 'repo_releases', 'repo_path_contents', 'users_search', 'issues_search',
|
||||
'commits_search', 'topics_search', 'repos_search', 'view_logs', 'read_log', 'delete_log',
|
||||
'clear_logs', 'view_csv', 'read_csv', 'delete_csv', 'clear_csv', 'about', 'author'])
|
||||
parser.add_argument('-u', '--username', help='username')
|
||||
parser.add_argument('-uB', '--username_b', help='username_B (used with user_follows)')
|
||||
parser.add_argument('-o', '--organization', '--organisation', help='organi[sz]ation name')
|
||||
parser.add_argument('-r', '--repository', help='repository name')
|
||||
parser.add_argument('-p', '--path_name', help='path name (used with repo_path_contents)')
|
||||
parser.add_argument('-q', '--query', help='query (used with search methods)')
|
||||
parser.add_argument('-l', '--limit', help='output limit (used with methods that return results in bulk) (default: %(default)s)', default=10)
|
||||
parser.add_argument('-c', '--colors', '--colours', help='specify to run octosuite cli with colo[u]rs enabled', action='store_true')
|
||||
parser.add_argument('--csv_file', help='csv file (used with csv management methods)')
|
||||
parser.add_argument('--log_file', help='log file (used with logs management methods)')
|
||||
parser.add_argument('--log-to-csv', help='log output to a csv file', action='store_true', dest='log_csv')
|
||||
return parser
|
||||
|
||||
|
||||
parser = create_parser()
|
||||
args = parser.parse_args()
|
||||
|
||||
# This file is responsible for enabling/disabling colo[u]rs and configuring argparse in OctoSuite
|
||||
# This file gets called first at start up before any other file
|
||||
# config.py is the reason why users get to choose whether to enable/disable colo[u]rs, and call the program with command line arguments
|
||||
# delete this file (I dare you), the entire program breaks
|
||||
system_info = [("RAM", f"{str(round(psutil.virtual_memory().total / (1024.0 ** 3)))}GB"),
|
||||
("Node", platform.node()),
|
||||
("Release", platform.release()),
|
||||
("Version", platform.version()),
|
||||
("Processor", platform.processor()),
|
||||
("Architecture", platform.architecture())]
|
||||
first_banner = f"""
|
||||
OCTOSUITE © 2023 Richard Mwewa
|
||||
{datetime.now().strftime('%A %d %B %Y, %H:%M:%S%p')}
|
||||
|
||||
"""
|
||||
|
||||
if args.colors:
|
||||
header_title = "bold white"
|
||||
red = "[red]"
|
||||
white = "[white]"
|
||||
green = "[green]"
|
||||
yellow = "[yellow]"
|
||||
red_bold = "[white bold]"
|
||||
white_bold = "[white bold]"
|
||||
green_bold = "[green bold]"
|
||||
reset = "[/]"
|
||||
else:
|
||||
print(first_banner)
|
||||
system_tree = Tree(platform.system())
|
||||
for system_key, system_value in system_info:
|
||||
system_tree.add(f"{system_key}: {system_value}")
|
||||
xprint(system_tree)
|
||||
print("\n")
|
||||
try:
|
||||
color_chooser = Confirm.ask(f"Welcome, would you like to enable colo(u)rs for this session?")
|
||||
if color_chooser:
|
||||
header_title = "bold white"
|
||||
red = "[red]"
|
||||
white = "[white]"
|
||||
green = "[green]"
|
||||
yellow = "[yellow]"
|
||||
red_bold = "[white bold]"
|
||||
white_bold = "[white bold]"
|
||||
green_bold = "[green bold]"
|
||||
reset = "[/]"
|
||||
else:
|
||||
header_title = red = white = green = red_bold = white_bold = green_bold = reset = yellow = ""
|
||||
except KeyboardInterrupt:
|
||||
exit(f"[WARNING] Process interrupted with Ctrl+C.")
|
||||
|
||||
@@ -2,7 +2,7 @@ import os
|
||||
import csv
|
||||
import logging
|
||||
from rich import print as xprint
|
||||
from octosuite.log_roller import prompt_log_csv, logged_to_csv, logging_skipped
|
||||
from octosuite.log_roller import prompt_log_csv, logged_to_csv
|
||||
from octosuite.message_prefixes import PROMPT, WARNING, POSITIVE, NEGATIVE, INFO
|
||||
|
||||
|
||||
@@ -440,4 +440,3 @@ def log_commits_search(commit, query):
|
||||
|
||||
logging.info(logged_to_csv.format(file.name))
|
||||
xprint(f"{POSITIVE} {logged_to_csv.format(file.name)}")
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from rich.table import Table
|
||||
from rich import print as xprint
|
||||
from octosuite.colors import white, green, white_bold, green_bold, header_title, reset
|
||||
from octosuite.config import Tree, xprint, white, green, white_bold, green_bold, header_title, reset
|
||||
|
||||
# helper.py
|
||||
# This file holds the help text for available commands.
|
||||
@@ -146,6 +145,8 @@ def help_command():
|
||||
core_cmd_table = Table(show_header=True, header_style=header_title)
|
||||
core_cmd_table.add_column("Command", style="dim", width=12)
|
||||
core_cmd_table.add_column("Description")
|
||||
core_cmd_table.add_row("ls", "List contents of the specified directory")
|
||||
core_cmd_table.add_row("cd", "Move to specified directory")
|
||||
core_cmd_table.add_row("help", "Help menu")
|
||||
core_cmd_table.add_row("exit", "Close session")
|
||||
core_cmd_table.add_row("clear", "Clear screen")
|
||||
|
||||
@@ -16,7 +16,6 @@ info_not_found = "Information not found: {}, {}, {}"
|
||||
user_not_found = "User not found: @{}"
|
||||
org_not_found = "Organization not found: @{}"
|
||||
repo_or_user_not_found = "Repository or User not found: {}, @{}"
|
||||
prompt_log_csv = "Do you wish to log this output to a CSV file?"
|
||||
prompt_log_csv = "Would you like to log this output to a .csv file?"
|
||||
logged_to_csv = "Output logged: {}"
|
||||
logging_skipped = "Logging skipped: {}"
|
||||
limit_output = "Limit '{}' output to how many? (1-100)"
|
||||
|
||||
@@ -9,7 +9,7 @@ def octosuite():
|
||||
clear_screen()
|
||||
configure_logging()
|
||||
check_updates()
|
||||
if args:
|
||||
if args.method:
|
||||
"""
|
||||
Iterate over the argument_map and check if the passed command line argument matches any argument in it [argument_map],
|
||||
if there's a match, we return its method. If no match is found, we do nothing (which will return the usage).
|
||||
@@ -18,29 +18,31 @@ def octosuite():
|
||||
if args.method == argument:
|
||||
method()
|
||||
print("\n")
|
||||
|
||||
"""
|
||||
Main loop keeps octosuite running, this will break if Octosuite detects a KeyboardInterrupt (Ctrl+C)
|
||||
or if the 'exit' command is entered.
|
||||
"""
|
||||
xprint(banner()[0], banner()[1])
|
||||
while True:
|
||||
command_input = Prompt.ask(f"{white}┌──({red}{getpass.getuser()}{white}@{red}octosuite{white})\n├──[~{green}{os.getcwd()}{white}]\n└╼ {reset}")
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
"""
|
||||
Iterate over the command_map and check if the user input matches any command in it [command_map],
|
||||
if there's a match, we return its method. If no match is found, we ignore it.
|
||||
Main loop keeps octosuite running, this will break if Octosuite detects a KeyboardInterrupt (Ctrl+C)
|
||||
or if the 'exit' command is entered.
|
||||
"""
|
||||
if command_input[:2] == 'cd':
|
||||
os.chdir(command_input[3:])
|
||||
elif command_input[:2] == 'ls':
|
||||
os.system(f'dir {command_input[3:]}' if os.name == 'nt' else f'ls {command_input[3:]}')
|
||||
else:
|
||||
for command, method in run.command_map:
|
||||
if command_input == command:
|
||||
method()
|
||||
print("\n")
|
||||
else:
|
||||
pass
|
||||
xprint(banner()[0], banner()[1])
|
||||
while True:
|
||||
command_input = Prompt.ask(f"{white}┌──({red}{getpass.getuser()}{white}@{red}octosuite{white})\n├──[~{green}{os.getcwd()}{white}]\n└╼{reset}")
|
||||
"""
|
||||
Iterate over the command_map and check if the user input matches any command in it [command_map],
|
||||
if there's a match, we return its method. If no match is found, we ignore it.
|
||||
"""
|
||||
if command_input[:2] == 'cd':
|
||||
os.chdir(command_input[3:])
|
||||
elif command_input[:2] == 'ls':
|
||||
os.system(f'dir {command_input[3:]}' if os.name == 'nt' else f'ls {command_input[3:]}')
|
||||
else:
|
||||
for command, method in run.command_map:
|
||||
if command_input == command:
|
||||
method()
|
||||
print("\n")
|
||||
else:
|
||||
pass
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logging.warning(ctrl_c)
|
||||
|
||||
@@ -10,14 +10,14 @@ import platform
|
||||
import subprocess
|
||||
from datetime import datetime
|
||||
from octosuite.banner import version_tag, banner
|
||||
from octosuite.config import Tree, Text, Table, Prompt, xprint, create_parser, args, red, white, green, yellow, header_title, reset
|
||||
from octosuite.config import Tree, Text, Table, Prompt, Confirm, xprint, create_parser, args, red, white, green, yellow, header_title, reset
|
||||
from octosuite.message_prefixes import ERROR, WARNING, PROMPT, POSITIVE, NEGATIVE, INFO # wondering why I name all the variables instead of just using the * wildcard?, because it's the pythonic way lol
|
||||
# seriously now, the reason why I am doing this, is so that you know exactly what I am importing from a named module :)
|
||||
from octosuite.helper import help_command, source_command, search_command, user_command, repo_command, \
|
||||
logs_command, csv_command, org_command, source, org, repo, user, search, logs, csv
|
||||
from octosuite.log_roller import ctrl_c, error, session_opened, session_closed, viewing_logs, viewing_csv, \
|
||||
deleted, reading, file_downloading, file_downloaded, info_not_found, \
|
||||
user_not_found, org_not_found, repo_or_user_not_found, limit_output, prompt_log_csv, logging_skipped
|
||||
user_not_found, org_not_found, repo_or_user_not_found, limit_output, prompt_log_csv
|
||||
from octosuite.csv_loggers import log_org_profile, log_user_profile, log_repo_profile, log_repo_path_contents, \
|
||||
log_repo_contributors, log_repo_stargazers, log_repo_forks, log_repo_issues, log_repo_releases, log_org_repos, \
|
||||
log_org_profile, log_user_repos, log_user_gists, log_user_orgs, log_user_events, log_user_subscriptions, \
|
||||
@@ -88,7 +88,7 @@ def delete_csv():
|
||||
if args.csv_file:
|
||||
csv_file = args.csv_file
|
||||
else:
|
||||
csv_file = Prompt.ask(f"{green}csv {white}(filename){reset}")
|
||||
csv_file = Prompt.ask(f"{green}.csv {white}(filename){reset}")
|
||||
os.remove(os.path.join("output", csv_file))
|
||||
logging.info(deleted.format(csv_file))
|
||||
xprint(f"{POSITIVE} {deleted.format(csv_file)}")
|
||||
@@ -96,8 +96,8 @@ def delete_csv():
|
||||
|
||||
# Clear csv files
|
||||
def clear_csv():
|
||||
prompt = Prompt.ask(f"{PROMPT} This will clear all {len(os.listdir('output'))} csv files, continue?", choices=['yes', 'no'])
|
||||
if prompt == "yes":
|
||||
clear_csv_prompt = Confirm.ask(f"{PROMPT} This will clear all {len(os.listdir('output'))} csv files, continue?")
|
||||
if clear_csv_prompt:
|
||||
shutil.rmtree('output', ignore_errors=True)
|
||||
xprint(f"{INFO} csv files cleared successfully!")
|
||||
else:
|
||||
@@ -121,7 +121,7 @@ def read_csv():
|
||||
if args.csv_file:
|
||||
csv_file = args.csv_file
|
||||
else:
|
||||
csv_file = Prompt.ask(f"{green}csv {white}(filename){reset}")
|
||||
csv_file = Prompt.ask(f"{green}.csv {white}(filename){reset}")
|
||||
with open(os.path.join("output", csv_file), "r") as file:
|
||||
logging.info(reading.format(csv_file))
|
||||
text = Text(file.read())
|
||||
@@ -145,7 +145,7 @@ def read_log():
|
||||
if args.log_file:
|
||||
log_file = args.log_file
|
||||
else:
|
||||
log_file = Prompt.ask(f"{green}log date{white} (eg. 2022-04-27 10:09:36AM){reset}")
|
||||
log_file = Prompt.ask(f"{green}.log date{white} (eg. 2022-04-27 10:09:36AM){reset}")
|
||||
with open(os.path.join(".logs", log_file + ".log"), "r") as log:
|
||||
logging.info(reading.format(log_file))
|
||||
xprint("\n" + log.read())
|
||||
@@ -156,7 +156,7 @@ def delete_log():
|
||||
if args.log_file:
|
||||
log_file = args.log_file
|
||||
else:
|
||||
log_file = Prompt.ask(f"{green}log date{white} (eg. 2022-04-27 10:09:36AM){reset}")
|
||||
log_file = Prompt.ask(f"{green}.log date{white} (eg. 2022-04-27 10:09:36AM){reset}")
|
||||
os.remove(os.path.join(".logs", log_file))
|
||||
logging.info(deleted.format(log_file))
|
||||
xprint(f"{POSITIVE} {deleted.format(log_file)}")
|
||||
@@ -164,8 +164,8 @@ def delete_log():
|
||||
|
||||
# Clear logs
|
||||
def clear_logs():
|
||||
prompt = Prompt.ask(f"{PROMPT} This will clear all {len(os.listdir('output'))} log files, continue?", choices=['yes', 'no'])
|
||||
if prompt == "yes":
|
||||
clear_logs_prompt = Confirm.ask(f"{PROMPT} This will clear all {len(os.listdir('output'))} log files, continue?")
|
||||
if clear_logs_prompt:
|
||||
shutil.rmtree('.logs', ignore_errors=True)
|
||||
xprint(f"{INFO} .log files cleared successfully!")
|
||||
exit()
|
||||
@@ -175,8 +175,8 @@ def clear_logs():
|
||||
|
||||
# Exit session
|
||||
def exit_session():
|
||||
exit_prompt = Prompt.ask(f"{PROMPT} This will close the current session, continue?", choices=['yes', 'no'])
|
||||
if exit_prompt == "yes":
|
||||
exit_prompt = Confirm.ask(f"{PROMPT} This will close the current session, continue?")
|
||||
if exit_prompt:
|
||||
logging.info(session_closed.format(datetime.now()))
|
||||
xprint(f"{INFO} {session_closed.format(datetime.now())}")
|
||||
exit()
|
||||
@@ -521,7 +521,7 @@ class Octosuite:
|
||||
if args.organization:
|
||||
organization = args.organization
|
||||
else:
|
||||
organization = Prompt.ask(f"{white}@{green}Organization{reset}")
|
||||
organization = Prompt.ask(f"{white}@{green}Organi[sz]ation{reset}")
|
||||
response = requests.get(f"{self.endpoint}/orgs/{organization}")
|
||||
if response.status_code == 404:
|
||||
xprint(f"{NEGATIVE} {org_not_found.format(organization)}")
|
||||
@@ -530,7 +530,9 @@ class Octosuite:
|
||||
for attr in self.org_attrs:
|
||||
org_profile_tree.add(f"{self.org_attr_dict[attr]}: {response.json()[attr]}")
|
||||
xprint(org_profile_tree)
|
||||
log_org_profile(response)
|
||||
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_org_profile(response)
|
||||
else:
|
||||
xprint(response.json())
|
||||
|
||||
@@ -550,7 +552,7 @@ class Octosuite:
|
||||
xprint(user_profile_tree)
|
||||
|
||||
# Logging output to a csv file
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_user_profile(response)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -572,7 +574,7 @@ class Octosuite:
|
||||
repo_profile_tree.add(f"{self.repo_attr_dict[attr]}: {response.json()[attr]}")
|
||||
xprint(repo_profile_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_repo_profile(response)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -621,7 +623,7 @@ class Octosuite:
|
||||
contributor_tree.add(f"{self.user_attr_dict[attr]}: {contributor[attr]}")
|
||||
xprint(contributor_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_repo_contributors(contributor, repo_name)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -648,7 +650,7 @@ class Octosuite:
|
||||
stargazer_tree.add(f"{self.user_attr_dict[attr]}: {stargazer[attr]}")
|
||||
xprint(stargazer_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_repo_stargazers(stargazer, repo_name)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -675,7 +677,7 @@ class Octosuite:
|
||||
fork_tree.add(f"{self.repo_attr_dict[attr]}: {fork[attr]}")
|
||||
xprint(fork_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_repo_forks(fork, count)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -729,7 +731,7 @@ class Octosuite:
|
||||
xprint(releases_tree)
|
||||
xprint(release['body'])
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_repo_releases(release, repo_name)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -740,7 +742,7 @@ class Octosuite:
|
||||
organization = args.organization
|
||||
limit = args.limit
|
||||
else:
|
||||
organization = Prompt.ask(f"{white}@{green}Organization{reset}")
|
||||
organization = Prompt.ask(f"{white}@{green}Organi[sz]ation{reset}")
|
||||
limit = Prompt.ask(limit_output.format("organization repositories"))
|
||||
response = requests.get(f"{self.endpoint}/orgs/{organization}/repos?per_page={limit}")
|
||||
if response.status_code == 404:
|
||||
@@ -752,7 +754,7 @@ class Octosuite:
|
||||
repos_tree.add(f"{self.repo_attr_dict[attr]}: {repository[attr]}")
|
||||
xprint(repos_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}") == "yes":
|
||||
log_org_repos(repository, organization)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -763,7 +765,7 @@ class Octosuite:
|
||||
organization = args.organization
|
||||
limit = args.limit
|
||||
else:
|
||||
organization = Prompt.ask(f"{white}@{green}Organization{reset}")
|
||||
organization = Prompt.ask(f"{white}@{green}Organi[sz]ation{reset}")
|
||||
limit = Prompt.ask(limit_output.format("organization events"))
|
||||
response = requests.get(f"{self.endpoint}/orgs/{organization}/events?per_page={limit}")
|
||||
if response.status_code == 404:
|
||||
@@ -785,7 +787,7 @@ class Octosuite:
|
||||
organization = args.organization
|
||||
username = args.username
|
||||
else:
|
||||
organization = Prompt.ask(f"{white}@{green}Organization{reset}")
|
||||
organization = Prompt.ask(f"{white}@{green}Organi[sz]ation{reset}")
|
||||
username = Prompt.ask(f"{white}@{green}Username{reset}")
|
||||
response = requests.get(f"{self.endpoint}/orgs/{organization}/public_members/{username}")
|
||||
if response.status_code == 204:
|
||||
@@ -811,7 +813,7 @@ class Octosuite:
|
||||
repos_tree.add(f"{self.repo_attr_dict[attr]}: {repository[attr]}")
|
||||
xprint(repos_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_user_repos(repository, username)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -836,7 +838,7 @@ class Octosuite:
|
||||
gists_tree.add(f"{self.gists_attr_dict[attr]}: {gist[attr]}")
|
||||
xprint(gists_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_user_gists(gist)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -861,7 +863,7 @@ class Octosuite:
|
||||
org_tree.add(f"{self.user_orgs_attr_dict[attr]}: {organization[attr]}")
|
||||
xprint(org_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_user_orgs(organization, username)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -910,7 +912,7 @@ class Octosuite:
|
||||
subscriptions_tree.add(f"{self.repo_attr_dict[attr]}: {repository[attr]}")
|
||||
xprint(subscriptions_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_user_subscriptions(repository, username)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -935,7 +937,7 @@ class Octosuite:
|
||||
following_tree.add(f"{self.user_attr_dict[attr]}: {user[attr]}")
|
||||
xprint(following_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_user_following(user, username)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -960,7 +962,7 @@ class Octosuite:
|
||||
followers_tree.add(f"{self.user_attr_dict[attr]}: {follower[attr]}")
|
||||
xprint(followers_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_user_followers(follower, username)
|
||||
else:
|
||||
xprint(response.json())
|
||||
@@ -994,7 +996,7 @@ class Octosuite:
|
||||
users_search_tree.add(f"{self.user_attr_dict[attr]}: {user[attr]}")
|
||||
xprint(users_search_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_users_search(user, query)
|
||||
|
||||
# Repository search
|
||||
@@ -1012,7 +1014,7 @@ class Octosuite:
|
||||
repos_search_tree.add(f"{self.repo_attr_dict[attr]}: {repository[attr]}")
|
||||
xprint(repos_search_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_repos_search(repository, query)
|
||||
|
||||
# Topics search
|
||||
@@ -1030,7 +1032,7 @@ class Octosuite:
|
||||
topics_search_tree.add(f"{self.topic_attr_dict[attr]}: {topic[attr]}")
|
||||
xprint(topics_search_tree)
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_topics_search(topic, query)
|
||||
|
||||
# Issue search
|
||||
@@ -1049,7 +1051,7 @@ class Octosuite:
|
||||
xprint(issues_search_tree)
|
||||
xprint(issue['body'])
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_issues_search(issue, query)
|
||||
|
||||
# Commits search
|
||||
@@ -1072,7 +1074,7 @@ class Octosuite:
|
||||
xprint(commits_search_tree)
|
||||
xprint(commit['commit']['message'])
|
||||
|
||||
if args.log_csv or Prompt.ask(f"{PROMPT} {prompt_log_csv}", choices=['yes', 'no']) == "yes":
|
||||
if args.log_csv or Confirm.ask(f"\n{PROMPT} {prompt_log_csv}"):
|
||||
log_commits_search(commit, query)
|
||||
|
||||
# Downloading release tarball
|
||||
|
||||
Reference in New Issue
Block a user