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

modifying the help messages #68

Merged
merged 14 commits into from
Jan 8, 2025
12 changes: 6 additions & 6 deletions .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ jobs:
run: pytest Quorum/tests --maxfail=1 --disable-warnings --tb=short

- name: Run Quorum setup
run: Quorum setup --working_dir workdir
run: quorum setup --working-dir workdir

- name: Init working directory
run: |
Expand All @@ -51,20 +51,20 @@ jobs:

- name: Single Address Test
working-directory: workdir
run: Quorum validate-address --customer Aave --chain Ethereum --proposal_address 0xAD6c03BF78A3Ee799b86De5aCE32Bb116eD24637
run: quorum validate-address --protocol-name Aave --chain Ethereum --payload-address 0xAD6c03BF78A3Ee799b86De5aCE32Bb116eD24637

- name: Batch Test
working-directory: workdir
run: Quorum validate-batch --config regression.json
run: quorum validate-batch --config regression.json

- name: Proposal ID Test
working-directory: workdir
run: Quorum validate-by-id --proposal_id 137 --customer Aave
run: quorum validate-by-id --proposal-id 137 --protocol-name Aave

- name: IPFS Test
working-directory: workdir
run: Quorum validate-ipfs --proposal_id 20 --chain Scroll --proposal_address 0x2B25cb729D90630395Cd3140f3460a73A41Fe5f0
run: quorum validate-ipfs --proposal-id 20 --chain Scroll --payload-address 0x2B25cb729D90630395Cd3140f3460a73A41Fe5f0

- name: Create Report
working-directory: workdir
run: Quorum create-report --proposal_id 137
run: quorum create-report --proposal_id 137
42 changes: 21 additions & 21 deletions Quorum/entry_points/cli_arguments.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,73 +7,73 @@


class Argument(BaseModel):
name: str
name: list[str]
type: Any
required: bool
help: str
default: Any | None = None
nargs: str | None = None


CUSTOMER_ARGUMENT = Argument(
name='--customer',
PROTOCOL_NAME_ARGUMENT = Argument(
name=['--protocol-name', '--protocol_name'],
type=str,
required=True,
help="Customer name or identifier."
help="Protocol name or identifier."
)


CHAIN_ARGUMENT = Argument(
name='--chain',
name=['--chain'],
type=Chain,
required=True,
help="Blockchain chain to target."
help="Blockchain to target."
)


PROPOSAL_ADDRESS_ARGUMENT = Argument(
name='--proposal_address',
PAYLOAD_ADDRESS_ARGUMENT = Argument(
name=['--payload-address', '--payload_address'],
type=arg_valid.validate_address,
required=True,
help="Ethereum proposal address."
help="On-chain payload address."
)


PROPOSAL_ID_ARGUMENT = Argument(
name='--proposal_id',
name=['--proposal-id', '--proposal_id'],
type=int,
required=True,
help="ID of the proposal."
help="Identifier of the proposal."
)


CONFIG_ARGUMENT = Argument(
name='--config',
name=['--config'],
type=arg_valid.load_config,
required=True,
help="Path to the JSON configuration file."
help="Path to the Json config file."
)


TEMPLATE_ARGUMENT = Argument(
name='--template',
name=['--template'],
type=Path,
required=False,
help="Path to the Jinja2 template file.",
help="Path to a Jinja2 template file that defines the output report format.",
default=Path(__file__).parent.parent / 'auto_report/AaveReportTemplate.md.j2'
)


GENERATE_REPORT_PATH_ARGUMENT = Argument(
name='--generate_report_path',
OUTPUT_PATH_ARGUMENT = Argument(
name=['--output-path', '--output_path'],
type=Path,
required=False,
help="Path to save the generated report."
help="The path to which the report is saved."
)


PROMPT_TEMPLATES_ARGUMENT = Argument(
name='--prompt_templates',
name=['--prompt-templates', '--prompt_templates'],
type=str,
required=False,
help="Jinja templates for prompting the LLM.",
Expand All @@ -83,9 +83,9 @@ class Argument(BaseModel):


WORKING_DIR_ARGUMENT = Argument(
name='--working_dir',
name=['--working-dir', '--working_dir'],
type=Path,
required=False,
help="Where to create the Quorum project.",
help="Specifies the path in which the project will be created. \n Note that all validations will have to run from this directory!",
default=Path.cwd() / 'quorum_project'
)
4 changes: 2 additions & 2 deletions Quorum/entry_points/implementations/check_proposal.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def run_single(args: argparse.Namespace) -> None:
The function creates customer and proposal configurations based on the input arguments
and executes a batch run for the single proposal.
"""
customer, chain, proposal_address = args.customer, args.chain, args.proposal_address
customer_config = CustomerConfig(customer=customer, payload_addresses=[PayloadAddresses(chain=chain, addresses=[proposal_address])])
protocol_name, chain, payload_address = args.protocol_name, args.chain, args.payload_address
customer_config = CustomerConfig(customer=protocol_name, payload_addresses=[PayloadAddresses(chain=chain, addresses=[payload_address])])
prop_config = ProposalConfig(customers_config=[customer_config])
run_customer_proposal_validation(prop_config)
8 changes: 4 additions & 4 deletions Quorum/entry_points/implementations/check_proposal_id.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ def run_proposal_id(args: argparse.Namespace) -> None:
Returns:
None
"""
customer, proposal_id = args.customer, args.proposal_id
customer_key = customer.lower()
protocol_name, proposal_id = args.protocol_name, args.proposal_id
customer_key = protocol_name.lower()
if customer_key not in CUSTOMER_TO_API:
raise ValueError(f"Customer '{customer}' is not supported. Supported customers: {list(CUSTOMER_TO_API.keys())}.")
raise ValueError(f"Customer '{protocol_name}' is not supported. Supported customers: {list(CUSTOMER_TO_API.keys())}.")

api = CUSTOMER_TO_API[customer_key]
payloads_addresses = api.get_all_payloads_addresses(proposal_id)
config = ProposalConfig(customers_config=[CustomerConfig(customer=customer, payload_addresses=payloads_addresses)])
config = ProposalConfig(customers_config=[CustomerConfig(customer=protocol_name, payload_addresses=payloads_addresses)])

run_customer_proposal_validation(config)
8 changes: 4 additions & 4 deletions Quorum/entry_points/implementations/create_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ def run_create_report(args: argparse.Namespace):
if not args.template.exists():
raise FileNotFoundError(f'could not find template at {args.template}.')

if args.generate_report_path is None:
args.generate_report_path = Path(f'v3-{args.proposal_id}.md')
if args.output_path is None:
args.output_path = Path(f'v3-{args.proposal_id}.md')


pp.pprint(f'Generating a report using template in {args.template}', pp.Colors.INFO)
Expand All @@ -43,7 +43,7 @@ def run_create_report(args: argparse.Namespace):

report = template.render(tags)

with open(args.generate_report_path, 'w') as f:
with open(args.output_path, 'w') as f:
f.write(report)

pp.pprint(f'Created report at {args.generate_report_path}.', pp.Colors.SUCCESS)
pp.pprint(f'Created report at {args.output_path}.', pp.Colors.SUCCESS)
2 changes: 1 addition & 1 deletion Quorum/entry_points/implementations/ipfs_validator.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def run_ipfs_validator(args: argparse.Namespace):

# Initialize Chain API and fetch source codes
block_explorer = ChainAPI(args.chain)
source_codes = block_explorer.get_source_code(args.proposal_address)
source_codes = block_explorer.get_source_code(args.payload_address)
if not source_codes:
raise ValueError("No source codes found for the given proposal address.")
payload = '\n'.join(source_codes[0].file_content)
Expand Down
54 changes: 32 additions & 22 deletions Quorum/entry_points/quorum_cli.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
# Quorum/entry_points/quorum_cli.py

import argparse
import argcomplete
from pydantic import BaseModel
from typing import Callable
from typing import Callable, Optional

import Quorum.entry_points.cli_arguments as cli_args
from Quorum.entry_points.implementations.check_proposal import run_single
Expand All @@ -18,60 +19,66 @@ class Command(BaseModel):
help: str
arguments: list[cli_args.Argument]
func: Callable[[argparse.Namespace], None]
aliases: Optional[list[str]] = []


COMMAND_REGISTRY = [
Command(
name="setup",
help="Sets up Quorum environment for quick start.",
arguments=[cli_args.WORKING_DIR_ARGUMENT],
func=run_setup_quorum
),
Command(
name="validate-address",
help="Run a single payload proposal check.",
aliases=["validate_address"],
help="Validate a single on-chain payload by address.",
arguments=[
cli_args.CUSTOMER_ARGUMENT,
cli_args.PROTOCOL_NAME_ARGUMENT,
cli_args.CHAIN_ARGUMENT,
cli_args.PROPOSAL_ADDRESS_ARGUMENT
cli_args.PAYLOAD_ADDRESS_ARGUMENT
],
func=run_single
),
Command(
name="validate-batch",
aliases=["validate_batch"],
help="Run a batch check from a JSON config file.",
arguments=[cli_args.CONFIG_ARGUMENT],
func=run_config
),
Command(
name="validate-by-id",
help="Check proposals by proposal ID.",
aliases=["validate_by_id"],
help="Validate a single on-chain proposal by passing the protocol name and id.",
arguments=[
cli_args.CUSTOMER_ARGUMENT,
cli_args.PROTOCOL_NAME_ARGUMENT,
cli_args.PROPOSAL_ID_ARGUMENT
],
func=run_proposal_id
),
Command(
name="create-report",
help="Generate a proposal report.",
arguments=[
cli_args.PROPOSAL_ID_ARGUMENT,
cli_args.TEMPLATE_ARGUMENT,
cli_args.GENERATE_REPORT_PATH_ARGUMENT
],
func=run_create_report
),
Command(
name="validate-ipfs",
aliases=["validate_ipfs"],
help="Compare IPFS content with a proposal's payload.",
arguments=[
cli_args.PROPOSAL_ID_ARGUMENT,
cli_args.CHAIN_ARGUMENT,
cli_args.PROPOSAL_ADDRESS_ARGUMENT,
cli_args.PAYLOAD_ADDRESS_ARGUMENT,
cli_args.PROMPT_TEMPLATES_ARGUMENT
],
func=run_ipfs_validator
),
Command(
name="setup",
help="Initial Quorum environment setup.",
arguments=[cli_args.WORKING_DIR_ARGUMENT],
func=run_setup_quorum
name="generate-report",
aliases=["generate_report"],
help="Generates a proposal report based on provided JINJA2 template.",
arguments=[
cli_args.PROPOSAL_ID_ARGUMENT,
cli_args.TEMPLATE_ARGUMENT,
cli_args.OUTPUT_PATH_ARGUMENT
],
func=run_create_report
)
]

Expand All @@ -87,7 +94,7 @@ def add_arguments(parser: argparse.ArgumentParser, arguments: list[cli_args.Argu
for arg in arguments:
arg_dict = arg.model_dump()
name = arg_dict.pop("name")
parser.add_argument(name, **arg_dict)
parser.add_argument(*name, **arg_dict)


def main():
Expand All @@ -102,11 +109,14 @@ def main():
for subcmd in COMMAND_REGISTRY:
subparser = subparsers.add_parser(
subcmd.name,
aliases=subcmd.aliases,
help=subcmd.help
)
add_arguments(subparser, subcmd.arguments)
subparser.set_defaults(func=subcmd.func)

argcomplete.autocomplete(parser)

args = parser.parse_args()

# Dispatch to the appropriate function
Expand Down
2 changes: 1 addition & 1 deletion Quorum/tests/test_auto_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def test_auto_report():
args = argparse.Namespace(
proposal_id=132,
template=Path('Quorum') / 'auto_report' / 'AaveReportTemplate.md.j2',
generate_report_path=None
output_path=None
)

create_report.run_create_report(args)
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,11 @@ This action will:
- **`execution.json`**: Specify proposal addresses to be checked for different chains.
- **`README.md`**: An auto-generated resource explaining your next steps.

3. **Optional: Command Autocompletion**
Enable Quorum command autocompletion by adding this line to your shell profile (`.bashrc` or `.zshrc`):
```bash
eval "$(register-python-argcomplete quorum)"
```
---

## Clarifications
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Homepage = "https://github.com/Certora/Quorum"
Source = "https://github.com/Certora/Quorum"

[project.scripts]
Quorum = "Quorum.entry_points.quorum_cli:main"
quorum = "Quorum.entry_points.quorum_cli:main"

[tool.setuptools]
include-package-data = true
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ langgraph
langchain_community
python-dotenv
json5
argcomplete
2 changes: 1 addition & 1 deletion version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
20250108.112835.691155
20250108.125906.135099
Loading