Skip to content

Commit

Permalink
Merge pull request #122 from NASA-AMMOS/release--v2.3.0
Browse files Browse the repository at this point in the history
Release  v2.3.0
  • Loading branch information
cartermak authored Feb 1, 2024
2 parents ca9e426 + cc3e454 commit db8046c
Show file tree
Hide file tree
Showing 17 changed files with 339 additions and 32 deletions.
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

0 comments on commit db8046c

Please sign in to comment.