Skip to content

Commit

Permalink
cEP-0030: Next Generation Action System
Browse files Browse the repository at this point in the history
Closes #181
  • Loading branch information
akshatkarani committed May 18, 2019
1 parent 93c7cce commit 1b18c5e
Showing 1 changed file with 197 additions and 0 deletions.
197 changes: 197 additions & 0 deletions cEP-0030.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
# Next Generation Action System

| Metadata | |
| -------- | -----------------------------------------------|
| cEP | 30 |
| Version | 1.0 |
| Title | Next Generation Action System |
| Authors | Akshat Karani <mailto:[email protected]> |
| Status | Proposed |
| Type | Process |

# Abstract

This cEP describes the details about Next Generation Action System which
will allow bears to define their own actions as a part of
[GSoC'19 project](https://summerofcode.withgoogle.com/projects/#5450946933424128).

# Introduction

Bears run some analysis on a piece of code and output is in form of
a `Result` object. Then some action from a predefined set of actions
is applied to that `Result` object. This system is a bit restrictive
as action from predefined set of actionscan be taken.
If there is a system which will support bears defining their
own actions, then it will make bears more useful.
This project is about changing the current action system so that bears
can define their own actions.

# Implementation

## Changing the `Result` class

1. The first step is to facilitate bears defining their own actions. For this
the `__init__` and `classmethod` of the Result class need to be changes.
While yielding Result object a new optional parameter `actions` can be passed.
This is a tuple of actions that are specific to the bear.
2. Then a new attribute, `action` is added to the Result class. This is a
list of current default actions and actions that are specific to the bear.

```python

class Result:

# A new parameter `actions` is added
def __init__(self,
origin,
message: str,
affected_code: (tuple, list) = (),
severity: int = RESULT_SEVERITY.NORMAL,
additional_info: str = '',
debug_msg='',
diffs: (dict, None) = None,
confidence: int = 100,
aspect: (aspectbase, None) = None,
message_arguments: dict = {},
applied_actions: dict = {},
actions: list = []):

# A new attribute `actions` is added
self.actions = actions
# All the default actions are appended to `actions`
self.actions.append(ShowPatchAction(diffs))
self.actions.append(ShowAppliedPatchesAction(applied_actions))
self.actions.append(PrintMoreInfoAction(additional_info))
self.actions.append(OpenEditorAction(affected_code))
self.actions.append(IgnoreResultAction(origin, affected_code))
self.actions.append(GeneratePatchesAction(diffs))
self.actions.append(ApplyPatchAction(diffs))
self.actions.append(PrintDebugMessageAction(debug_msg))

```

3. Now action objects contain all the relevant data, so we can remove
the unncessary fields from Result class like `diffs`, `additional_info`,
`applied_actions`, `debug_msg`.

## Modifying the existing action classes

1. Currently we need to pass result object as a parameter to method
of action classes. But now we have action objects defined inside result object,
the methods of actions classes are changed.
2. The changes made in `ResultAction` class are:

```python

class ResultAction:

# `result` is removed as a parameter of the function
# It is no longer a `staticmethod`
def is_applicable(self,
original_file_dict,
file_diff_dict,
applied_actions=()):
return True

# `result` is removed as a parameter of the function
def apply(self, original_file_dict, file_diff_dict, **kwargs):
raise NotImplementedError

# `result` is removed as a parameter of the function
@enforce_signature
def apply_from_section(self,
original_file_dict: dict,
file_diff_dict: dict,
section: Section):
params = self.get_metadata().create_params_from_section(section)
# `result` is no longer passed as an argument
return self.apply(original_file_dict, file_diff_dict, **params)

```

3. All the actions classes inherit from `ResultAction` and are changed
accordingly. For example here are the changes to
`PrintDebugMessageAction` class:

```python

class PrintDebugMessageAction(ResultAction):

# `__init__` method is added with relevant parameters
def __init__(self, debug_msg):
self.debug_msg = debug_msg

# `self.debug_msg` is used instead of `result.debug_msg`
@enforce_signature
def is_applicable(self,
original_file_dict,
file_diff_dict,
applied_actions=()):
if self.debug_msg != '':
return True
return 'There is no debug message.'

# `self.debug_msg` is used instead of `result.debug_msg`
def apply(self, original_file_dict, file_diff_dict):
"""
Print (D)ebug message
"""
print(self.debug_msg)

return file_diff_dict

```

## Changing `ConsoleInteraction` and `Processing` module

1. Now `ConsoleInteraction` and `Processing` module are changed
to use `result.actions`.
2. `acquire_actions_and_apply` function in `ConsoleInteraction` module is
changed. Instead of using `cli_actions`, we use `result.actions`. If a action
from `result.actions` is applicable then it is added to `metadata_list`
and then user is asked which action is to be applied from `metadata_list`.
3. `autoapply_actions` function in `Processing` module is modified
to use `result.actions`.

## Writing bear specific actions

1. With all the changes above it now possible to support bear specific actions.
2. Implementation of `AddNewLineAction` for `GitCommitBear`.
`AddNewLineAction` on application adds a new line between
shortlog and body of the commit message.

```python

from coalib.misc.Shell import run_shell_command
from coalib.results.result_actions.ResultAction import ResultAction


class AddNewLineAction(ResultAction):

SUCCESS_MESSAGE = 'New Line added successfully.'

def __init__(self, message, shortlog, body):
self.message = message
self.shortlog = shortlog
self.body = body

def apply(self, original_file_dict, file_diff_dict, **kwargs):
"""
Add (N)ewline
"""
new_commit_message = '{}\n\n{}'.format(self.shortlog, self.body)
command = 'git commit --amend -m "{}"'.format(new_commit_message)
stdout, err = run_shell_command(command)
return file_diff_dict

```

3. `CommitBear.py` file must also be changed so then when yielding Result object, a list of actions is passed.

```python

yield Result(self,
message,
actions=[AddNewLineAction(message, shortlog, body)])

```

0 comments on commit 1b18c5e

Please sign in to comment.