diff --git a/assets/pipeline-test.yaml b/assets/pipeline-test.yaml index 1973234..6c807b9 100644 --- a/assets/pipeline-test.yaml +++ b/assets/pipeline-test.yaml @@ -6,17 +6,17 @@ pipeline: id: main workflow: #동기식 실행, 해당 수행이 끝나야만 다음 스텝실행, command일경우 해당 id 기입 - - exe: createAppData#1 + - async: appData #비동기식 실행, 해당 수행이 완료됨과 관계없이 실행하고 다음 스텝을 실행한다 - - async: dartCompile#1 + - exe: buildDart #일반적인 if문과 동일 - if: #property의 내용은 기본 dynamic(Object)형으로써, 비교시 정확한 캐스팅 필요, 적지 않을시 기본 string condition-int: == on-false: - - exe: + - exe: zip commands: ### Version 쓰기 diff --git a/lib/oto/application.dart b/lib/oto/application.dart index 26e6993..6b9ef0c 100644 --- a/lib/oto/application.dart +++ b/lib/oto/application.dart @@ -2,11 +2,13 @@ import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'package:dart_framework/platform/process.dart'; +import 'package:dart_framework/subtitle/parser_base.dart'; import 'package:dart_framework/utils/system_util.dart'; import 'package:oto_cli/cli/cli.dart'; import 'package:oto_cli/oto/command.dart'; import 'package:oto_cli/oto/data/command_data.dart'; import 'package:oto_cli/oto/data/jenkins_data.dart'; +import 'package:oto_cli/oto/data/pipeline_data.dart'; import 'package:oto_cli/oto/defined_data.dart'; import 'package:yaml/yaml.dart'; @@ -23,8 +25,8 @@ class Application { BuildType.file: () => DataComposerFile() }; - final Map taskMap = { - 'exe': () => PipelineExec(), + final Map exeMap = { + 'exe': () => PipelineExe(), 'async': () => PipelineAsync(), 'if': () => PipelineIf(), /*'while': () => PipelineWhile(), @@ -32,14 +34,29 @@ class Application { 'switch': () => PipelineSwitch(),*/ }; + DataJenkins? jenkinsData; Map? property; Map dataCommandMap = {}; + late Pipeline pipeline; - DataJenkins? jenkinsData; + PipelineValidateResult pipelineInitialize(List list) { + var result = PipelineValidateResult(); + for (Map item in list) { + var key = item.keys.first; + if (!exeMap.containsKey(key)) { + result.enable = false; + result.message = 'Validate Error - "$key" is not a supported task'; + return result; + } - bool pipelineInitialize(List list) { - for (Map item in list) {} - return false; + var exe = exeMap[key]!(); + var childResult = exe.initialize(item); + if (!childResult.enable) { + return childResult; + } + result.exeList.add(exe); + } + return result; } Future build(BuildType buildType, {String? yamlContent}) async { @@ -72,7 +89,7 @@ class Application { if (dataCommandMap.containsKey(command.id)) { var ex = ExceptionData(); ex.phase = 'Validate command list'; - ex.message = 'Duplicate command id exists: ${command.id}'; + ex.message = 'Duplicate command id exists: "${command.id}"'; throw Exception(ex); } else { dataCommandMap[command.id] = command; @@ -80,9 +97,15 @@ class Application { } //Parse pipeline & validate - var pipeline = build.pipeline; - List list = pipeline!.workflow; - bool validateResult = pipelineInitialize(list); + var validateResult = pipelineInitialize(build.pipeline!.workflow); + if (!validateResult.enable) { + var ex = ExceptionData(); + ex.phase = 'Validate Pipeline'; + ex.message = validateResult.message; + throw Exception(ex); + } + pipeline = validateResult.pipeline!; + await pipeline.execute(); } } on Exception catch (e, stacktace) { await CLI.printString(e.toString(), color: Color.redStrong); @@ -123,43 +146,131 @@ class Application { } } +//####################### Pipeline #######################// +class Pipeline { + List _exeList; + + Pipeline(this._exeList); + + Future execute() async { + for (var exe in _exeList) { + await exe.execute(); + } + return simpleFuture; + } +} + +class PipelineValidateResult { + late String? message; + late bool enable = true; + late List exeList = []; + Pipeline? get pipeline { + if (exeList.isNotEmpty) { + return Pipeline(exeList); + } else { + return null; + } + } +} + abstract class PipelineExecutor { - bool initialize(Map set); + //set & validate data + PipelineValidateResult initialize(Map set); Future execute(); + + PipelineValidateResult validateTasks(List? list) { + var result = PipelineValidateResult(); + if (list != null) { + return Application.instance.pipelineInitialize(list); + } + return result; + } } -class PipelineExec implements PipelineExecutor { +class PipelineExe extends PipelineExecutor { + late String targetCommandID; @override - bool initialize(Map set) { - return false; + PipelineValidateResult initialize(Map set) { + var result = PipelineValidateResult(); + targetCommandID = set.values.first as String; + if (!Application.instance.dataCommandMap.containsKey(targetCommandID)) { + result.enable = false; + result.message = + 'The "$targetCommandID" command does not exist in the command list.'; + } + return result; + } + + Future get commandData async { + var commandData = Application.instance.dataCommandMap[targetCommandID]!; + await Application.instance + .printBuildStep('Phase Start: ${commandData.name}', Color.green); + return dataFutrue(commandData); } @override Future execute() async { + var now = DateTime.now(); + var time = + '${now.minute.toString().padLeft(2)}:${now.second.toString().padLeft(2)}:${now.millisecond.toString().padLeft(2)}'; + print('==================> [$time] Execute: $targetCommandID'); + var data = await commandData; + await Command.byType(data.command).execute(data); return simpleFuture; } } -class PipelineAsync implements PipelineExecutor { - @override - bool initialize(Map set) { - return false; - } - +class PipelineAsync extends PipelineExe { @override Future execute() async { + var now = DateTime.now(); + var time = + '${now.minute.toString().padLeft(2)}:${now.second.toString().padLeft(2)}:${now.millisecond.toString().padLeft(2)}'; + print('==================> [$time] Async Execute: $targetCommandID'); + executeAsync(await commandData); return simpleFuture; } + + void executeAsync(DataCommand data) async { + await Command.byType(data.command).execute(data); + } } -class PipelineIf implements PipelineExecutor { +class PipelineIf extends PipelineExecutor { + late DataIf _data; + late Pipeline? _pipelineTrue; + late Pipeline? _pipelineFalse; + @override - bool initialize(Map set) { - return false; + PipelineValidateResult initialize(Map set) { + var result = PipelineValidateResult(); + _data = DataIf.fromJson(set.values.first); + var dataValidateResult = _data.validate(); + if (!dataValidateResult.enable) { + return dataValidateResult; + } + //set true task + var validateResult = validateTasks(_data.on_true); + if (!validateResult.enable) { + return validateResult; + } + _pipelineTrue = validateResult.pipeline; + + //set false task + validateResult = validateTasks(_data.on_false); + if (!validateResult.enable) { + return validateResult; + } + _pipelineFalse = validateResult.pipeline; + + return result; } @override Future execute() async { + //To-do: check true or false + await _pipelineTrue?.execute(); + await _pipelineFalse?.execute(); return simpleFuture; } } diff --git a/lib/oto/data/command_data.g.dart b/lib/oto/data/command_data.g.dart index d184b35..6066325 100644 --- a/lib/oto/data/command_data.g.dart +++ b/lib/oto/data/command_data.g.dart @@ -8,22 +8,28 @@ part of 'command_data.dart'; DataBuild _$DataBuildFromJson(Map json) => DataBuild() ..property = json['property'] as Map + ..pipeline = json['pipeline'] == null + ? null + : DataPipeline.fromJson(json['pipeline'] as Map) ..commands = (json['commands'] as List) .map((e) => DataCommand.fromJson(e as Map)) .toList(); Map _$DataBuildToJson(DataBuild instance) => { 'property': instance.property, + 'pipeline': instance.pipeline, 'commands': instance.commands, }; DataCommand _$DataCommandFromJson(Map json) => DataCommand() ..command = $enumDecode(_$CommandTypeEnumMap, json['command']) + ..id = json['id'] as String ..param = json['param']; Map _$DataCommandToJson(DataCommand instance) => { 'command': _$CommandTypeEnumMap[instance.command]!, + 'id': instance.id, 'param': instance.param, }; diff --git a/lib/oto/data/pipeline_data.dart b/lib/oto/data/pipeline_data.dart index dc0ec18..a155a4e 100644 --- a/lib/oto/data/pipeline_data.dart +++ b/lib/oto/data/pipeline_data.dart @@ -1,16 +1,12 @@ // ignore_for_file: non_constant_identifier_names import 'package:json_annotation/json_annotation.dart'; +import 'package:oto_cli/oto/application.dart'; part 'pipeline_data.g.dart'; /// ***************************** Base Data ****************************/// abstract class DataValidator { - DataValidateResult validate(); -} - -class DataValidateResult { - late String? message; - bool result = true; + PipelineValidateResult validate(); } @JsonSerializable() @@ -45,20 +41,20 @@ class DataIf implements DataValidator { DataIf(); @override - DataValidateResult validate() { - var result = DataValidateResult(); + PipelineValidateResult validate() { + var result = PipelineValidateResult(); if (condition_int == null && condition_float == null && condition_string == null && condition_version == null && condition_bool == null) { result.message = 'If syntax requires a condition.'; - result.result = false; + result.enable = false; return result; } if (on_true == null && on_false == null) { result.message = 'If syntax requires on-true or on-false.'; - result.result = false; + result.enable = false; return result; } return result; diff --git a/lib/oto/data/pipeline_data.g.dart b/lib/oto/data/pipeline_data.g.dart index 06e871e..9c07776 100644 --- a/lib/oto/data/pipeline_data.g.dart +++ b/lib/oto/data/pipeline_data.g.dart @@ -17,20 +17,20 @@ Map _$DataPipelineToJson(DataPipeline instance) => }; DataIf _$DataIfFromJson(Map json) => DataIf() - ..condition_int = json['condition_int'] as String? - ..condition_float = json['condition_float'] as String? - ..condition_string = json['condition_string'] as String? - ..condition_version = json['condition_version'] as String? - ..condition_bool = json['condition_bool'] as String? - ..on_true = json['on_true'] as List? - ..on_false = json['on_false'] as List?; + ..condition_int = json['condition-int'] as String? + ..condition_float = json['condition-float'] as String? + ..condition_string = json['condition-string'] as String? + ..condition_version = json['condition-version'] as String? + ..condition_bool = json['condition-bool'] as String? + ..on_true = json['on-true'] as List? + ..on_false = json['on-false'] as List?; Map _$DataIfToJson(DataIf instance) => { - 'condition_int': instance.condition_int, - 'condition_float': instance.condition_float, - 'condition_string': instance.condition_string, - 'condition_version': instance.condition_version, - 'condition_bool': instance.condition_bool, - 'on_true': instance.on_true, - 'on_false': instance.on_false, + 'condition-int': instance.condition_int, + 'condition-float': instance.condition_float, + 'condition-string': instance.condition_string, + 'condition-version': instance.condition_version, + 'condition-bool': instance.condition_bool, + 'on-true': instance.on_true, + 'on-false': instance.on_false, };