Release v0.2.0
Associated PR: #500
What changed?
In previous versions of AaC, plugins were defined in YAML using the model
root
key. We found that this didn't provide enough control over what the plugin
actually contributed (e.g. commands, definitions, and validations) which made
generating artifacts, code, etc less clear.
In version 0.2.0, we have added a plugin
root key which is used to define a
plugin and it's contributions. Additionally, the new structure adds extra
capabilities for defining commands with command groups, etc which allows us to
better control command structure.
Do these changes affect me?
This change will effect users that have created custom plugins or users that depend, in some way, on the plugin definition file - i.e. the file in which the plugin is defined using AaC constructs.
What do I need to do about it?
To migrate a plugin to use the new structure, consider the following example of a plugin as defined in version 0.1.11:
plugin.yaml
model:
name: test-plugin
description: test-plugin is a test plugin
behavior:
- name: test-plugin-command
type: command
description: Test plugin generation
input:
- name: architecture_file
type: file
python_type: str
description: An architecture-as-code file.
acceptance:
- scenario: Test some stuff
given:
- The contents of {{test-plugin-command.input.architecture_file}} represents a valid system architecture.
when:
- The command is run
then:
- Then stuff happens
---
enum:
name: CommandEnum
values:
- VALUE_A
- VALUE_B
- VALUE_C
---
ext:
name: AnotherPrimitive
type: Primitives
enumExt:
add:
- complex
---
schema:
name: TestPluginData
fields:
- name: value1
type: string
- name: value2
type: string
validation:
- name: Required fields are present
arguments:
- value1
---
validation:
name: Test definition validation
description: A test definition validator.
behavior:
- name: Validate a definition
type: REQUEST_RESPONSE
input:
- name: input
type: ValidatorInput
output:
- name: results
type: ValidatorOutput
acceptance:
- scenario: Successfully validate the definition
given:
- The ValidatorInput content consists of valid AaC definitions.
when:
- The validator plugin is executed.
then:
- The ValidatorOutput does not indicate any errors.
- The ValidatorOutput does not indicate any warnings.
- The ValidatorOutput indicates the validator plugin under test is valid.
---
validation:
name: Test primitive validation
description: A test primitive validator.
behavior:
- name: Validate a primitive
type: REQUEST_RESPONSE
input:
- name: input
type: ValidatorInput
output:
- name: results
type: ValidatorOutput
acceptance:
- scenario: Successfully validate the primitive
given:
- The ValidatorInput content consists of a valid primitive value.
when:
- The validator plugin is executed.
then:
- The ValidatorOutput does not indicate any errors.
- The ValidatorOutput does not indicate any warnings.
- The ValidatorOutput indicates the validator plugin under test is valid.
In version 0.2.0, the plugin could be defined as follows:
plugin.yaml
plugin:
name: Test Plugin
description: |
A test plugin with a contributed definition, a command, a definition
validation, and a primitive validation.
definitionSources:
- ./definitions.yaml
- ./test-definition-validation.yaml
- ./test-primitive-validation.yaml
definitionValidations:
- name: Test definition validation
primitiveValidations:
- name: Test primitive validation
commands:
- name: test-plugin-command
helpText: Test plugin generation
input:
- name: architecture_file
type: file
python_type: str
description: An architecture-as-code file.
acceptance:
- scenario: Test some stuff
given:
- The definitions in {{test-plugin-command.input.architecture_file}} represent a valid system architecture.
when:
- The command is run with the expected arguments.
then:
- Then stuff happens
definitions.yaml
enum:
name: CommandEnum
values:
- VALUE_A
- VALUE_B
- VALUE_C
---
ext:
name: AnotherPrimitive
type: Primitives
enumExt:
add:
- complex
---
schema:
name: TestPluginData
fields:
- name: value1
type: string
- name: value2
type: string
validation:
- name: Required fields are present
arguments:
- value1
test-definition-validation.yaml
validation:
name: Test definition validation
description: A test definition validator.
behavior:
- name: Validate a definition
type: REQUEST_RESPONSE
input:
- name: input
type: ValidatorInput
output:
- name: results
type: ValidatorOutput
acceptance:
- scenario: Successfully validate the definition
given:
- The ValidatorInput content consists of valid AaC definitions.
when:
- The validator plugin is executed.
then:
- The ValidatorOutput does not indicate any errors.
- The ValidatorOutput does not indicate any warnings.
- The ValidatorOutput indicates the validator plugin under test is valid.
test-primitive-validation.yaml
validation:
name: Test primitive validation
description: A test primitive validator.
behavior:
- name: Validate a primitive
type: REQUEST_RESPONSE
input:
- name: input
type: ValidatorInput
output:
- name: results
type: ValidatorOutput
acceptance:
- scenario: Successfully validate the primitive
given:
- The ValidatorInput content consists of a valid primitive value.
when:
- The validator plugin is executed.
then:
- The ValidatorOutput does not indicate any errors.
- The ValidatorOutput does not indicate any warnings.
- The ValidatorOutput indicates the validator plugin under test is valid.
There are several things to note with this update.
First, we are defining the plugin using the plugin
root key rather than the
model
root key, as in previous versions.
Second, we make use of a field defined in the plugin
schema called
definitionSources
. This field allows including other files whose definitions
are contributed by the plugin. As such, these files should be accessible from
the provided path (as is the case with import
s, in general). Observant readers
might ask why not just use import
to include definitions - a fair question. We
felt that definitionSources
provided greater clarity that the definitions in
those files are being contributed by the plugin.
The directory structure in which the above plugin is defined would look like this:
$ tree .
.
├── definitions.yaml
├── plugin.yaml
├── test-definition-validation.yaml
└── test-primitive-validation.yaml
Clearly, this is one way the project could be structured and not the only way.
That said, it shows how the definitionSources
field is used when defining a
plugin with contributions including definitions found in separate files.
The next difference are the fields definitionValidations
and
primitiveValidations
. These fields are used to specify, respectively, that the
plugin contributes one or more definition or primitive validations.
Finally, we come to the commands
field. In previous version of AaC, plugin
commands were defined using Behavior
s with a BehaviorType
of command
. In
version 0.2.0, we decided to opt for a more explicit approach. PluginCommand
s are an
additional schema
provided by the core language and the structure is very
similar to that of Behavior
with the exception that some fields exist in both
but have names more aligned with CLI commands - e.g. helpText
as opposed to
description
- or are wholly specific to CLI commands - e.g. group
which will
be used to define command groupings similar to other modern tools such as
docker
, podman
, kubectl
, etc. For a full comparison between
PluginCommand
and
Behavior
,
look at the definitions in the core specification. With those differences in
mind, the core part of Behavior
s - i.e. the input
, output
, and
acceptance
fields - however, are provided by both.
What changed?
We've released the first official AaC Style Guide to aid users in developing consistent systems with the AaC language. The style guide is minimal in keeping with one of the primary goals that AaC be unopinionated. However, after a system grows sufficiently, a consistent naming style and similar conventions will be helpful in reasoning about the system being created.
In addition to publishing the style guide, we have updated the core specification to conform to these guidelines.
Do these changes affect me?
These changes will affect everyone currently using AaC prior to version 0.2.0.
What do I need to do about it?
Refer to the AaC Style guide to see the changes made to root keys, enum values, etc. Update any references to core spec structures in your systems. Validation will also be a useful tool in knowing which values need to be updated to use the new style.
Associated PR: #612
What changed?
In previous versions of AaC, the scope of an import
declaration was unclear.
The import
root key was applied to each definition, however, this approach
lead to inconsistent behavior, as shown in the example below.
file1.yaml
import:
- ./file2.yaml
ext:
name: DefinitionAExtension
type: DefinitionA
schemaExt:
add:
- name: anotherField
type: string
---
model:
name: A model
behavior:
- name: A behavior
input:
- name: input
type: DefinitionA
output:
- name: output
type: string
scenario:
- name: A scenario
given:
- A precondition
when:
- Something happens
then:
- Another thing happens
file2.yaml
schema:
name: DefinitionA
fields:
- name: f1
type: int
While admittedly contrived, this example demonstrates that DefinitionA
is
imported on the DefinitionAExtension
definition but not on the A model
definition even though it uses DefinitionA
, as well. Even without an explicit
import for the definition, DefinitionA
is available to the A model
definition because it was imported on the DefinitionAExtension
definition. If,
however, the import
keyword were removed from DefinitionAExtension
and not
added to the A model
definition, validation would fail stating DefinitionA
is not defined. In a simple example such as this, it can be easy to see why this
would fail validation but, in more complex systems with more definitions that
might import the needed definition, the problem is better hidden.
Do these changes affect me?
This change will affect all users that make use of the import
root key in
their AaC files.
What do I need to do about it?
The changes required are straightforward. Imports are now treated as definitions like everything else and, per the style guide, they are to be defined once per file. Thus, considering file1.yaml and file2.yaml above and a separate file, file3.yaml, containing the definition of an external user then, in the old version, file4.yaml would have been defined as follows:
file4.yaml
import:
- file1.yaml
schema:
name: DefinitionB
fields:
- name: a
type: DefinitionA
---
import:
- file2.yaml
- file3.yaml
usecase:
name: A usecase
description: An example usecase
participants:
- name: sys1
type: A model
- name: sys2
type: Another model
steps:
- step: A thing happens
source: sys1
target: sys2
action: A behavior
However, with the changes to import
in v0.2.0, file4.yaml would be changed
as follows:
file4.yaml
import:
files:
- ./file1.yaml
- ./file2.yaml
- ./file3.yaml
---
schema:
name: DefinitionB
fields:
- name: a
type: DefinitionA
---
usecase:
name: A usecase
description: An example usecase
participants:
- name: sys1
type: A model
- name: sys2
type: Another model
steps:
- step: A thing happens
source: sys1
target: sys2
action: A behavior
Associated PR: #623
What changed?
The active-context
plugin had the add-file
, remove-file
, and reset-context
commands removed.
The state persistence between CLI commands maintained in the state.json
file no longer tracks the definitions or files in the context.
Do these changes affect me?
This change shouldn't affect users. The removed data wasn't leveraged in a noticeable way for users.