pipeline initial commit

This commit is contained in:
leedongmyung[desktop] 2023-11-19 17:21:35 +09:00
parent c1d6978ce9
commit 9b48d80392
26 changed files with 283 additions and 45 deletions

7
.vscode/launch.json vendored
View file

@ -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",

View file

@ -30,7 +30,7 @@ pipeline:
#일반적인 while문과 동일
- while:
condition: <property:result> [bool]
condition-bool: <property:result>
do:
- async: <command:buildDart>
- exec: <command:zip#1>
@ -42,7 +42,7 @@ pipeline:
true:
#조건문 내에도 선언 가능, 반대도 가능
- while:
condition: <property:result> < 10 [int]
condition-int: <property:result> < 10
do:
- exec: <command:buildDart#1>
#일반적인 switch구문과 동일
@ -90,5 +90,4 @@ commands:
- <property:workspace>/release/oto_cli
- <property:workspace>/release/test
rersult:
success: <property:zipResult>
zipPath: <property:zipPath>

43
assets/pipeline-test.yaml Normal file
View file

@ -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: <property:test> == <property:result>
on-false:
- exe: <command:buildDartCompile#1>
commands:
### Version 쓰기
- command: CreateAppData
id: appData
param:
scm: Git
name: OTO
relativeAssetPath: assets/data
returnVersion: "<!common.version>"
returnHash: "<!common.hash>"
### 실행가능한 파일로 빌드
- command: BuildDart
id: buildDart
param: {}
### 최종 zip 파일 형태로 저장
- command: Zip
id: zip
param:
zipFile: "<!common.workspace>/release/oto_win_v<!common.version>.zip"
zipList:
- "<!common.workspace>/release/oto_cli.exe"

View file

@ -1,5 +1,5 @@
---
common:
property:
workspace: "."
commands:

View file

@ -1,5 +1,5 @@
---
common:
property:
workspace: "."
commands:

View file

@ -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<BuildType, DataComposer> _mapComposer = {
BuildType.test: DataComposerTest(),
BuildType.jenkins: DataComposerJenkins(),
BuildType.file: DataComposerFile()
final Map<BuildType, DataComposer Function()> _mapComposer = {
BuildType.test: () => DataComposerTest(),
BuildType.jenkins: () => DataComposerJenkins(),
BuildType.file: () => DataComposerFile()
};
Map<String, dynamic>? _property;
Map<String, dynamic>? get property {
return _property;
}
final Map<String, PipelineExecutor Function()> taskMap = {
'exe': () => PipelineExec(),
'async': () => PipelineAsync(),
'if': () => PipelineIf(),
/*'while': () => PipelineWhile(),
'wait-until': () => PipelineWaitUntil(),
'switch': () => PipelineSwitch(),*/
};
DataJenkins? _jenkinsData;
DataJenkins? get jenkinsData {
return _jenkinsData;
Map<String, dynamic>? property;
Map<String, DataCommand> dataCommandMap = {};
DataJenkins? jenkinsData;
bool pipelineInitialize(List<dynamic> list) {
for (Map<String, dynamic> item in list) {}
return false;
}
Future<void> 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<dynamic> 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<String, dynamic>? getMapFromYamlA(String yamlStr) {
Map<String, dynamic>? 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<String, dynamic> set);
Future execute();
}
class PipelineExec implements PipelineExecutor {
@override
bool initialize(Map<String, dynamic> set) {
return false;
}
@override
Future execute() async {
return simpleFuture;
}
}
class PipelineAsync implements PipelineExecutor {
@override
bool initialize(Map<String, dynamic> set) {
return false;
}
@override
Future execute() async {
return simpleFuture;
}
}
class PipelineIf implements PipelineExecutor {
@override
bool initialize(Map<String, dynamic> set) {
return false;
}
@override
Future execute() async {
return simpleFuture;
}
}
//############################ DataComposer ##########################//
abstract class DataComposer {
DataJenkins? jenkinsData;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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 }

View file

@ -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';

View file

@ -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';

View file

@ -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<String, dynamic> common;
late Map<String, dynamic> property;
late DataPipeline? pipeline;
late List<DataCommand> commands;
DataBuild();
@ -22,6 +24,7 @@ class DataCommand {
DataCommand();
late CommandType command;
late String id;
late dynamic param;
String get name {

View file

@ -1,19 +1,19 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'data.dart';
part of 'command_data.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DataBuild _$DataBuildFromJson(Map<String, dynamic> json) => DataBuild()
..common = json['common'] as Map<String, dynamic>
..property = json['property'] as Map<String, dynamic>
..commands = (json['commands'] as List<dynamic>)
.map((e) => DataCommand.fromJson(e as Map<String, dynamic>))
.toList();
Map<String, dynamic> _$DataBuildToJson(DataBuild instance) => <String, dynamic>{
'common': instance.common,
'property': instance.property,
'commands': instance.commands,
};

View file

@ -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<dynamic> workflow;
DataPipeline();
factory DataPipeline.fromJson(Map<String, dynamic> json) =>
_$DataPipelineFromJson(json);
Map<String, dynamic> 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<dynamic>? on_true;
@JsonKey(name: 'on-false')
late List<dynamic>? 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<String, dynamic> json) => _$DataIfFromJson(json);
Map<String, dynamic> toJson() => _$DataIfToJson(this);
}

View file

@ -0,0 +1,36 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'pipeline_data.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
DataPipeline _$DataPipelineFromJson(Map<String, dynamic> json) => DataPipeline()
..id = json['id'] as String
..workflow = json['workflow'] as List<dynamic>;
Map<String, dynamic> _$DataPipelineToJson(DataPipeline instance) =>
<String, dynamic>{
'id': instance.id,
'workflow': instance.workflow,
};
DataIf _$DataIfFromJson(Map<String, dynamic> 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<dynamic>?
..on_false = json['on_false'] as List<dynamic>?;
Map<String, dynamic> _$DataIfToJson(DataIf instance) => <String, dynamic>{
'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,
};

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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';

View file

@ -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 {

View file

@ -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;

View file

@ -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';

View file

@ -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