From 9b48d803927d4ce20f9432b38f0b548a2bb21008 Mon Sep 17 00:00:00 2001 From: "leedongmyung[desktop]" Date: Sun, 19 Nov 2023 17:21:35 +0900 Subject: [PATCH] pipeline initial commit --- .vscode/launch.json | 7 ++ assets/example.yaml | 5 +- assets/pipeline-test.yaml | 43 +++++++ build_osx.yaml | 2 +- build_win.yaml | 2 +- lib/oto/application.dart | 119 +++++++++++++++--- lib/oto/build/app_data_creator.dart | 2 +- lib/oto/build/build_dart.dart | 2 +- lib/oto/build/build_dart_compile.dart | 2 +- lib/oto/build/build_dot_net.dart | 2 +- lib/oto/build/build_flutter.dart | 2 +- lib/oto/build/build_ios.dart | 2 +- lib/oto/command.dart | 2 +- lib/oto/data/{data.dart => command_data.dart} | 7 +- .../data/{data.g.dart => command_data.g.dart} | 6 +- lib/oto/data/pipeline_data.dart | 69 ++++++++++ lib/oto/data/pipeline_data.g.dart | 36 ++++++ lib/oto/file/copy.dart | 2 +- lib/oto/file/delete.dart | 2 +- lib/oto/file/rename.dart | 2 +- lib/oto/shell/shell.dart | 2 +- lib/oto/uploader/uploader.dart | 2 +- lib/oto/util/execute_app.dart | 2 +- lib/oto/util/publish_ios.dart | 2 +- lib/oto/util/slack.dart | 2 +- lib/oto/util/zip.dart | 2 +- 26 files changed, 283 insertions(+), 45 deletions(-) create mode 100644 assets/pipeline-test.yaml rename lib/oto/data/{data.dart => command_data.dart} (97%) rename lib/oto/data/{data.g.dart => command_data.g.dart} (98%) create mode 100644 lib/oto/data/pipeline_data.dart create mode 100644 lib/oto/data/pipeline_data.g.dart diff --git a/.vscode/launch.json b/.vscode/launch.json index 0cbb5b6..4e21231 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -32,6 +32,13 @@ "program": "./bin/main.dart", "args": ["exe", "-f ./build_osx.yaml"] }, + { + "name": "exe pipeline", + "request": "launch", + "type": "dart", + "program": "./bin/main.dart", + "args": ["exe", "-f ./assets/pipeline-test.yaml"] + }, { "name": "test", "request": "launch", diff --git a/assets/example.yaml b/assets/example.yaml index 0e14b84..d922902 100644 --- a/assets/example.yaml +++ b/assets/example.yaml @@ -30,7 +30,7 @@ pipeline: #일반적인 while문과 동일 - while: - condition: [bool] + condition-bool: do: - async: - exec: @@ -42,7 +42,7 @@ pipeline: true: #조건문 내에도 선언 가능, 반대도 가능 - while: - condition: < 10 [int] + condition-int: < 10 do: - exec: #일반적인 switch구문과 동일 @@ -90,5 +90,4 @@ commands: - /release/oto_cli - /release/test rersult: - success: zipPath: diff --git a/assets/pipeline-test.yaml b/assets/pipeline-test.yaml new file mode 100644 index 0000000..1973234 --- /dev/null +++ b/assets/pipeline-test.yaml @@ -0,0 +1,43 @@ +--- +property: + workspace: . + +pipeline: + id: main + workflow: + #동기식 실행, 해당 수행이 끝나야만 다음 스텝실행, command일경우 해당 id 기입 + - exe: createAppData#1 + + #비동기식 실행, 해당 수행이 완료됨과 관계없이 실행하고 다음 스텝을 실행한다 + - async: dartCompile#1 + + #일반적인 if문과 동일 + - if: + #property의 내용은 기본 dynamic(Object)형으로써, 비교시 정확한 캐스팅 필요, 적지 않을시 기본 string + condition-int: == + on-false: + - exe: + +commands: + ### Version 쓰기 +- command: CreateAppData + id: appData + param: + scm: Git + name: OTO + relativeAssetPath: assets/data + returnVersion: "" + returnHash: "" + + ### 실행가능한 파일로 빌드 +- command: BuildDart + id: buildDart + param: {} + + ### 최종 zip 파일 형태로 저장 +- command: Zip + id: zip + param: + zipFile: "/release/oto_win_v.zip" + zipList: + - "/release/oto_cli.exe" diff --git a/build_osx.yaml b/build_osx.yaml index 58bd221..cf3bf77 100644 --- a/build_osx.yaml +++ b/build_osx.yaml @@ -1,5 +1,5 @@ --- -common: +property: workspace: "." commands: diff --git a/build_win.yaml b/build_win.yaml index 9060d93..463fb7c 100644 --- a/build_win.yaml +++ b/build_win.yaml @@ -1,5 +1,5 @@ --- -common: +property: workspace: "." commands: diff --git a/lib/oto/application.dart b/lib/oto/application.dart index 98a84f1..26e6993 100644 --- a/lib/oto/application.dart +++ b/lib/oto/application.dart @@ -5,9 +5,10 @@ import 'package:dart_framework/platform/process.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/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; import 'package:oto_cli/oto/data/jenkins_data.dart'; import 'package:oto_cli/oto/defined_data.dart'; +import 'package:yaml/yaml.dart'; enum BuildType { jenkins, test, file } @@ -16,20 +17,29 @@ class Application { static final Application _instance = Application._privateConstructor(); static Application get instance => _instance; - final Map _mapComposer = { - BuildType.test: DataComposerTest(), - BuildType.jenkins: DataComposerJenkins(), - BuildType.file: DataComposerFile() + final Map _mapComposer = { + BuildType.test: () => DataComposerTest(), + BuildType.jenkins: () => DataComposerJenkins(), + BuildType.file: () => DataComposerFile() }; - Map? _property; - Map? get property { - return _property; - } + final Map taskMap = { + 'exe': () => PipelineExec(), + 'async': () => PipelineAsync(), + 'if': () => PipelineIf(), + /*'while': () => PipelineWhile(), + 'wait-until': () => PipelineWaitUntil(), + 'switch': () => PipelineSwitch(),*/ + }; - DataJenkins? _jenkinsData; - DataJenkins? get jenkinsData { - return _jenkinsData; + Map? property; + Map dataCommandMap = {}; + + DataJenkins? jenkinsData; + + bool pipelineInitialize(List list) { + for (Map item in list) {} + return false; } Future build(BuildType buildType, {String? yamlContent}) async { @@ -38,20 +48,41 @@ class Application { // var envArgs = envArguments(arguments); // bool isTest = envArgs.containsKey('isTest'); //for Unit Test try { - var composer = _mapComposer[buildType]!; + var composer = _mapComposer[buildType]!(); await composer.compose(yamlContent, printBuildStep); - _jenkinsData = composer.jenkinsData; + jenkinsData = composer.jenkinsData; DataBuild? build = - DataBuild.fromJson(getMapFromYaml(composer.buildYaml)!); + DataBuild.fromJson(getMapFromYamlA(composer.buildYaml)!); await CLI.println( '********************************* Build Data *************************************', color: Color.magenta); print(composer.buildYaml); - _property = build.common; - for (var command in build.commands) { - await printBuildStep('Phase Start: ${command.name}', Color.green); - await Command.byType(command.command).execute(command); + property = build.property; + + if (build.pipeline == null) { + //이후 pipeline 안정이후, command로만 빌드는 삭제, pipeline 필수로 넣도록 구성 + for (var command in build.commands) { + await printBuildStep('Phase Start: ${command.name}', Color.green); + await Command.byType(command.command).execute(command); + } + } else { + //set command in dic, 중복 커맨드 id 필터 + for (var command in build.commands) { + if (dataCommandMap.containsKey(command.id)) { + var ex = ExceptionData(); + ex.phase = 'Validate command list'; + ex.message = 'Duplicate command id exists: ${command.id}'; + throw Exception(ex); + } else { + dataCommandMap[command.id] = command; + } + } + + //Parse pipeline & validate + var pipeline = build.pipeline; + List list = pipeline!.workflow; + bool validateResult = pipelineInitialize(list); } } on Exception catch (e, stacktace) { await CLI.printString(e.toString(), color: Color.redStrong); @@ -73,6 +104,15 @@ class Application { return simpleFuture; } + Map? getMapFromYamlA(String yamlStr) { + Map? map; + if (yamlStr.length > 5) { + YamlMap data = loadYaml(yamlStr); + map = jsonDecode(jsonEncode(data)); + } + return map; + } + Future printBuildStep(String name, Color? color) async { var message = '''************************************************************************************ @@ -83,6 +123,47 @@ class Application { } } +abstract class PipelineExecutor { + bool initialize(Map set); + Future execute(); +} + +class PipelineExec implements PipelineExecutor { + @override + bool initialize(Map set) { + return false; + } + + @override + Future execute() async { + return simpleFuture; + } +} + +class PipelineAsync implements PipelineExecutor { + @override + bool initialize(Map set) { + return false; + } + + @override + Future execute() async { + return simpleFuture; + } +} + +class PipelineIf implements PipelineExecutor { + @override + bool initialize(Map set) { + return false; + } + + @override + Future execute() async { + return simpleFuture; + } +} + //############################ DataComposer ##########################// abstract class DataComposer { DataJenkins? jenkinsData; diff --git a/lib/oto/build/app_data_creator.dart b/lib/oto/build/app_data_creator.dart index 517f756..1ca8cf1 100644 --- a/lib/oto/build/app_data_creator.dart +++ b/lib/oto/build/app_data_creator.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:dart_framework/core/app_data_manager.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; class CreateAppData extends Command { Function? get error => null; diff --git a/lib/oto/build/build_dart.dart b/lib/oto/build/build_dart.dart index c633dbc..058df03 100644 --- a/lib/oto/build/build_dart.dart +++ b/lib/oto/build/build_dart.dart @@ -3,7 +3,7 @@ import 'package:dart_framework/platform/process.dart'; import 'package:dart_framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; class BuildDart extends Command { Function? get error => null; diff --git a/lib/oto/build/build_dart_compile.dart b/lib/oto/build/build_dart_compile.dart index 550d3e3..ba588a1 100644 --- a/lib/oto/build/build_dart_compile.dart +++ b/lib/oto/build/build_dart_compile.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'dart:io'; import 'package:oto_cli/oto/build/build_dart.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; import 'package:dart_framework/utils/path.dart'; // ignore: depend_on_referenced_packages import 'package:path/path.dart' as path; diff --git a/lib/oto/build/build_dot_net.dart b/lib/oto/build/build_dot_net.dart index e14f796..c19524f 100644 --- a/lib/oto/build/build_dot_net.dart +++ b/lib/oto/build/build_dot_net.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:dart_framework/platform/process.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; class BuildDotNet extends Command { Function? get error => null; diff --git a/lib/oto/build/build_flutter.dart b/lib/oto/build/build_flutter.dart index 7454446..73cdeeb 100644 --- a/lib/oto/build/build_flutter.dart +++ b/lib/oto/build/build_flutter.dart @@ -1,7 +1,7 @@ import 'dart:async'; import 'package:oto_cli/oto/build/build_dart.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; // ignore: constant_identifier_names enum BuildPlatform { Windows, Macos, Web, Apk, Appbundle, iOS, Linux } diff --git a/lib/oto/build/build_ios.dart b/lib/oto/build/build_ios.dart index 9d75f46..a931d8f 100644 --- a/lib/oto/build/build_ios.dart +++ b/lib/oto/build/build_ios.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; import 'package:dart_framework/platform/process.dart'; import 'package:dart_framework/utils/path.dart'; diff --git a/lib/oto/command.dart b/lib/oto/command.dart index 52ce997..155f8ad 100644 --- a/lib/oto/command.dart +++ b/lib/oto/command.dart @@ -9,7 +9,7 @@ import 'package:oto_cli/oto/build/build_dart_compile.dart'; import 'package:oto_cli/oto/build/build_dot_net.dart'; import 'package:oto_cli/oto/build/build_flutter.dart'; import 'package:oto_cli/oto/build/build_ios.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; import 'package:oto_cli/oto/file/delete.dart'; import 'package:oto_cli/oto/file/rename.dart'; import 'package:oto_cli/oto/shell/shell.dart'; diff --git a/lib/oto/data/data.dart b/lib/oto/data/command_data.dart similarity index 97% rename from lib/oto/data/data.dart rename to lib/oto/data/command_data.dart index 65aeb74..1ce0ebe 100644 --- a/lib/oto/data/data.dart +++ b/lib/oto/data/command_data.dart @@ -2,12 +2,14 @@ import 'package:dart_framework/utils/slack/slack_sender.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:dart_framework/core/app_data_manager.dart'; import 'package:oto_cli/oto/command.dart'; -part 'data.g.dart'; +import 'package:oto_cli/oto/data/pipeline_data.dart'; +part 'command_data.g.dart'; /// ***************************** Base Data ****************************/// @JsonSerializable() class DataBuild { - late Map common; + late Map property; + late DataPipeline? pipeline; late List commands; DataBuild(); @@ -22,6 +24,7 @@ class DataCommand { DataCommand(); late CommandType command; + late String id; late dynamic param; String get name { diff --git a/lib/oto/data/data.g.dart b/lib/oto/data/command_data.g.dart similarity index 98% rename from lib/oto/data/data.g.dart rename to lib/oto/data/command_data.g.dart index 88f5783..d184b35 100644 --- a/lib/oto/data/data.g.dart +++ b/lib/oto/data/command_data.g.dart @@ -1,19 +1,19 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'data.dart'; +part of 'command_data.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** DataBuild _$DataBuildFromJson(Map json) => DataBuild() - ..common = json['common'] as Map + ..property = json['property'] as Map ..commands = (json['commands'] as List) .map((e) => DataCommand.fromJson(e as Map)) .toList(); Map _$DataBuildToJson(DataBuild instance) => { - 'common': instance.common, + 'property': instance.property, 'commands': instance.commands, }; diff --git a/lib/oto/data/pipeline_data.dart b/lib/oto/data/pipeline_data.dart new file mode 100644 index 0000000..dc0ec18 --- /dev/null +++ b/lib/oto/data/pipeline_data.dart @@ -0,0 +1,69 @@ +// ignore_for_file: non_constant_identifier_names + +import 'package:json_annotation/json_annotation.dart'; +part 'pipeline_data.g.dart'; + +/// ***************************** Base Data ****************************/// +abstract class DataValidator { + DataValidateResult validate(); +} + +class DataValidateResult { + late String? message; + bool result = true; +} + +@JsonSerializable() +class DataPipeline { + late String id; + late List workflow; + + DataPipeline(); + + factory DataPipeline.fromJson(Map json) => + _$DataPipelineFromJson(json); + Map toJson() => _$DataPipelineToJson(this); +} + +@JsonSerializable() +class DataIf implements DataValidator { + @JsonKey(name: 'condition-int') + late String? condition_int; + @JsonKey(name: 'condition-float') + late String? condition_float; + @JsonKey(name: 'condition-string') + late String? condition_string; + @JsonKey(name: 'condition-version') + late String? condition_version; + @JsonKey(name: 'condition-bool') + late String? condition_bool; + @JsonKey(name: 'on-true') + late List? on_true; + @JsonKey(name: 'on-false') + late List? on_false; + + DataIf(); + + @override + DataValidateResult validate() { + var result = DataValidateResult(); + 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; + return result; + } + if (on_true == null && on_false == null) { + result.message = 'If syntax requires on-true or on-false.'; + result.result = false; + return result; + } + return result; + } + + factory DataIf.fromJson(Map json) => _$DataIfFromJson(json); + Map toJson() => _$DataIfToJson(this); +} diff --git a/lib/oto/data/pipeline_data.g.dart b/lib/oto/data/pipeline_data.g.dart new file mode 100644 index 0000000..06e871e --- /dev/null +++ b/lib/oto/data/pipeline_data.g.dart @@ -0,0 +1,36 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'pipeline_data.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +DataPipeline _$DataPipelineFromJson(Map json) => DataPipeline() + ..id = json['id'] as String + ..workflow = json['workflow'] as List; + +Map _$DataPipelineToJson(DataPipeline instance) => + { + 'id': instance.id, + 'workflow': instance.workflow, + }; + +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?; + +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, + }; diff --git a/lib/oto/file/copy.dart b/lib/oto/file/copy.dart index f76c19c..7b8ed2d 100644 --- a/lib/oto/file/copy.dart +++ b/lib/oto/file/copy.dart @@ -4,7 +4,7 @@ import 'dart:io'; import 'package:dart_framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; class Copy extends Command { @override diff --git a/lib/oto/file/delete.dart b/lib/oto/file/delete.dart index d87b4b7..5677a96 100644 --- a/lib/oto/file/delete.dart +++ b/lib/oto/file/delete.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:dart_framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; class Delete extends Command { @override diff --git a/lib/oto/file/rename.dart b/lib/oto/file/rename.dart index c0d10bf..9db976c 100644 --- a/lib/oto/file/rename.dart +++ b/lib/oto/file/rename.dart @@ -5,7 +5,7 @@ import 'package:path/path.dart' as path; import 'package:dart_framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; class Rename extends Command { @override diff --git a/lib/oto/shell/shell.dart b/lib/oto/shell/shell.dart index 36f8c7f..5f87207 100644 --- a/lib/oto/shell/shell.dart +++ b/lib/oto/shell/shell.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:dart_framework/platform/process.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; class Shell extends Command { @override diff --git a/lib/oto/uploader/uploader.dart b/lib/oto/uploader/uploader.dart index 4d02a57..032ddad 100644 --- a/lib/oto/uploader/uploader.dart +++ b/lib/oto/uploader/uploader.dart @@ -4,7 +4,7 @@ import 'dart:io'; import 'package:path/path.dart' as path; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; import 'package:oto_cli/oto/uploader/ftp.dart'; import 'package:dart_framework/utils/path.dart'; diff --git a/lib/oto/util/execute_app.dart b/lib/oto/util/execute_app.dart index 66180fb..f180870 100644 --- a/lib/oto/util/execute_app.dart +++ b/lib/oto/util/execute_app.dart @@ -2,7 +2,7 @@ import 'dart:async'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; import 'package:dart_framework/platform/process.dart'; class ExecuteApp extends Command { diff --git a/lib/oto/util/publish_ios.dart b/lib/oto/util/publish_ios.dart index bbfe857..611ab19 100644 --- a/lib/oto/util/publish_ios.dart +++ b/lib/oto/util/publish_ios.dart @@ -3,7 +3,7 @@ import 'dart:io'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; import 'package:dart_framework/utils/path.dart'; // ignore: depend_on_referenced_packages import 'package:path/path.dart' as path; diff --git a/lib/oto/util/slack.dart b/lib/oto/util/slack.dart index 34ae4fc..f98df61 100644 --- a/lib/oto/util/slack.dart +++ b/lib/oto/util/slack.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:dart_framework/utils/system_util.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; import 'package:color/color.dart'; import 'package:dart_framework/utils/slack/slack_sender.dart'; diff --git a/lib/oto/util/zip.dart b/lib/oto/util/zip.dart index 4cd2c5c..faac463 100644 --- a/lib/oto/util/zip.dart +++ b/lib/oto/util/zip.dart @@ -5,7 +5,7 @@ import 'package:archive/archive_io.dart'; import 'package:dart_framework/utils/path.dart'; import 'package:oto_cli/oto/application.dart'; import 'package:oto_cli/oto/command.dart'; -import 'package:oto_cli/oto/data/data.dart'; +import 'package:oto_cli/oto/data/command_data.dart'; class Zip extends Command { @override