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

Release v2.3.0 #122

Merged
merged 16 commits into from
Feb 1, 2024
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
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
DOCKER_TAG=v2.1.0
DOCKER_TAG=v2.2.0
REPOSITORY_DOCKER_URL=ghcr.io/nasa-ammos

AERIE_USERNAME=aerie
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
environment: integration-test-workflow
strategy:
matrix:
python-version: [ "3.6.15", "3.7", "3.8", "3.9", "3.10", "3.11" ]
python-version: ["3.6.15", "3.7", "3.8", "3.9", "3.10", "3.11"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand All @@ -46,8 +46,8 @@ jobs:
environment: integration-test-workflow
strategy:
matrix:
python-version: [ "3.6.15", "3.11" ]
aerie-version: ["2.1.0"]
python-version: ["3.6.15", "3.11"]
aerie-version: ["2.2.0"]
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
Expand Down Expand Up @@ -86,4 +86,4 @@ jobs:
docker ps -a
- name: Prune volumes
if: always()
run: docker volume prune --force
run: docker volume prune --force
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "aerie-cli"
version = "2.2.0"
version = "2.3.0"
description = "A CLI application and Python API for interacting with Aerie."
authors = []
license = "MIT"
Expand Down
108 changes: 89 additions & 19 deletions src/aerie_cli/aerie_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ def get_activity_plan_by_id(self, plan_id: int, full_args: str = None) -> Activi
simulations{
id
}
tags {
tag {
id
name
}
}
activity_directives(order_by: { start_offset: asc }) {
id
name
Expand Down Expand Up @@ -92,6 +98,12 @@ def list_all_activity_plans(self) -> List[ActivityPlanRead]:
simulations{
id
}
tags {
tag {
id
name
}
}
}
}
"""
Expand Down Expand Up @@ -147,6 +159,60 @@ def get_plan_id_by_sim_id(self, simulation_dataset_id: int) -> int:
simulation_dataset_id=simulation_dataset_id
)
return resp['simulation']['plan']['id']

def get_tag_id_by_name(self, tag_name: str):
get_tags_by_name_query = """
query GetTagByName($name: String) {
tags(where: {name: {_eq: $name}}) {
id
}
}
"""

#make default color of tag white
create_new_tag = """
mutation CreateNewTag($name: String, $color: String = "#FFFFFF") {
insert_tags_one(object: {name: $name, color: $color}) {
id
}
}
"""

resp = self.aerie_host.post_to_graphql(
get_tags_by_name_query,
name=tag_name
)

#if a tag with the specified name exists then returns the ID, else creates a new tag with this name
if len(resp) > 0:
return resp[0]["id"]
else:
new_tag_resp = self.aerie_host.post_to_graphql(
create_new_tag,
name=tag_name
)

return new_tag_resp["id"]

def add_plan_tag(self, plan_id: int, tag_name: str):
add_tag_to_plan = """
mutation AddTagToPlan($plan_id: Int, $tag_id: Int) {
insert_plan_tags(objects: {plan_id: $plan_id, tag_id: $tag_id}) {
returning {
tag_id
}
}
}
"""

#add tag to plan
resp = self.aerie_host.post_to_graphql(
add_tag_to_plan,
plan_id=plan_id,
tag_id=self.get_tag_id_by_name(tag_name)
)

return resp['returning'][0]

def create_activity_plan(
self, model_id: int, plan_to_create: ActivityPlanCreate
Expand All @@ -167,6 +233,11 @@ def create_activity_plan(
)
plan_id = plan_resp["id"]
plan_revision = plan_resp["revision"]

#add plan tags if exists from plan_to_create
for tag in plan_to_create.tags:
self.add_plan_tag(plan_id, tag["tag"]["name"])

# This loop exists to make sure all anchor IDs are updated as necessary

# Deep copy activities so we can augment and pop from the list
Expand Down Expand Up @@ -782,6 +853,8 @@ def create_expansion_rule(
activity_name: str,
model_id: str,
command_dictionary_id: str,
name: str = None,
description: str = None
) -> int:
"""Submit expansion logic to an Aerie instance

Expand All @@ -790,34 +863,31 @@ def create_expansion_rule(
activity_name (str): Name of the activity
model_id (str): Aerie model ID
command_dictionary_id (str): Aerie command dictionary ID
name (str, Optional): Name of the expansion rule
description (str, Optional): Description of the expansion rule

Returns:
int: Expansion Rule ID in Aerie
"""

create_expansion_logic_query = """
mutation UploadExpansionLogic(
$activity_type_name: String!
$expansion_logic: String!
$command_dictionary_id: Int!
$mission_model_id: Int!
) {
addCommandExpansionTypeScript(
activityTypeName: $activity_type_name
expansionLogic: $expansion_logic
authoringCommandDictionaryId: $command_dictionary_id
authoringMissionModelId: $mission_model_id
) {
mutation CreateExpansionRule($rule: expansion_rule_insert_input!) {
createExpansionRule: insert_expansion_rule_one(object: $rule) {
id
}
}
"""
rule = {
"activity_type": activity_name,
"authoring_command_dict_id": command_dictionary_id,
"authoring_mission_model_id": model_id,
"expansion_logic": expansion_logic,
"name": name if (name is not None) else activity_name + arrow.utcnow().format("_YYYY-MM-DDTHH-mm-ss"),
"description": description if (description is not None) else ""
}
data = self.aerie_host.post_to_graphql(
create_expansion_logic_query,
activity_type_name=activity_name,
expansion_logic=expansion_logic,
mission_model_id=model_id,
command_dictionary_id=command_dictionary_id,
rule=rule
)

return data["id"]
Expand Down Expand Up @@ -1642,12 +1712,12 @@ def get_constraint_violations(self, plan_id):
get_violations_query = """
query ($plan_id: Int!) {
constraintResponses: constraintViolations(planId: $plan_id) {
constraintId
constraintName
type
success
results {
constraintId
constraintName
resourceIds
type
gaps {
end
start
Expand Down
106 changes: 105 additions & 1 deletion src/aerie_cli/commands/expansion.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
from pathlib import Path
import fnmatch

import arrow

from rich.console import Console
from rich.table import Table

from aerie_cli.commands.command_context import CommandContext
from aerie_cli.utils.prompts import select_from_list
from aerie_cli.schemas.client import ExpansionRun
from aerie_cli.schemas.client import ExpansionRun, ExpansionDeployConfiguration

app = typer.Typer()
sequences_app = typer.Typer()
Expand All @@ -19,6 +21,108 @@
app.add_typer(runs_app, name='runs', help='Commands for expansion runs')
app.add_typer(sets_app, name='sets', help='Commands for expansion sets')

# === Bulk Deploy Command ===

@app.command('deploy')
def bulk_deploy(
model_id: int = typer.Option(
..., '--model-id', '-m', prompt='Mission Model ID',
help='Mission Model ID'
),
command_dictionary_id: int = typer.Option(
..., '--command-dict-id', '-d', prompt='Command Dictionary ID',
help='Command Dictionary ID'
),
config_file: str = typer.Option(
..., "--config-file", "-c", prompt="Configuration file",
help="Deploy configuration JSON file"
),
rules_path: Path = typer.Option(
Path.cwd(), help="Path to folder containing expansion rule files"
),
time_tag: bool = typer.Option(False, help="Append time tags to create unique expansion rule/set names")
):
"""
Bulk deploy command expansion rules and sets to an Aerie instance according to a JSON configuration file.

The configuration file contains a list of rules and a list of sets:

```
{
"rules": [...],
"sets": [...]
}
```

Each rule must provide a unique rule name, the activity type name, and the name of the file with expansion logic:

```
{
"name": "Expansion Rule Name",
"activity_type": "Activity Type Name",
"file_name": "my_file.ts"
}
```

Each set must provide a unique set name and a list of rule names to add:

```
{
"name": "Expansion Set Name",
"rules": ["Expansion Rule Name", ...]
}
```
"""

client = CommandContext.get_client()

with open(Path(config_file), "r") as fid:
configuration: ExpansionDeployConfiguration = ExpansionDeployConfiguration.from_dict(json.load(fid))

name_suffix = arrow.utcnow().format("_YYYY-MM-DDTHH-mm-ss") if time_tag else ""

# Loop and upload all expansion rules
uploaded_rules = {}
for rule in configuration.rules:
try:
with open(rules_path.joinpath(rule.file_name), "r") as fid:
expansion_logic = fid.read()

rule_id = client.create_expansion_rule(
expansion_logic=expansion_logic,
activity_name=rule.activity_type,
model_id=model_id,
command_dictionary_id=command_dictionary_id,
name=rule.name + name_suffix
)
typer.echo(f"Created expansion rule {rule.name + name_suffix}: {rule_id}")
uploaded_rules[rule.name] = rule_id
except:
typer.echo(f"Failed to create expansion rule {rule.name}")

for set in configuration.sets:
try:
rule_ids = []
for rule_name in set.rules:
if rule_name in uploaded_rules.keys():
rule_ids.append(uploaded_rules[rule_name])
else:
typer.echo(f"No uploaded rule {rule_name} for set {set.name}")

assert len(rule_ids)

set_id = client.create_expansion_set(
command_dictionary_id=command_dictionary_id,
model_id=model_id,
expansion_ids=rule_ids,
name=set.name + name_suffix
)

typer.echo(f"Created expansion set {set.name + name_suffix}: {set_id}")
except:
typer.echo(f"Failed to create expansion set {set.name}")


# === Commands for expansion runs ===


Expand Down
6 changes: 6 additions & 0 deletions src/aerie_cli/schemas/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ class ApiActivityPlanRead(ApiActivityPlanBase):
converter=converters.optional(
lambda listOfDicts: [ApiActivityRead.from_dict(d) if isinstance(d, dict) else d for d in listOfDicts])
)
tags: Optional[List[Dict]] = field(
default = [],
converter=converters.optional(
lambda listOfDicts: [d for d in listOfDicts]
)
)


@define
Expand Down
Loading
Loading