Skip to content

Commit

Permalink
Add CircleCI plugin and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Sebastian Simon committed Sep 30, 2024
1 parent b9df724 commit cb5a1ee
Show file tree
Hide file tree
Showing 7 changed files with 204 additions and 8 deletions.
70 changes: 70 additions & 0 deletions src/cfgnet/plugins/concept/circleci_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# This file is part of the CfgNet module.
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <https://www.gnu.org/licenses/>.
from cfgnet.plugins.file_type.yaml_plugin import YAMLPlugin
from cfgnet.config_types.config_types import ConfigType


class CircleCiPlugin(YAMLPlugin):
def __init__(self):
super().__init__("circleci")

def is_responsible(self, abs_file_path):
return abs_file_path.endswith(".circleci/config.yml")

# pylint: disable=too-many-return-statements
def get_config_type(self, option_name: str) -> ConfigType:
"""
Find config type based on option name.
:param option_name: name of option
:return: config type
"""
if option_name in ("command", "run", "shell", "entrypoint"):
return ConfigType.COMMAND

if option_name == "image":
return ConfigType.IMAGE

if option_name in ("parallelism"):
return ConfigType.NUMBER

if option_name in (
"at",
"working_directory",
"path",
"paths",
"destination",
):
return ConfigType.PATH

if option_name in ("name", "resource_class"):
return ConfigType.NAME

if option_name == "user":
return ConfigType.USERNAME

if option_name == "environment":
return ConfigType.ENVIRONMENT

if option_name in ("xcode", "version"):
return ConfigType.VERSION_NUMBER

if option_name in ("docker_layer_caching", "background"):
return ConfigType.BOOLEAN

if option_name in ("no_output_timeout"):
return ConfigType.TIME

return ConfigType.UNKNOWN
6 changes: 1 addition & 5 deletions src/cfgnet/plugins/file_type/yaml_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,7 @@ def _parse_scalar_node(self, node, parent):
):
name = node.value if node.value != "" else ""

name = (
f"{parent.name}:{node.value}"
if parent.config_type == ConfigType.VERSION_NUMBER
else node.value
)
name = node.value

value = ValueNode(name=name)
if isinstance(parent, ArtifactNode):
Expand Down
2 changes: 2 additions & 0 deletions src/cfgnet/plugins/plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
from cfgnet.plugins.concept.kafka_plugin import KafkaPlugin
from cfgnet.plugins.concept.angular_plugin import AngularPlugin
from cfgnet.plugins.concept.mapreduce_plugin import MapReducePlugin
from cfgnet.plugins.concept.circleci_plugin import CircleCiPlugin


class PluginManager:
Expand Down Expand Up @@ -83,6 +84,7 @@ class PluginManager:
KafkaPlugin(),
AngularPlugin(),
MapReducePlugin(),
CircleCiPlugin(),
]

file_type_plugins: List[Plugin] = [
Expand Down
89 changes: 89 additions & 0 deletions tests/cfgnet/plugins/concept/test_circleci_plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# This file is part of the CfgNet module.
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <https://www.gnu.org/licenses/>.

import os

import pytest

from cfgnet.plugins.concept.circleci_plugin import CircleCiPlugin
from cfgnet.config_types.config_types import ConfigType
from tests.utility.id_creator import make_id


@pytest.fixture(name="get_plugin")
def get_plugin_():
plugin = CircleCiPlugin()
return plugin


def test_is_responsible(get_plugin):
plugin = get_plugin
circle_file = os.path.abspath("tests/files/.circleci/config.yml")
no_circle_file = os.path.abspath("tests/files/config.yml")

circle_file = plugin.is_responsible(circle_file)
no_circle_file = plugin.is_responsible(no_circle_file)

assert circle_file
assert not no_circle_file


def test_parse_circle_file(get_plugin):
plugin = get_plugin
circle_file = os.path.abspath("tests/files/.circleci/config.yml")

artifact = plugin.parse_file(circle_file, "config.yml")
nodes = artifact.get_nodes()
ids = {node.id for node in nodes}

for id in ids:
print(id)

assert artifact is not None
assert len(nodes) == 16

assert make_id("config.yml", "file", "config.yml") in ids
assert make_id("config.yml", "jobs", "build", "docker", "offset:0", "image", "circleci/node:14") in ids
assert make_id("config.yml", "jobs", "build", "steps", "checkout") in ids
assert make_id("config.yml", "jobs", "build", "steps", "offset:0", "run", "name", "Install dependencies") in ids
assert make_id("config.yml", "jobs", "build", "steps", "offset:0", "run", "command", "npm install") in ids
assert make_id("config.yml", "jobs", "build", "steps", "offset:1", "persist_to_workspace", "root", ".") in ids
assert make_id("config.yml", "jobs", "build", "steps", "offset:1", "persist_to_workspace", "paths", "dist") in ids
assert make_id("config.yml", "jobs", "build", "steps", "offset:1", "persist_to_workspace", "paths", "src") in ids
assert make_id("config.yml", "jobs", "deploy", "docker", "offset:0", "image", "circleci/node:14") in ids
assert make_id("config.yml", "jobs", "deploy", "steps", "offset:0", "attach_workspace", "at", "/workspace") in ids
assert make_id("config.yml", "jobs", "deploy", "steps", "offset:1", "run", "name", "Deploy application") in ids
assert make_id("config.yml", "jobs", "deploy", "steps", "offset:1", "run", "command", 'echo "Deploying application..."') in ids
assert make_id("config.yml", "workflows", "version", "2") in ids
assert make_id("config.yml", "workflows", "build_and_deploy", "jobs", "build") in ids
assert make_id("config.yml", "workflows", "build_and_deploy", "jobs", "offset:0", "deploy", "requires", "build") in ids


def test_config_types(get_plugin):
plugin = get_plugin
file = os.path.abspath("tests/files/.circleci/config.yml")

artifact = plugin.parse_file(file, "config.yml")
nodes = artifact.get_nodes()

version_node = next(filter(lambda x: x.id == make_id("config.yml", "workflows", "version", "2"), nodes))
command_node = next(filter(lambda x: x.id == make_id("config.yml", "jobs", "build", "steps", "offset:0", "run", "command", "npm install"), nodes))
path_node = next(filter(lambda x: x.id == make_id("config.yml", "jobs", "deploy", "steps", "offset:0", "attach_workspace", "at", "/workspace"), nodes))
image_node = next(filter(lambda x: x.id == make_id("config.yml", "jobs", "build", "docker", "offset:0", "image", "circleci/node:14"), nodes))

assert version_node.config_type == ConfigType.VERSION_NUMBER
assert command_node.config_type == ConfigType.COMMAND
assert path_node.config_type == ConfigType.PATH
assert image_node.config_type == ConfigType.IMAGE
4 changes: 2 additions & 2 deletions tests/cfgnet/plugins/concept/test_travis_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ def test_parse_travis_file(get_plugin):
)

assert make_id(".travis.yml", "env", "FOLDER=integration/user") in ids
assert make_id(".travis.yml", "version", "version:>= 1.0.0") in ids
assert make_id(".travis.yml", "version", ">= 1.0.0") in ids
assert make_id(".travis.yml", "os", "linux") in ids
assert make_id(".travis.yml", "dist", "trusty") in ids
assert make_id(".travis.yml", "language", "ruby") in ids
Expand All @@ -147,7 +147,7 @@ def test_config_types(get_plugin):
== make_id(
".travis.yml",
"version",
"version:>= 1.0.0",
">= 1.0.0",
),
nodes,
)
Expand Down
4 changes: 3 additions & 1 deletion tests/cfgnet/plugins/test_plugin_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
def test_get_all_plugins():
all_plugins = PluginManager.get_plugins()

assert len(all_plugins) == 26
assert len(all_plugins) == 27


def test_get_responsible_plugin():
Expand Down Expand Up @@ -71,6 +71,7 @@ def test_get_responsible_plugin():
kafka_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/server.properties")
angular_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/angular.json")
mapreduce_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/mapred-site.xml")
circleci_plugin = PluginManager.get_responsible_plugin(plugins, "path/to/.circleci/config.yml")

assert docker_plugin.concept_name == "docker"
assert maven_plugin.concept_name == "maven"
Expand Down Expand Up @@ -98,3 +99,4 @@ def test_get_responsible_plugin():
assert kafka_plugin.concept_name == "kafka"
assert angular_plugin.concept_name == "angular"
assert mapreduce_plugin.concept_name == "mapreduce"
assert circleci_plugin.concept_name == "circleci"
37 changes: 37 additions & 0 deletions tests/files/.circleci/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
version: 2.1

jobs:
build:
docker:
- image: circleci/node:14
steps:
- checkout

- run:
name: Install dependencies
command: npm install

- persist_to_workspace:
root: .
paths:
- dist
- src

deploy:
docker:
- image: circleci/node:14
steps:
- attach_workspace:
at: /workspace
- run:
name: Deploy application
command: echo "Deploying application..." # Add your deployment commands here

workflows:
version: 2
build_and_deploy:
jobs:
- build
- deploy:
requires:
- build

0 comments on commit cb5a1ee

Please sign in to comment.