Skip to content

Release v0.2.0

Cameron Chaparro edited this page Jun 28, 2023 · 5 revisions

Release v0.2.0

Breaking Changes

Plugins are now defined using a specific plugin definition construct

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 imports, 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 Behaviors with a BehaviorType of command. In version 0.2.0, we decided to opt for a more explicit approach. PluginCommands 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 Behaviors - i.e. the input, output, and acceptance fields - however, are provided by both.

Release of the Official "Core Spec Style Guide"

Associated PR: #613, #619

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.

The scope of imports change from definition-wide to file-wide

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

Active Context manager plugin and state file changes

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.