update files

This commit is contained in:
leedongmyung(desktop) 2024-09-22 16:47:02 +09:00
parent 963e96be85
commit 0c1bc79635
62 changed files with 3701 additions and 369 deletions

View file

@ -1,15 +1,17 @@
---
property:
workspace: .
revision: c65a8bb
revision: 24c9423
valueTest: 15.3
pipeline:
id: main
workflow:
# - async: git
- exe: git
- exe: set-value
- exe: print
- exe: buildDart
# - exe: buildDart
# - exe: json-reader
@ -29,6 +31,7 @@ pipeline:
# - async: git-count
# - wait-until-seconds: 10
# - wait-until-string: <!state.git-count> != complete
# - async: git-rev
@ -53,6 +56,25 @@ pipeline:
# - exe: zip
commands:
### 파이프라인 실행도중 값 세팅
- command: SetValue
id: set-value
param:
values-string:
stringTest: Test!
values-int:
intTest: 12
values-float:
floatTest: <!property.valueTest>
values-bool:
boolTest: true
### Print
- command: Print
id: print
param:
message: this is test message / <!property.stringTest> / <!property.intTest> / <!property.floatTest> / <!property.boolTest>
### 콜백이 필요없는 단순 Git 명령 호출
- command: Git
id: git
@ -70,6 +92,19 @@ commands:
- fetch origin
- reset --hard origin/master
### Git 로컬로 체크아웃
- command: GitCheckout
id: git-checkout
param:
branch: main
execute-pull: true
### Git Push
- command: GitPush
id: git-push
param:
branch: main
### 깃 리비전 정보 저장
- command: GitRev
id: git-rev
@ -86,14 +121,10 @@ commands:
- command: JsonReader
id: json-reader
param:
path: ./assets/data/app_data.json
json: <!property.payload>
pair:
- from: gitHash
to: <!property.old-git-rev>
- from: version
to: <!property.old-version>
- from: gitCount
to: <!property.old-git-count>
- from: deleted
setValue: <@property.deleted>
### Version 쓰기
- command: CreateAppData
@ -117,3 +148,28 @@ commands:
zipFile: "<!property.workspace>/release/oto_win_v<!property.version>.zip"
zipList:
- "<!property.workspace>/release/oto_cli.exe"
- command: AwsCli
id: aws-cli
param:
sub-command: s3api get-object
args:
- --profile vo-stage
- --bucket vo-stage-deploy
- --key stage/webserver/revision/api.jar
- api-0.0.1.jar
- command: Docker
id: docker
param:
sub-command: stop
args:
- web
- command: Gradle
id: gradle
param:
args:
- -p backend
- clean
- build

View file

View file

@ -9,10 +9,15 @@ for /F "skip=2 tokens=1,2*" %%G in ('%SystemRoot%\System32\reg.exe query "HKCU\E
if /I "%%H" == "REG_EXPAND_SZ" (set "PathExpand=1" & set "PathUser=%%I") else if /I "%%H" == "REG_SZ" set "PathUser=%%I"
)
PATH=%PathSystem%;%PathUser%
PATH=%PathSystem%;%PathUser%;%SystemRoot%\System32
echo %PATH%
SET BuildData > build_data.conf
IF [%1]==[] (
SET BuildData > build_data.conf
) ELSE (
SET %1 > build_data.conf
)
SET BUILDER=%~dp0
cd "%BUILDER%..\..\.."

View file

@ -11,7 +11,7 @@ for /F "skip=2 tokens=1,2*" %%G in ('%SystemRoot%\System32\reg.exe query "HKCU\E
if /I "%%H" == "REG_EXPAND_SZ" (set "PathExpand=1" & set "PathUser=%%I") else if /I "%%H" == "REG_SZ" set "PathUser=%%I"
)
PATH=%PathSystem%;%PathUser%
PATH=%PathSystem%;%PathUser%;%SystemRoot%\System32
echo %PATH%
: cd ../dart_framework && git pull origin master
: cd "../%JOB_NAME%"

View file

@ -1,3 +1,5 @@
source ~/.zshrc
echo $PATH
BASEDIR=$(dirname $0)
echo "===> Script location: ${BASEDIR}"
cd ${BASEDIR}/../../..

View file

@ -1,3 +1,4 @@
source ~/.zshrc
echo $PATH
echo "Current workspace: ${PWD}"

View file

@ -0,0 +1,40 @@
---
property:
workspace: C:/jenkins/workspace/VirtualOffice_PlayServer/Server/MetaVServer/Server/Src
deployPath: C:/Server
enviroment: devClient
pipeline:
id: main
workflow:
- exe: msbuild
- exe: print
- exe: copy
commands:
### MSBuild
- command: BuildMSBuild
id: msbuild
param:
projectFile: Server.sln
config: Release
type: Rebuild
### Print
- command: Print
id: print
param:
message: build complete
### Copy
- command: Copy
id: copy
param:
ignorePattern:
- servercfg.ini
- StartServer.bat
- StopServer.bat
copyMap:
"<!property.workspace>/Release64/*": "<!property.deployPath>/<!property.enviroment>"

View file

@ -0,0 +1,59 @@
---
property:
workspace: .
arr1:
- This is message 1
- This is message 2
- This is message 3
- This is message 4
map:
test1: This is message 1
test2: This is message 2
test3: This is message 3
test4: This is message 4
arr2:
- innter arr message 1
- innter arr message 2
- innter arr message 3
- innter arr message 4
pipeline:
id: main
workflow:
# list foreach
- foreach:
iterator: <!property.arr1>
setValue: <@property.element1>
on-do:
- exe: print1
# innter foreach
- foreach:
iterator: <!property.arr2>
setValue: <@property.element2>
on-do:
- exe: print2
# map foreach
- foreach:
iterator: <!property.map>
# setKey is optional
setKey: <@property.keyName>
setValue: <@property.element>
on-do:
- exe: print3
commands:
- command: Print
id: print1
param:
message: <!property.element1>
- command: Print
id: print2
param:
message: <!property.element2>
- command: Print
id: print3
param:
message: <!property.keyName> - <!property.element>

View file

@ -0,0 +1,59 @@
---
property:
workspace: .
arr1:
- This is message 1
- This is message 2
- This is message 3
- This is message 4
map:
test1: This is message 1
test2: This is message 2
test3: This is message 3
test4: This is message 4
arr2:
- innter arr message 1
- innter arr message 2
- innter arr message 3
- innter arr message 4
pipeline:
id: main
workflow:
# list foreach
- foreach:
iterator: <!property.arr1>
setValue: <@property.element1>
on-do:
- exe: print1
# innter foreach
- foreach:
iterator: <!property.arr2>
setValue: <@property.element2>
on-do:
- exe: print2
# map foreach
- foreach:
iterator: <!property.map>
# setKey is optional
setKey: <@property.keyName>
setValue: <@property.element>
on-do:
- exe: print3
commands:
- command: Print
id: print1
param:
message: <!property.element1>
- command: Print
id: print2
param:
message: <!property.element2>
- command: Print
id: print3
param:
message: <!property.keyName> - <!property.element>

View file

@ -9,8 +9,8 @@ commands:
scm: Git
name: OTO
relativeAssetPath: assets/data
returnVersion: "<!common.version>"
returnHash: "<!common.hash>"
return-version: "<!property.version>"
return-hash: "<!property.hash>"
### 프로젝트 패키지 업데이트
- command: BuildDart
@ -26,6 +26,6 @@ commands:
### 최종 zip 파일 형태로 저장
- command: Zip
param:
zipFile: "<!common.workspace>/release/oto_osx_v<!common.version>.zip"
zipFile: "<!property.workspace>/release/oto_osx_v<!property.version>.zip"
zipList:
- "<!common.workspace>/release/oto_service_cli"
- "<!property.workspace>/release/oto_service_cli"

View file

@ -9,8 +9,8 @@ commands:
scm: Git
name: OTO
relativeAssetPath: assets/data
returnVersion: "<!common.version>"
returnHash: "<!common.hash>"
return-version: "<!property.version>"
return-hash: "<!property.hash>"
### 실행가능한 파일로 빌드
- command: BuildDartCompile
@ -21,6 +21,6 @@ commands:
### 최종 zip 파일 형태로 저장
- command: Zip
param:
zipFile: "<!common.workspace>/release/oto_win_v<!common.version>.zip"
zipFile: "<!property.workspace>/release/oto_win_v<!property.version>.zip"
zipList:
- "<!common.workspace>/release/oto_cli.exe"
- "<!property.workspace>/release/oto_cli.exe"

View file

@ -310,7 +310,8 @@ class _PrinterUnix extends Printer {
}
var temp = await getTempFile(message.toString(), 'sh');
await Process.run('zsh', [temp.path]).then((ProcessResult result) {
var shellExe = Platform.isMacOS ? 'zsh' : 'bash';
await Process.run(shellExe, [temp.path]).then((ProcessResult result) {
print(result.stdout);
});
await temp.delete();

View file

@ -12,6 +12,7 @@ import 'package:oto_cli/oto/data/command_data.dart';
import 'package:oto_cli/oto/data/jenkins_data.dart';
import 'package:oto_cli/oto/core/data_composer.dart';
import 'package:yaml/yaml.dart';
import 'package:path/path.dart' as pathlib;
enum BuildType { jenkins, test, file }
@ -21,6 +22,16 @@ class Application {
Application._privateConstructor();
static final Application _instance = Application._privateConstructor();
static Application get instance => _instance;
static String get current {
if(Application.instance.buildType == BuildType.jenkins)
{
return Platform.environment['WORKSPACE']!;
}
else
{
return pathlib.current;
}
}
final Map<BuildType, DataComposer Function()> _mapComposer = {
BuildType.test: () => DataComposerTest(),
@ -28,13 +39,19 @@ class Application {
BuildType.file: () => DataComposerFile()
};
DataJenkins? jenkinsData;
DataCommon? commonData;
Map<String, dynamic> property = {};
Map<String, CommandState> commandStates = {};
Map<String, DataCommand> dataCommandMap = {};
late Pipeline pipeline;
late BuildType _buildType;
get buildType
{
return _buildType;
}
Future<void> build(BuildType buildType, {String? yamlContent}) async {
_buildType = buildType;
setUTF8();
// var envArgs = envArguments(arguments);
@ -42,7 +59,7 @@ class Application {
try {
var composer = _mapComposer[buildType]!();
await composer.compose(yamlContent, printBuildStep);
jenkinsData = composer.jenkinsData;
commonData = composer.commonData;
DataBuild? build =
DataBuild.fromJson(getMapFromYamlA(composer.buildYaml)!);
await CLI.println(
@ -50,34 +67,38 @@ class Application {
color: Color.magenta);
print(composer.buildYaml);
property = build.property;
property = build.property ?? {};
if(!property.containsKey('workspace'))
{
property['workspace'] = current;
}
property = Command.replaceAllTagsMap(property, replace: true);
//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 validateResult =
Pipeline.pipelineInitialize(build.pipeline!.workflow);
if (!validateResult.enable) {
for (var command in build.commands) {
if (dataCommandMap.containsKey(command.id)) {
var ex = ExceptionData();
ex.phase = 'Validate Pipeline';
ex.message = validateResult.message;
ex.phase = 'Validate command list';
ex.message = 'Duplicate command id exists: "${command.id}"';
throw Exception(ex);
} else {
dataCommandMap[command.id] = command;
}
pipeline = validateResult.pipeline!;
}
//start build
await pipeline.execute();
//Parse pipeline & validate
var validateResult =
Pipeline.pipelineInitialize(build.pipeline!.workflow);
if (!validateResult.enable) {
var ex = ExceptionData();
ex.phase = 'Validate Pipeline';
ex.message = validateResult.message;
throw Exception(ex);
}
pipeline = validateResult.pipeline!;
//start build
await pipeline.execute();
} on Exception catch (e, stacktace) {
await CLI.printString(e.toString(), color: Color.redStrong);
await CLI.printString(stacktace.toString(), color: Color.yellowStrong);

View file

@ -0,0 +1,25 @@
import 'package:dart_framework/platform/process.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
class AwsCli extends Command {
@override
Future execute(DataCommand command) async {
DataAwsCli data = DataAwsCli.fromJson(getParam(command));
String subCommand = data.subCommand;
List<String> args = data.args;
StringBuffer shell = StringBuffer(getCDPath(workspace));
shell.write(' && aws $subCommand');
for (String arg in args) {
shell.write(' $arg');
}
var process = await ProcessExecutor.start(shell);
return await completeProcess(process, command);
}
}

View file

@ -9,13 +9,14 @@ class CreateAppData extends Command {
@override
Future execute(DataCommand command) async {
var data = DataAppDataCreator.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var data = DataAppDataCreator.fromJson(getParam(command));
var appData = await AppDataManager.to
.create(data.scm, workspace, data.relativeAssetPath, data.name);
await setReturn(data.return_version, appData.version);
await setReturn(data.return_hash, appData.gitHash.substring(0, 7));
await setProperty(data.setVersion, appData.version);
await setProperty(data.setHash, appData.gitHash.substring(0, 7));
if(data.setCount != null) await setProperty(data.setCount!, appData.gitCount.toString());
if(data.setDate != null) await setProperty(data.setDate!, appData.buildDate);
return complete(0, command);
}
}

View file

@ -1,5 +1,6 @@
import 'dart:async';
import 'package:dart_framework/platform/process.dart';
import 'package:dart_framework/utils/system_util.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
@ -8,15 +9,12 @@ class BuildDart extends Command {
Future<StringBuffer> appendShell(
StringBuffer shell, DataCommand command) async {
var c = Completer<StringBuffer>();
c.complete(shell);
return c.future;
return dataFutrue(shell);
}
@override
Future execute(DataCommand command) async {
var data = DataBuildDart.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var data = DataBuildDart.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
shell.write(' && flutter clean');
@ -31,7 +29,6 @@ class BuildDart extends Command {
var process = await ProcessExecutor.start(await appendShell(shell, command),
printStderr: false);
return await complete(await process.process.exitCode, command,
errorMessage: process.stderr.toString());
return await completeProcess(process, command);
}
}

View file

@ -10,9 +10,8 @@ class BuildDartCompile extends BuildDart {
Future<StringBuffer> appendShell(
StringBuffer shell, DataCommand command) async {
var c = Completer<StringBuffer>();
var data = DataBuildDartCompile.fromJson(command.param);
var data = DataBuildDartCompile.fromJson(getParam(command));
var extension = getExeExtension();
var workspace = getWorkspace(data.workspace);
var binPath = path.join(workspace, 'bin');
//find build target
@ -24,7 +23,7 @@ class BuildDartCompile extends BuildDart {
break;
}
findedDartFile = path.join(workspace, 'bin', findedDartFile);
var targetDartFile = replaceTag(data.targetDartFile ?? findedDartFile);
var targetDartFile = data.targetDartFile ?? findedDartFile;
//clear build path
var buildFolderName = 'release';

View file

@ -8,8 +8,7 @@ class BuildDotNet extends Command {
@override
Future execute(DataCommand command) async {
var data = DataBuildDotNet.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var data = DataBuildDotNet.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
shell.write(
@ -18,7 +17,6 @@ class BuildDotNet extends Command {
var process = await ProcessExecutor.start(shell,
workspace: workspace, printStderr: false);
return complete(await process.process.exitCode, command,
errorMessage: process.stderr.toString());
return await completeProcess(process, command);
}
}

View file

@ -1,74 +1,213 @@
import 'dart:async';
import 'dart:io';
import 'package:oto_cli/oto/commands/build/build_flutter.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
import 'package:dart_framework/platform/process.dart';
import 'package:path/path.dart' as path;
class BuildiOS extends Command {
Function? get error => null;
@override
Future execute(DataCommand command) async {
var data = DataBuildiOS.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var xcworkspaceFilePath = getPathNormal(data.xcworkspaceFilePath);
var destination = data.destination ?? 'generic/platform=iOS build';
var data = DataBuildiOS.fromJson(getParam(command));
var xcodeProjectPath = data.xcworkspaceFilePath ?? data.xcodeProjectFilePath;
if(xcodeProjectPath == null) throw Exception('"xcodeProjectFilePath" or "xcworkspaceFilePath" must set at least one.');
var xcworkspaceFilePath = Command.getPathNormal(xcodeProjectPath);
var os = 'iOS';
if(data.os != null)
{
if(data.os == BuildPlatform.Macos)
{
os = 'macOS';
}
}
var destination = "'generic/platform=$os'";
var cleanPod = data.cleanPod ?? false;
var xcodeProjectParentPath = Directory(xcworkspaceFilePath).parent.path;
var podFile = File('$xcodeProjectParentPath/PodFile');
var project = '';
if(data.xcworkspaceFilePath != null) {
project = '-workspace $xcodeProjectPath';
} else {
project = '-project $xcodeProjectPath';
}
var configuration = '';
if(data.configuration != null)
{
configuration = ' -configuration ${data.configuration}';
}
var derivedDataPath = '';
if(data.derivedDataPath != null)
{
derivedDataPath = ' -derivedDataPath ${data.configuration}';
}
var settings = '';
if(data.settings != null)
{
var map = data.settings!;
for(var item in map.entries)
{
settings += ' ${item.key}="${item.value}"';
}
}
var shell = StringBuffer();
shell.write('security unlock-keychain -pr0bins');
shell.write(' && cd $workspace/ios');
shell.write('security unlock-keychain -p${data.macPassword}');
shell.write(' && cd $xcodeProjectParentPath');
shell.write(' && export LANG=en_US.UTF-8');
shell.write(' && rm -rf Pods');
shell.write(' && rm -rf Podfile.lock');
if (cleanPod) {
shell.write(' && pod cache clean --all');
shell.write(' && pod repo update');
shell.write(' && pod install --repo-update');
} else {
shell.write(' && pod install');
if(podFile.existsSync())
{
shell.write(' && rm -rf Pods');
shell.write(' && rm -rf Podfile.lock');
if (cleanPod) {
shell.write(' && pod cache clean --all');
shell.write(' && pod repo update');
shell.write(' && pod install --repo-update');
} else {
shell.write(' && pod install');
}
}
shell.write(
' && xcodebuild -workspace $xcworkspaceFilePath -scheme ${data.scheme} -destination $destination');
' && xcodebuild $project -scheme ${data.scheme} -destination $destination$configuration$derivedDataPath$settings clean build');
var processData = await ProcessExecutor.start(shell,
workspace: workspace, printStderr: false);
var exitCode = await processData.process.exitCode;
var process = await ProcessExecutor.start(shell, printStderr: false);
var exitCode = await process.process.exitCode;
var success = exitCode == 0;
if (success) {
return complete(0, command);
return await completeProcess(process, command);
} else {
if (exitCode == 31) {
data.cleanPod = true;
command.param = data.toJson();
return await execute(command);
} else {
return complete(exitCode, command,
errorMessage: processData.stderr.toString());
return await completeProcess(process, command);
}
}
}
}
class CodeSign extends Command {
Function? get error => null;
@override
Future execute(DataCommand command) async {
var data = DataCodeSign.fromJson(getParam(command));
var entitlement = '';
if(data.entitlementPath == null)
{
entitlement = ' --entitlements "${data.entitlementPath}"';
}
var shell = StringBuffer(getCDPath(workspace));
shell.write(
' && codesign --deep --force --verify --verbose --timestamp --options runtime$entitlement --sign "${data.certificationName}" "${data.appPath}"');
var process = await ProcessExecutor.start(shell,
workspace: workspace, printStderr: false);
return await completeProcess(process, command);
}
}
class CodeSignVerify extends Command {
Function? get error => null;
@override
Future execute(DataCommand command) async {
var data = DataCodeSignVerify.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
shell.write(' && codesign -verify -verbose "${data.appPath}"');
shell.write(' && spctl --assess --verbose "${data.appPath}"');
var process = await ProcessExecutor.start(shell,
workspace: workspace, printStderr: false);
return await completeProcess(process, command);
}
}
class ProductBuild extends Command {
Function? get error => null;
@override
Future execute(DataCommand command) async {
var data = DataProductBuild.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
if(data.scripts != null) {
shell.write(' && chmod a+x "${data.scripts}/postinstall"');
shell.write(' && pkgbuild --identifier "${data.identifier}" --scripts "${data.scripts}" --component "${data.appPath}" --sign "${data.installCertificationName}" --install-location "/Applications" "${data.unsignedResultPath}"');
} else {
shell.write(' && productbuild --component "${data.appPath}" /Applications --sign "${data.installCertificationName}" "${data.unsignedResultPath}"');
}
shell.write(' && productsign --sign "${data.installCertificationName}" "${data.unsignedResultPath}" "${data.signedResultPath}"');
var process = await ProcessExecutor.start(shell,
workspace: workspace, printStderr: false);
return await completeProcess(process, command);
}
}
class Notarize extends Command {
Function? get error => null;
@override
Future execute(DataCommand command) async {
var data = DataNotarize.fromJson(getParam(command));
var isApp = path.extension(data.resultPath).toLowerCase().contains('app');
var shell = StringBuffer(getCDPath(workspace));
shell.write(' && security unlock-keychain -p${data.macPassword}');
shell.write(' && xcrun notarytool store-credentials "${data.bundleName}" --apple-id "${data.appleAccount}" --team-id "${data.teamId}" --password "${data.applePassword}"');
var notaryTarget = data.resultPath;
var appFileName = '';
var zipFileName = '';
if(isApp) {
var dir = Directory(data.resultPath).parent;
appFileName = path.basename(data.resultPath);
zipFileName = '${path.basenameWithoutExtension(data.resultPath)}.zip';
notaryTarget = '${dir.path}/$zipFileName';
shell.write(' && cd ${dir.path}');
shell.write(' && ditto -c -k --sequesterRsrc --keepParent "$appFileName" "$zipFileName"');
}
shell.write(' && xcrun notarytool submit "$notaryTarget" --keychain-profile "${data.bundleName}" --wait');
shell.write(' && xcrun stapler staple "${data.resultPath}"');
if(isApp) {
shell.write(' && rm $zipFileName');
shell.write(' && ditto -c -k --sequesterRsrc --keepParent "$appFileName" "$zipFileName"');
}
var process = await ProcessExecutor.start(shell,
workspace: workspace, printStderr: false);
return await completeProcess(process, command);
}
}
class ArchiveiOS extends Command {
Function? get error => null;
@override
Future execute(DataCommand command) async {
var data = DataArchiveiOS.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var workspacePath = getPathNormal(data.xcworkspaceFilePath);
var archivePath = getPathNormal(data.archivePath);
var data = DataArchiveiOS.fromJson(getParam(command));
var workspacePath = Command.getPathNormal(data.xcworkspaceFilePath);
var archivePath = Command.getPathNormal(data.archivePath);
var destination = data.destination ?? "'generic/platform=iOS'";
var shell = StringBuffer();
shell.write(
'xcodebuild -workspace $workspacePath -scheme ${data.scheme} -archivePath $archivePath archive');
'xcodebuild -workspace $workspacePath -scheme ${data.scheme} -destination $destination -archivePath $archivePath archive');
var processData = await ProcessExecutor.start(shell,
var process = await ProcessExecutor.start(shell,
workspace: workspace, printStderr: false);
return complete(await processData.process.exitCode, command,
errorMessage: processData.stderr.toString());
return await completeProcess(process, command);
}
}
@ -77,20 +216,19 @@ class ExportiOS extends Command {
@override
Future execute(DataCommand command) async {
var data = DataExportiOS.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var archivePath = getPathNormal(data.archivePath);
var exportPath = getPathNormal(data.exportPath);
var exportOptionPlistPath = getPathNormal(data.exportOptionPlistPath);
var data = DataExportiOS.fromJson(getParam(command));
var archivePath = Command.getPathNormal(data.archivePath);
var exportPath = Command.getPathNormal(data.exportPath);
var exportOptionPlistPath =
Command.getPathNormal(data.exportOptionPlistPath);
var shell = StringBuffer();
shell.write(
'xcodebuild -exportArchive -archivePath $archivePath -exportPath $exportPath -exportOptionsPlist $exportOptionPlistPath');
var processData = await ProcessExecutor.start(shell,
var process = await ProcessExecutor.start(shell,
workspace: workspace, printStderr: false);
return complete(await processData.process.exitCode, command,
errorMessage: processData.stderr.toString());
return await completeProcess(process, command);
}
}

View file

@ -0,0 +1,30 @@
// ignore_for_file: constant_identifier_names
import 'dart:async';
import 'dart:io';
import 'package:dart_framework/platform/process.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
enum MSBuildType { Clean, Build, Rebuild }
enum MSBuildConfig { Debug, Release }
class BuildMSBuild extends Command {
Function? get error => null;
@override
Future execute(DataCommand command) async {
var data = DataBuildMSBuild.fromJson(getParam(command));
var param =
'${data.projectFile} /p:Configuration=${data.config.name} /p:Platform=x64 /t:${data.type.name}';
var shell = StringBuffer(getCDPath(workspace));
shell.write(' && msbuild $param');
var process = await ProcessExecutor.start(shell,
decoder: SystemEncoding().decoder, printStderr: false);
return await completeProcess(process, command);
}
}

View file

@ -1,9 +1,10 @@
// ignore_for_file: constant_identifier_names, depend_on_referenced_packages
// ignore_for_file: constant_identifier_names, depend_on_referenced_packages, avoid_init_to_null
import 'dart:async';
import 'dart:io';
import 'package:dart_framework/platform/process.dart';
import 'package:dart_framework/utils/path.dart';
import 'package:dart_framework/utils/system_util.dart';
import 'package:oto_cli/cli/cli.dart';
import 'package:oto_cli/oto/application.dart';
import 'package:oto_cli/oto/commands/build/app_data_creator.dart';
import 'package:oto_cli/oto/commands/build/build_dart.dart';
@ -11,92 +12,220 @@ import 'package:oto_cli/oto/commands/build/build_dart_compile.dart';
import 'package:oto_cli/oto/commands/build/build_dot_net.dart';
import 'package:oto_cli/oto/commands/build/build_flutter.dart';
import 'package:oto_cli/oto/commands/build/build_ios.dart';
import 'package:oto_cli/oto/commands/build/build_msbuild.dart';
import 'package:oto_cli/oto/commands/file/directory.dart';
import 'package:oto_cli/oto/commands/file/file.dart';
import 'package:oto_cli/oto/commands/file/file_diff_check.dart';
import 'package:oto_cli/oto/commands/git/git.dart';
import 'package:oto_cli/oto/commands/util/jira.dart';
import 'package:oto_cli/oto/commands/aws/awscli.dart';
import 'package:oto_cli/oto/commands/docker/docker.dart';
import 'package:oto_cli/oto/commands/git/git_hub.dart';
import 'package:oto_cli/oto/commands/gradle/gradle.dart';
import 'package:oto_cli/oto/commands/jira/jira.dart';
import 'package:oto_cli/oto/commands/process/process.dart';
import 'package:oto_cli/oto/commands/proto/protobuf.dart';
import 'package:oto_cli/oto/commands/util/json.dart';
import 'package:oto_cli/oto/commands/util/print.dart';
import 'package:oto_cli/oto/commands/util/set_value.dart';
import 'package:oto_cli/oto/commands/util/string_util.dart';
import 'package:oto_cli/oto/commands/web/web.dart';
import 'package:oto_cli/oto/data/command_data.dart';
import 'package:oto_cli/oto/data/jenkins_data.dart';
import 'package:oto_cli/oto/commands/file/delete.dart';
import 'package:oto_cli/oto/commands/file/rename.dart';
import 'package:oto_cli/oto/commands/shell/shell.dart';
import 'package:oto_cli/oto/commands/file/copy.dart';
import 'package:oto_cli/oto/commands/util/execute_app.dart';
import 'package:oto_cli/oto/commands/util/publish_ios.dart';
import 'package:oto_cli/oto/commands/util/slack.dart';
import 'package:oto_cli/oto/commands/util/zip.dart';
import 'package:oto_cli/oto/commands/uploader/uploader.dart';
import 'package:path/path.dart' as pathlib;
import 'package:oto_cli/oto/pipeline/pipeline_exe_handle.dart';
enum CommandType {
SimpleCommand,
Print,
SetValue,
CreateAppData,
BuildDart,
BuildFlutter,
BuildDartCompile,
BuildDotNet,
BuildiOS,
BuildMSBuild,
CodeSign,
CodeSignVerify,
ProductBuild,
Notarize,
ArchiveiOS,
ExportiOS,
PublishiOS,
ExecuteApp,
Upload,
Copy,
Rename,
Delete,
FileDiffCheck,
FileRead,
FileWrite,
DirectoryCreate,
Slack,
SlackBuild,
StringSub,
StringReplace,
Jira,
Zip,
Shell,
ShellFile,
Git,
GitPush,
GitCheckout,
GitRev,
GitCount,
JsonReader
GitHub,
GitHubPullRequestCreate,
GitHubPullRequestList,
GitHubPullRequestClose,
Protobuf,
JsonReader,
JsonReaderFile,
AwsCli,
Docker,
Gradle,
WebRequest,
WebFile,
ProcessPortUse,
ProcessRun,
ProcessKill
}
abstract class Command {
static final Map<CommandType, Command> _commandMap = {
CommandType.SimpleCommand: SimpleCommand(),
CommandType.CreateAppData: CreateAppData(),
CommandType.BuildDart: BuildDart(),
CommandType.BuildFlutter: BuildFlutter(),
CommandType.BuildDartCompile: BuildDartCompile(),
CommandType.BuildDotNet: BuildDotNet(),
CommandType.BuildiOS: BuildiOS(),
CommandType.ArchiveiOS: ArchiveiOS(),
CommandType.ExportiOS: ExportiOS(),
CommandType.PublishiOS: PublishiOS(),
CommandType.ExecuteApp: ExecuteApp(),
CommandType.Upload: Uploader(),
CommandType.Copy: Copy(),
CommandType.Rename: Rename(),
CommandType.Delete: Delete(),
CommandType.Slack: Slack(),
CommandType.SlackBuild: SlackBuild(),
CommandType.Jira: Jira(),
CommandType.Zip: Zip(),
CommandType.Shell: Shell(),
CommandType.Git: Git(),
CommandType.GitRev: GitRev(),
CommandType.GitCount: GitCount(),
CommandType.JsonReader: JsonReader()
static final Map<CommandType, Command Function()> _commandMap = {
CommandType.SimpleCommand: () => SimpleCommand(),
CommandType.Print: () => PrintCommand(),
CommandType.SetValue: () => SetValueCommand(),
CommandType.CreateAppData: () => CreateAppData(),
CommandType.BuildDart: () => BuildDart(),
CommandType.BuildFlutter: () => BuildFlutter(),
CommandType.BuildDartCompile: () => BuildDartCompile(),
CommandType.BuildDotNet: () => BuildDotNet(),
CommandType.BuildiOS: () => BuildiOS(),
CommandType.BuildMSBuild: () => BuildMSBuild(),
CommandType.CodeSign: () => CodeSign(),
CommandType.CodeSignVerify: () => CodeSignVerify(),
CommandType.ProductBuild: () => ProductBuild(),
CommandType.Notarize: () => Notarize(),
CommandType.ArchiveiOS: () => ArchiveiOS(),
CommandType.ExportiOS: () => ExportiOS(),
CommandType.PublishiOS: () => PublishiOS(),
CommandType.Upload: () => Uploader(),
CommandType.Copy: () => Copy(),
CommandType.Rename: () => Rename(),
CommandType.Delete: () => Delete(),
CommandType.FileDiffCheck: () => FileDiffCheck(),
CommandType.FileRead: () => FileRead(),
CommandType.FileWrite: () => FileWrite(),
CommandType.DirectoryCreate: () => DirectoryCreate(),
CommandType.Slack: () => Slack(),
CommandType.SlackBuild: () => SlackBuild(),
CommandType.StringSub: () => StringSub(),
CommandType.StringReplace: () => StringReplace(),
CommandType.Jira: () => Jira(),
CommandType.Zip: () => Zip(),
CommandType.Shell: () => Shell(),
CommandType.ShellFile: () => ShellFile(),
CommandType.Git: () => Git(),
CommandType.GitPush: () => GitPush(),
CommandType.GitCheckout: () => GitCheckout(),
CommandType.GitRev: () => GitRev(),
CommandType.GitCount: () => GitCount(),
CommandType.GitHub: () => GitHub(),
CommandType.GitHubPullRequestCreate: () => GitHubPullRequestCreate(),
CommandType.GitHubPullRequestList: () => GitHubPullRequestList(),
CommandType.GitHubPullRequestClose: () => GitHubPullRequestClose(),
CommandType.Protobuf: () => Protobuf(),
CommandType.JsonReader: () => JsonReader(),
CommandType.JsonReaderFile: () => JsonReaderFile(),
CommandType.AwsCli: () => AwsCli(),
CommandType.Docker: () => Docker(),
CommandType.Gradle: () => Gradle(),
CommandType.WebRequest: () => WebRequest(),
CommandType.WebFile: () => WebFile(),
CommandType.ProcessPortUse: () => ProcessPortUse(),
CommandType.ProcessRun: () => ProcessRun(),
CommandType.ProcessKill: () => ProcessKill()
};
factory Command.byType(CommandType type) {
return _commandMap[type]!;
return _commandMap[type]!();
}
Command();
late String id;
static RegExp regEx = RegExp(r'(<!)([_a-zA-Z0-9.-]+)(>)');
static RegExp regSetEx = RegExp(r'(<@)([_a-zA-Z0-9.-]+)(>)');
static Future setReturnValue(String tag, dynamic value) async {
var match = regEx.firstMatch(tag);
static Map<String, dynamic> replaceAllTagsMap(Map<String, dynamic> map,
{bool replace = false}) {
var newMap = <String, dynamic>{};
var deleteKeys = <String>[];
for (var pair in map.entries) {
var key = pair.key;
var keyReplacedTag = Command.replaceTagValue(key);
if (keyReplacedTag != key) {
deleteKeys.add(key);
}
if (map[key] is String) {
newMap[keyReplacedTag] = Command.replaceTagValue(map[key]);
} else if (map[key] is List) {
newMap[keyReplacedTag] = replaceAllTagsList(map[key], replace: replace);
} else if (map[key] is Map) {
newMap[keyReplacedTag] = replaceAllTagsMap(map[key], replace: replace);
} else {
newMap[keyReplacedTag] = map[key];
}
if (replace) {
map[keyReplacedTag] = newMap[keyReplacedTag];
}
}
if (replace) {
for (var key in deleteKeys) {
map.remove(key);
}
return map;
}
return newMap;
}
static List replaceAllTagsList(List list, {bool replace = false}) {
var newList = <dynamic>[];
for (var i = 0; i < list.length; ++i) {
if (list[i] is String) {
newList.add(Command.replaceTagValue(list[i]));
} else if (list[i] is List) {
newList.add(replaceAllTagsList(list[i]));
} else if (list[i] is Map) {
newList.add(replaceAllTagsMap(list[i]));
} else {
newList.add(list[i]);
}
if (replace) {
list[i] = newList[i];
}
}
if (replace) {
return newList;
}
return newList;
}
static Future setPropertyValue(String tag, dynamic value) async {
var match = regSetEx.firstMatch(tag);
tag = match!.group(2)!;
if (tag.startsWith('property')) {
var key = tag.replaceFirst('property.', '');
Application.instance.property[key] = value;
await CLI.println('[Return] $key : $value', color: Color.yellowStrong);
// await CLI.println('[Return] $key : $value', color: Color.yellowStrong);
print('[Return] $key : $value');
}
return simpleFuture;
}
@ -136,8 +265,32 @@ abstract class Command {
return data;
}
static String replaceTagValue(String raw) {
static String getAbs(String path) {
path = getPathNormal(path);
if (path == '.' || path.startsWith('./') || path.startsWith('.\\')) {
path = path.replaceFirst('.', getPathNormal(Application.current));
}
if (path == '..' || path.startsWith('../') || path.startsWith('..\\')) {
path =
path.replaceFirst('..', '${getPathNormal(Application.current)}/..');
}
return File(path).absolute.path;
}
static String getPathNormal(String path) {
return replaceTagValue(Path.getNormal(path));
}
static dynamic replaceTagValue(String raw) {
var list = regEx.allMatches(raw);
if (list.length == 1) {
var item = list.first;
var sub = list.first.input.substring(item.start, item.end);
if (sub == raw) {
return replaceSingleTagValue(raw);
}
}
for (var match in list) {
var param = match.group(2);
var target = '<!${param!}>';
@ -156,27 +309,34 @@ abstract class Command {
return value;
}
late ExeHandleData? exeHandle = null;
late String _workspace;
String get workspace {
return _workspace;
}
Map<String, dynamic> get property {
return Application.instance.property;
}
DataJenkins? get jenkinsData {
return Application.instance.jenkinsData;
DataCommon? get commonData {
return Application.instance.commonData;
}
String getWorkspace(String? dataWorkspace) {
return getAbs(dataWorkspace ?? jenkinsData!.workspace);
}
String getAbs(String path) {
path = getPathNormal(path);
if (path == '.' || path.startsWith('./') || path.startsWith('.\\')) {
path = path.replaceFirst('.', getPathNormal(pathlib.current));
if (dataWorkspace == null) {
// workspace가 property에 workspace
if (property.containsKey('workspace')) {
return getAbs(property['workspace']);
}
//property에도 workspace
else {
return getAbs(commonData!.workspace);
}
} else {
return getAbs(dataWorkspace);
}
if (path == '..' || path.startsWith('../') || path.startsWith('..\\')) {
path = path.replaceFirst('..', '${getPathNormal(pathlib.current)}/..');
}
return path;
}
String getCDPath(String path) {
@ -187,10 +347,6 @@ abstract class Command {
return '${drive}cd $path';
}
String getPathNormal(String path) {
return replaceTag(Path.getNormal(path));
}
String replaceTag(String raw) {
return Command.replaceTagValue(raw);
}
@ -199,25 +355,98 @@ abstract class Command {
return Command.replaceSingleTagValue(raw);
}
Future setReturn(String tag, dynamic value) async {
await Command.setReturnValue(tag, value);
Future setProperty(String tag, dynamic value) async {
await Command.setPropertyValue(tag, value);
}
Map<String, dynamic> getParam(DataCommand command) {
var map = Command.replaceAllTagsMap(command.param);
map['workspace'] = _workspace = getWorkspace(map['workspace']);
return map;
}
Future execute(DataCommand command) async {
return simpleFuture;
}
Future complete(int exitCode, DataCommand command,
{String? errorMessage, List<int>? passCode}) {
passCode ??= [0];
if (passCode.contains(exitCode)) {
return simpleFuture;
} else {
print('Exit Code: $exitCode');
var data = ExceptionData();
data.phase = command.name;
data.message = errorMessage;
throw Exception(data);
Future executeHandle(DataCommand command, ExeHandleData handleData) async {
exeHandle = handleData;
try
{
return await execute(command);
}
on Exception catch (e)
{
return await exeHandle!.pipelineFail!.execute();
}
}
Future<List<int>> getMergedPassExitCode(
Map<String, dynamic>? param, List<int>? passExitCodes) async {
var c = Completer<List<int>>();
var passExitCodesMerged = [0];
if (param != null) {
var data = DataParam.fromJson(param);
if (data.passExitCodes != null) {
passExitCodesMerged.addAll(data.passExitCodes!);
}
}
if (passExitCodes != null) {
passExitCodesMerged.addAll(passExitCodes);
}
c.complete(passExitCodesMerged);
return c.future;
}
Future completeProcess(ProcessData processData, DataCommand command,
{List<int>? passExitCodes}) async {
var exitCode = await processData.process.exitCode;
var passExitCodesMerge =
await getMergedPassExitCode(command.param, passExitCodes);
String? resultMessage = null;
if (exitCode != 0 && passExitCodesMerge.contains(exitCode)) {
resultMessage = processData.stderr.toString();
}
return await complete(exitCode, command,
errorMessage: processData.stderr.toString(),
passExitCodes: passExitCodes,
resultMessage: resultMessage);
}
Future<dynamic> complete(int exitCode, DataCommand command,
{String? errorMessage,
List<int>? passExitCodes,
String? resultMessage}) async {
var passExitCodesMerge =
await getMergedPassExitCode(command.param, passExitCodes);
if (command.param != null) {
var data = DataParam.fromJson(command.param);
if (data.setExitCode != null) {
await setProperty(data.setExitCode!, exitCode);
}
if (data.setResult != null) {
await setProperty(data.setResult!, resultMessage);
}
}
if(exeHandle == null)
{
if (passExitCodesMerge.contains(exitCode)) {
return simpleFuture;
} else {
print('Exit Code: $exitCode');
var data = ExceptionData();
data.phase = command.name;
data.message = errorMessage;
throw Exception(data);
}
}
else
{
if (passExitCodesMerge.contains(exitCode)) {
return await exeHandle!.pipelineSuccess!.execute();
} else {
return await exeHandle!.pipelineFail!.execute();
}
}
}
}

View file

@ -0,0 +1,25 @@
import 'package:dart_framework/platform/process.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
class Docker extends Command {
@override
Future execute(DataCommand command) async {
DataDocker data = DataDocker.fromJson(getParam(command));
String dockerCommand = data.command;
List<String> args = data.args;
StringBuffer shell = StringBuffer(getCDPath(workspace));
shell.write(' && docker $dockerCommand');
for (String arg in args) {
shell.write(' $arg');
}
var process = await ProcessExecutor.start(shell);
return await completeProcess(process, command);
}
}

View file

@ -8,20 +8,23 @@ import 'package:oto_cli/oto/data/command_data.dart';
class Copy extends Command {
@override
Future execute(DataCommand command) async {
var data = DataCopy.fromJson(command.param);
var data = DataCopy.fromJson(getParam(command));
var isMove = data.isMove == null ? false : data.isMove!;
var isOverwrite = data.isOverwrite == null ? true : data.isOverwrite!;
var entries = data.copyMap.entries;
try {
var ignoredList = <String>[];
for (var entry in entries) {
var start = getPathNormal(entry.key);
var dest = getPathNormal(entry.value);
var start = Command.getPathNormal(entry.key);
var dest = Command.getPathNormal(entry.value);
var destDir = Directory(dest);
var name = Path.getName(start);
if (name == "*") {
//Delete & recreate dest folder
if (destDir.existsSync()) destDir.deleteSync(recursive: true);
destDir.createSync(recursive: true);
if (!destDir.existsSync())
{
destDir.createSync(recursive: true);
}
var startParentStr = Path.getParent(start);
if (startParentStr != null) {
var startParent = Directory(startParentStr);
@ -37,7 +40,7 @@ class Copy extends Command {
await Path.copy(file.path, dest, true,
ignorePattern: data.ignorePattern,
ignoredList: ignoredList,
isMove: isMove);
isMove: isMove, isOverwrite: isOverwrite);
}
}
} else {
@ -68,6 +71,7 @@ class Copy extends Command {
}
} on Exception catch (e) {
print('Copy General Exception: $e');
rethrow;
}
return complete(0, command);
}

View file

@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:io';
import 'package:dart_framework/utils/path.dart';
import 'package:oto_cli/oto/commands/command.dart';
@ -7,15 +8,41 @@ import 'package:oto_cli/oto/data/command_data.dart';
class Delete extends Command {
@override
Future execute(DataCommand command) async {
var data = DataDelete.fromJson(command.param);
var data = DataDelete.fromJson(getParam(command));
try {
var ignoredList = <String>[];
var ignoredList = data.ignorePattern ??= [];
for (var item in data.list) {
var path = getPathNormal(item);
var path = Command.getPathNormal(item);
var name = Path.getName(path);
if (name == "*") {
//Delete & recreate dest folder
} else {}
var dir = Directory(Path.getParent(path)!);
if(dir.existsSync())
{
await dir.delete(recursive: true);
}
} else {
var deletable = true;
for(var ignoreItem in ignoredList)
{
if(name.contains(ignoreItem)) {
deletable = false;
}
}
if(deletable) {
var file = File(path);
if(file.existsSync()) {
await file.delete(recursive: true);
print('Deleted File: ${file.path}');
}
var dir = Directory(path);
if(dir.existsSync()) {
await dir.delete(recursive: true);
print('Deleted Directory: ${dir.path}');
}
}
}
}
if (ignoredList.isNotEmpty) {
@ -26,7 +53,7 @@ class Delete extends Command {
print('======================================================');
}
} on Exception catch (e) {
print('Copy General Exception: $e');
rethrow;
}
return complete(0, command);
}

View file

@ -0,0 +1,19 @@
// ignore_for_file: depend_on_referenced_packages
import 'dart:async';
import 'dart:io';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
class DirectoryCreate extends Command {
@override
Future execute(DataCommand command) async {
var data = DataDirectoryCreate.fromJson(getParam(command));
var dir = Directory(data.path);
if(!dir.existsSync()) {
await dir.create(recursive: true);
print('Directory Created: ${data.path}');
}
return complete(0, command);
}
}

View file

@ -0,0 +1,34 @@
// ignore_for_file: depend_on_referenced_packages
import 'dart:async';
import 'dart:io';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
class FileRead extends Command {
@override
Future execute(DataCommand command) async {
var data = DataFileRead.fromJson(getParam(command));
var file = File(data.path);
var content = '';
if(file.existsSync()) {
content = file.readAsStringSync();
} else {
throw Exception('File not exist - ${data.path}');
}
setProperty(data.setContent, content);
return complete(0, command);
}
}
class FileWrite extends Command {
@override
Future execute(DataCommand command) async {
var data = DataFileWrite.fromJson(getParam(command));
var file = File(data.path);
if(file.existsSync()) file.deleteSync();
await file.writeAsString(data.content);
return complete(0, command);
}
}

View file

@ -0,0 +1,146 @@
// ignore_for_file: depend_on_referenced_packages
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:dart_framework/utils/system_util.dart';
import 'package:file_hasher/file_hasher.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart' as crypto;
class FileDiffCheck extends Command {
@override
Future execute(DataCommand command) async {
var data = DataFileDiffCheck.fromJson(getParam(command));
var exitCode = 0;
var diff = false;
var currentDir = Directory(workspace);
var fileName = getUniqueFileName(data.paths.join(';'));
var tempDir = Directory.systemTemp;
var cacheFolder = Directory('${tempDir.path}/oto/${getUniqueFileName(currentDir.path)}');
if(!cacheFolder.existsSync())
{
cacheFolder.createSync(recursive: true);
}
var cacheFile = File('${cacheFolder.path}/$fileName');
var paths = data.paths;
print('Cache Path: ${cacheFile.path}, Exist: ${cacheFile.existsSync()}');
if(paths.isEmpty)
{
throw Exception('The paths is Empty.');
}
else
{
if(cacheFile.existsSync())
{
var cachedMap = jsonDecode(cacheFile.readAsStringSync()) as Map<String, dynamic>;
var filesHashMap = await getFilesHashMap(paths);
if(cachedMap.length == filesHashMap.length)
{
for(var pair in filesHashMap.entries)
{
if(cachedMap.containsKey(pair.key))
{
var cachedHash = cachedMap[pair.key];
if(cachedHash != pair.value)
{
await saveDiffData(cacheFile, paths);
diff = true;
break;
}
}
else
{
await saveDiffData(cacheFile, paths);
diff = true;
break;
}
}
}
else
{
await saveDiffData(cacheFile, paths);
diff = true;
}
}
else
{
await saveDiffData(cacheFile, paths);
diff = true;
}
}
await setProperty(data.setDiff, diff);
return await complete(exitCode, command);
}
Future saveDiffData(File cacheFile, List<String> paths) async
{
var cachedMap = await getFilesHashMap(paths);
var jsonString = jsonEncode(cachedMap);
await cacheFile.writeAsString(jsonString);
return simpleFuture;
}
String getUniqueFileName(String seed)
{
var fileName = generateMd5(seed);
if(fileName.length > 150)
{
fileName = fileName.substring(0, 150);
}
return fileName;
}
Future<Map<String, dynamic>> getFilesHashMap(List<String> paths) async
{
var c = Completer<Map<String, dynamic>>();
var cachedMap = <String, dynamic>{};
for(var path in paths)
{
var file = File(path);
var type = file.statSync().type;
switch(type)
{
case FileSystemEntityType.directory:
var dir = Directory(path);
var files = dir.listSync();
for(var child in files)
{
if(child is File)
{
await setCachedMapHash(cachedMap, File(child.path));
}
}
break;
case FileSystemEntityType.file:
await setCachedMapHash(cachedMap, file);
break;
default:
throw Exception('File or Directory are not exists: $path');
}
}
c.complete(cachedMap);
return c.future;
}
Future setCachedMapHash(Map<String, dynamic> cachedMap, File file) async
{
cachedMap[file.path] = await FileHasher.hash(file);
return simpleFuture;
}
///Generate MD5 hash
String generateMd5(String data) {
var content = Utf8Encoder().convert(data);
var md5 = crypto.md5;
var digest = md5.convert(content);
return hex.encode(digest.bytes);
}
}

View file

@ -11,12 +11,12 @@ import 'package:oto_cli/oto/data/command_data.dart';
class Rename extends Command {
@override
Future execute(DataCommand command) async {
var data = DataRename.fromJson(command.param);
var data = DataRename.fromJson(getParam(command));
var entries = data.renameMap.entries;
try {
for (var entry in entries) {
var start = getPathNormal(entry.key);
var targetName = replaceTag(entry.value);
var start = Command.getPathNormal(entry.key);
var targetName = entry.value;
var type = Path.getType(start);
var parentPath = Path.getParent(start)!;
var newPath = path.join(parentPath, targetName);

View file

@ -5,55 +5,108 @@ import 'package:dart_framework/platform/process.dart';
class Git extends Command {
@override
Future execute(DataCommand command) async {
var data = DataGit.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var data = DataGit.fromJson(getParam(command));
print(workspace);
var shell = StringBuffer(getCDPath(workspace));
var commands = data.commands;
for (var item in commands) {
shell.write(' && git ${getPathNormal(item)}');
shell.write(' && git ${Command.getPathNormal(item)}');
}
var process = await ProcessExecutor.start(shell);
return complete(await process.process.exitCode, command,
errorMessage: process.stderr.toString());
return await completeProcess(process, command);
}
}
//
class GitPush extends Command {
@override
Future execute(DataCommand command) async {
var data = DataGitPush.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
if(data.branch == null)
{
shell.write(' && git push');
}
else
{
shell.write(' && git push origin ${data.branch!}');
}
var process = await ProcessExecutor.start(shell);
return await completeProcess(process, command, passExitCodes: [1 /*Everything up-to-date*/]);
}
}
// , , pull수행
class GitCheckout extends Git {
@override
Future execute(DataCommand command) async {
var data = DataGitCheckout.fromJson(getParam(command));
var branch = data.branch;
var shell = StringBuffer(getCDPath(workspace));
shell.write(' && git checkout origin/$branch');
shell.write(' && git checkout -b $branch');
var process = await ProcessExecutor.start(shell);
var exitCode = await process.process.exitCode;
var ignores = [128/*Already exists*/];
if(ignores.contains(exitCode))
{
exitCode = 0;
}
if(exitCode == 0)
{
shell = StringBuffer(getCDPath(workspace));
shell.write(' && git checkout $branch');
if(data.executePull == null ? true : data.executePull!)
{
shell.write(' && git pull origin $branch');
}
process = await ProcessExecutor.start(shell);
exitCode = await process.process.exitCode;
}
return await completeProcess(process, command);
}
}
//Git commit에 count
class GitCount extends Command {
@override
Future execute(DataCommand command) async {
var data = DataGitCount.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var data = DataGitCount.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
shell.write(' && git rev-list --all HEAD --all --count');
var process = await ProcessExecutor.start(shell, printStderr: false);
var exitCode = await process.process.exitCode;
var number = int.parse(process.stdoutArr.last);
await setReturn(data.result_value, number);
await setProperty(data.setValue, number);
return complete(exitCode, command, errorMessage: process.stderr.toString());
return await completeProcess(process, command);
}
}
//git의
class GitRev extends Command {
@override
Future execute(DataCommand command) async {
var data = DataGitRev.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var data = DataGitRev.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
var target = data.branch ?? 'HEAD';
target = replaceTag(target);
shell.write(' && git fetch origin');
shell.write(' && git rev-parse $target');
var process = await ProcessExecutor.start(shell, printStderr: false);
var exitCode = await process.process.exitCode;
var hash = process.stdoutArr.last;
await setReturn(data.result_value, hash);
await setProperty(data.setValue, hash);
return complete(exitCode, command, errorMessage: process.stderr.toString());
return await completeProcess(process, command);
}
}

View file

@ -0,0 +1,131 @@
// ignore_for_file: avoid_init_to_null
import 'dart:convert';
import 'dart:io';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
import 'package:dart_framework/platform/process.dart';
class GitHub extends Command {
@override
Future execute(DataCommand command) async {
var data = DataGitHub.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
var commands = data.commands;
for (var item in commands) {
shell.write(' && gh ${Command.getPathNormal(item)}');
}
var process = await ProcessExecutor.start(shell);
return await completeProcess(process, command);
}
}
class GitHubPullRequestCreate extends Command {
@override
Future execute(DataCommand command) async {
var data = DataGitHubPullRequestCreate.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
shell.write(' && gh pr create --title "${data.title}" --body "${data.body}" -B ${data.branch}');
var process = await ProcessExecutor.start(shell);
var passExitCodes = [0, 1 /*already exists*/];
var exitCode = await process.process.exitCode;
if(passExitCodes.contains(exitCode))
{
var resultMessage = '';
if(exitCode == 1)
{
resultMessage = process.stderr.toString().replaceAll('\n', '');
var startIndex = resultMessage.indexOf(':') + 1;
resultMessage = resultMessage.substring(startIndex);
}
else
{
resultMessage = process.stdout.toString().replaceAll('\n', '');
}
String? url = null;
String? number = null;
if(!resultMessage.contains('GraphQL: No commits'))
{
var num = resultMessage.substring(resultMessage.lastIndexOf('/') + 1);
url = resultMessage;
number = num.toString();
}
await setProperty(data.setURL, url);
await setProperty(data.setNumber, number);
}
return await completeProcess(process, command, passExitCodes: passExitCodes);
}
}
class GitHubPullRequestList extends Command {
@override
Future execute(DataCommand command) async {
var data = DataGitHubPullRequestList.fromJson(getParam(command));
if(data.keys.isEmpty) throw Exception('keys not exist');
var keysString = data.keys.join(',');
var shell = StringBuffer(getCDPath(workspace));
shell.write(' && gh pr list --json $keysString');
var decorder = Platform.isWindows ? SystemEncoding().decoder : utf8.decoder;
var process = await ProcessExecutor.start(shell, decoder: decorder);
var exitCode = await process.process.exitCode;
if(exitCode == 0)
{
Map<String, dynamic>? target = null;
var jsonRaw = process.stdout.toString();
jsonRaw = jsonRaw.substring(jsonRaw.indexOf('['));
List<dynamic> list = jsonDecode(jsonRaw) as List<dynamic>;
for(Map<String, dynamic> item in list)
{
if(item.containsKey(data.targetKey))
{
if(item[data.targetKey] == data.targetValue)
{
target = item;
break;
}
}
}
if(target == null)
{
await setProperty(data.setValue, null);
}
else
{
await setProperty(data.setValue, jsonEncode(target));
}
}
else
{
await setProperty(data.setValue, null);
}
return await completeProcess(process, command);
}
}
class GitHubPullRequestClose extends Command {
@override
Future execute(DataCommand command) async {
var data = DataGitHubPullRequestClose.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
shell.write(' && gh pr close ${data.number}');
var decorder = Platform.isWindows ? SystemEncoding().decoder : utf8.decoder;
var process = await ProcessExecutor.start(shell, decoder: decorder);
return await completeProcess(process, command);
}
}

View file

@ -0,0 +1,24 @@
import 'package:dart_framework/platform/process.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
class Gradle extends Command {
@override
Future execute(DataCommand command) async {
DataGradle data = DataGradle.fromJson(getParam(command));
List<String> args = data.args;
StringBuffer shell = StringBuffer(getCDPath(workspace));
shell.write(' && gradle');
for (String arg in args) {
shell.write(' $arg');
}
var process = await ProcessExecutor.start(shell);
return await completeProcess(process, command);
}
}

View file

@ -0,0 +1,123 @@
// ignore_for_file: prefer_function_declarations_over_variables, avoid_init_to_null
import 'dart:convert';
import 'package:dart_framework/utils/slack/slack_data.dart';
import 'package:dart_framework/utils/system_util.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
import 'package:http/http.dart' as http;
import 'package:oto_cli/oto/data/jira_data.dart';
class Jira extends Command {
String? findContent(DataJiraContent? data) {
if(data != null) {
if(data.text != null) {
return data.text;
} else {
if(data.content != null && data.content!.isNotEmpty) {
return findContent(data.content!.first);
} else {
return null;
}
}
} else {
return null;
}
}
@override
Future execute(DataCommand command) async {
var data = DataJira.fromJson(getParam(command));
var text = '${data.id}:${data.token}';
var base64 = base64Encode(utf8.encode(text));
var header =
{
'Content-Type': 'application/json',
'Authorization': 'Basic $base64'
};
var url = 'https://${data.domain}/rest/api/3/issue/${data.issue}';
print(url);
var response = await http.get(Uri.parse(url), headers: header);
if(response.statusCode < 300 && response.statusCode >= 200)
{
print(response.body);
var issue = DataJiraIssue.fromJson(jsonDecode(response.body));
var targetUser = issue.fields?.assignee?.emailAddress;
if(targetUser != null)
{
var slackID = '';
for(var user in data.users) {
if(targetUser.contains(user.mail!)) {
slackID = user.slackID!;
break;
}
}
if(slackID.isNotEmpty) {
var arr = issue.fields?.description?.content;
var summary = issue.fields?.summary;
if((arr != null && arr.isNotEmpty) || summary != null) {
String? content = "";
if(arr != null && arr.isNotEmpty) {
content = findContent(arr.first);
content ??= summary!;
} else {
content = summary!;
}
var browseUrl = 'https://${data.domain}/browse/${data.issue}';
DataSlack Function(String) getData = (channel) {
var slackData = DataSlack(channel);
slackData.attachments = [];
var attachment = SlackAttachment();
slackData.blocks = [];
var blockSection = SlackBlockSection();
blockSection.text = SlackBlockText();
blockSection.text!.text = ':jira: 새 Jira 업무가 할당되었습니다.';
slackData.blocks!.add(blockSection);
attachment.blocks = [];
blockSection = SlackBlockSection();
blockSection.text = SlackBlockText();
blockSection.text!.type = SlackTextType.mrkdwn;
blockSection.text!.text = '*<$browseUrl|${data.issue}> ${issue.fields?.summary}*';
attachment.blocks!.add(blockSection);
blockSection = SlackBlockSection();
blockSection.text = SlackBlockText();
blockSection.text!.text = content;
blockSection.accessory = SlackAccessory();
blockSection.accessory!.type = SlackActionType.button;
blockSection.accessory!.url = browseUrl;
blockSection.accessory!.text = SlackBlockText();
blockSection.accessory!.text!.type = SlackTextType.plain_text;
blockSection.accessory!.text!.text = 'Open';
attachment.blocks!.add(blockSection);
slackData.attachments!.add(attachment);
return slackData;
};
await setProperty(data.setSlackData, getData(slackID));
if(data.subChannel != null) {
await setProperty(data.setSlackChannel, getData(data.subChannel!));
}
}
} else {
print('User not found');
}
}
}
else
{
throw Exception('Request Jira API Faile: $url');
}
return simpleFuture;
}
}

View file

@ -0,0 +1,57 @@
import 'dart:async';
import 'dart:io';
import 'package:dart_framework/platform/process.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
class ProcessPortUse extends Command {
@override
Future execute(DataCommand command) async {
var data = DataProcessPortUse.fromJson(getParam(command));
try {
var process = await findUsePortPid(int.parse(data.port));
var pid = process?.pid.toString();
setProperty(data.setPid, pid);
} on Exception catch (e) {
rethrow;
}
return complete(0, command);
}
}
class ProcessRun extends Command {
@override
Future execute(DataCommand command) async {
var data = DataProcessRun.fromJson(getParam(command));
var exe = data.executable;
print('Process Start: $exe');
var shell = StringBuffer(getCDPath(data.workspace!));
var dontKillme =
Platform.isWindows ? 'SET BUILD_ID=dontKillMe' : 'BUILD_ID=dontKillMe';
var param = data.param == null ? '' : ' ${data.param}';
shell.writeln(' && $dontKillme && $exe$param');
var file =
File('${Directory.systemTemp.path}/${ProcessExecutor.tempFileName}');
await file.writeAsString(shell.toString());
await Process.start(file.path, [],
runInShell: true,
workingDirectory: data.workspace,
mode: ProcessStartMode.detached);
return complete(0, command);
}
}
class ProcessKill extends Command {
@override
Future execute(DataCommand command) async {
var data = DataProcessKill.fromJson(getParam(command));
if (Process.killPid(int.parse(data.pid))) {
print('Process killed');
} else {
print('Process not exist');
}
return complete(0, command);
}
}

View file

@ -0,0 +1,20 @@
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
import 'package:dart_framework/platform/process.dart';
class Protobuf extends Command {
@override
Future execute(DataCommand command) async {
var data = DataProtobuf.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
var commands = data.commands;
for (var item in commands) {
shell.write(' && protoc ${Command.getPathNormal(item)}');
}
var process = await ProcessExecutor.start(shell);
return await completeProcess(process, command);
}
}

View file

@ -7,21 +7,32 @@ import 'package:oto_cli/oto/data/command_data.dart';
class Shell extends Command {
@override
Future execute(DataCommand command) async {
var data = DataShell.fromJson(command.param);
print(command.param);
//Start here
var workspace = getWorkspace(data.workspace);
var path = getPathNormal(data.path);
var data = DataShell.fromJson(getParam(command));
var shell = StringBuffer(getCDPath(workspace));
var commands = data.commands;
for (var item in commands) {
shell.write(' && $item');
}
var process = await ProcessExecutor.start(shell);
return await completeProcess(process, command);
}
}
class ShellFile extends Command {
@override
Future execute(DataCommand command) async {
var data = DataShellFile.fromJson(getParam(command));
var path = Command.getPathNormal(data.path);
var shell = StringBuffer();
if (Platform.isWindows) {
shell.writeln('call $path');
} else {
shell.writeln('source $path');
}
var processData = await ProcessExecutor.start(shell, workspace: workspace);
var process = await ProcessExecutor.start(shell, workspace: workspace);
return complete(await processData.process.exitCode, command,
errorMessage: processData.stderr.toString());
return await completeProcess(process, command);
}
bool isSuccess(int exitCode) {

View file

@ -12,7 +12,7 @@ import 'package:dart_framework/utils/path.dart';
class Uploader extends Command {
@override
Future execute(DataCommand command) async {
var data = DataUploader.fromJson(command.param);
var data = DataUploader.fromJson(getParam(command));
//Check asterisk
var uploadMap = <String, String>{};
@ -30,7 +30,7 @@ class Uploader extends Command {
var entries = map.entries;
for (var entry in entries) {
var local =
path.join(Application.instance.jenkinsData!.workspace, entry.key);
path.join(Application.instance.commonData!.workspace, entry.key);
var remote = entry.value;
print('[Upload]: $local ====> $remote');

View file

@ -8,9 +8,36 @@ import 'package:oto_cli/oto/data/command_data.dart';
class JsonReader extends Command {
@override
Future execute(DataCommand command) async {
var data = DataJsonReader.fromJson(command.param);
var workspace = getWorkspace(data.workspace);
var path = getAbs(data.path);
var data = DataJsonReader.fromJson(getParam(command));
try {
Map<String, dynamic> temp = data.json is String ? jsonDecode(data.json) : data.json as Map<String, dynamic>;
for (var item in data.pair) {
var keys = item.from.split('.');
for (var i = 0; i < keys.length; ++i) {
var key = keys[i];
if (temp.containsKey(key)) {
if (i == keys.length - 1) {
await setProperty(item.setValue, temp[keys[i]].toString());
break;
} else {
temp = temp[keys[i]];
}
} else {
throw Exception('Not exist key: "$key" in $item');
}
}
}
} on Exception catch (e) {
throw Exception('Json parsing error: $e');
}
}
}
class JsonReaderFile extends Command {
@override
Future execute(DataCommand command) async {
var data = DataJsonReaderFile.fromJson(getParam(command));
var path = Command.getAbs(data.path);
var file = File(path);
if (file.existsSync()) {
var content = await file.readAsString();
@ -23,7 +50,7 @@ class JsonReader extends Command {
var key = keys[i];
if (temp.containsKey(key)) {
if (i == keys.length - 1) {
await setReturn(item.to, temp[keys[i]].toString());
await setProperty(item.setValue, temp[keys[i]].toString());
break;
} else {
temp = temp[keys[i]];
@ -37,7 +64,7 @@ class JsonReader extends Command {
throw Exception('Json parsing error: $e');
}
} else {
await CLI.println('Json "$path" file not exit. Resturn value to be null.',
await CLI.println('Json "$path" file not exit. Return value to be null.',
color: Color.red);
}
}

View file

@ -0,0 +1,17 @@
import 'package:oto_cli/cli/cli.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
class PrintCommand extends Command {
Function? get error => null;
@override
Future execute(DataCommand command) async {
var data = DataPrint.fromJson(getParam(command));
// await CLI.println(data.message, color: Color.red);
print(data.message);
return complete(0, command);
}
}

View file

@ -11,9 +11,9 @@ class PublishiOS extends Command {
@override
Future execute(DataCommand command) async {
var data = DataPublishiOS.fromJson(command.param);
var menifestURL = replaceTag(data.menifestURL);
var destinationPath = replaceTag(data.destinationPath);
var data = DataPublishiOS.fromJson(getParam(command));
var menifestURL = data.menifestURL;
var destinationPath = data.destinationPath;
var templatePath = path.normalize(
'${path.dirname(Platform.script.toFilePath())}/../assets/template');
@ -32,12 +32,12 @@ class PublishiOS extends Command {
var menifestContent =
await File('$templatePath/manifest.plist').readAsString();
menifestContent = menifestContent
.replaceFirst('IPA_URL', replaceTag(data.ipaURL))
.replaceFirst('BUNDLE_ID', replaceTag(data.bundleID))
.replaceFirst('VERSION', replaceTag(data.version))
.replaceFirst('APP_NAME', replaceTag(data.appName))
.replaceFirst('DISPLAY_IMAGE_URL', replaceTag(data.displayImageURL))
.replaceFirst('FULL_SIZE_IMAGE_URL', replaceTag(data.fullSizeImageURL));
.replaceFirst('IPA_URL', data.ipaURL)
.replaceFirst('BUNDLE_ID', data.bundleID)
.replaceFirst('VERSION', data.version)
.replaceFirst('APP_NAME', data.appName)
.replaceFirst('DISPLAY_IMAGE_URL', data.displayImageURL)
.replaceFirst('FULL_SIZE_IMAGE_URL', data.fullSizeImageURL);
var menifestFile = File('$destinationPath/manifest.plist');
await menifestFile.writeAsString(menifestContent);

View file

@ -0,0 +1,113 @@
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
class SetValueCommand extends Command {
Function? get error => null;
@override
Future execute(DataCommand command) async {
var data = DataSetValue.fromJson(getParam(command));
if(data.values_bool != null)
{
for(var pair in data.values_bool!.entries)
{
bool value = false;
if(pair.value is bool)
{
value = pair.value;
}
else if(pair.value is String)
{
var resultTag = replaceSingleTag(pair.value);
if(resultTag is String)
{
var toLow = resultTag.toLowerCase();
if(toLow == 'true' || toLow == 'false')
{
value = toLow == 'true';
}
}
else if(resultTag is bool)
{
value = resultTag;
}
}
await setProperty(getTag(pair.key), value);
}
}
if(data.values_float != null)
{
for(var pair in data.values_float!.entries)
{
double value = 0;
if(pair.value is double)
{
value = pair.value;
}
else if(pair.value is String)
{
var resultTag = replaceSingleTag(pair.value);
if(resultTag is String)
{
value = double.parse(resultTag);
}
else if(resultTag is double)
{
value = resultTag;
}
else if(resultTag is int)
{
value = resultTag + 0.0;
}
}
await setProperty(getTag(pair.key), value);
}
}
if(data.values_int != null)
{
for(var pair in data.values_int!.entries)
{
var value = 0;
if(pair.value is int)
{
value = pair.value;
}
else if(pair.value is String)
{
var resultTag = replaceSingleTag(pair.value);
if(resultTag is String)
{
value = int.parse(resultTag);
}
else if(resultTag is int)
{
value = resultTag;
}
else if(resultTag is double)
{
value = resultTag.round();
}
}
await setProperty(getTag(pair.key), value);
}
}
if(data.values_string != null)
{
for(var pair in data.values_string!.entries)
{
await setProperty(getTag(pair.key), pair.value);
}
}
return complete(0, command);
}
String getTag(String key)
{
return '<@property.$key>';
}
}

View file

@ -1,6 +1,7 @@
// ignore_for_file: avoid_init_to_null
import 'dart:async';
import 'dart:convert';
import 'package:dart_framework/utils/slack/slack_data.dart';
import 'package:dart_framework/utils/system_util.dart';
@ -12,21 +13,24 @@ import 'package:dart_framework/utils/slack/slack_sender.dart';
class Slack extends Command {
@override
Future execute(DataCommand command) async {
var data = DataSlackSender.fromJson(command.param);
var data = DataSlackSender.fromJson(getParam(command));
var sender = SlackSender(data.token);
DataSlack? message = null;
if (data.property != null) {
var value = replaceSingleTag(data.property!);
var value = data.property as DataSlack?;
if (value != null) {
message = value as DataSlack;
await sender.sendData(value);
}
else
{
throw Exception('The property is null.');
}
} else {
message = data.message;
}
if (message != null) {
await sender.send(message);
} else {
else if(data.message != null)
{
await sender.send(jsonEncode(data.message));
}
else
{
throw Exception('property or message field should not be null');
}
@ -37,15 +41,9 @@ class Slack extends Command {
class SlackBuild extends Command {
@override
Future execute(DataCommand command) async {
var data = DataSlackBuild.fromJson(command.param);
var data = DataSlackBuild.fromJson(getParam(command));
var token = replaceTag(data.token);
var version = replaceTag(data.version);
var download = replaceTag(data.downloadURL);
var color = Color.hex(data.color);
var sender = SlackSender(token);
await sender.sendBuild(data.appName, data.type, color, version, download);
await SlackSender(data.token).sendBuild(data.appName, data.type, Color.hex(data.color), data.version, data.downloadURL);
return complete(0, command);
}

View file

@ -0,0 +1,46 @@
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
class StringSub extends Command {
@override
Future execute(DataCommand command) async {
var data = DataStringSub.fromJson(getParam(command));
var text = data.text;
var exitCode = 0;
try
{
int startIndex = data.startIndex == null ? 0 : data.startIndex!;
int lastIndex = data.lastIndex == null ? text.length - startIndex : data.lastIndex!;
text = text.substring(startIndex, lastIndex);
await setProperty(data.setValue, text);
}
on Exception catch(e)
{
rethrow;
}
return await complete(exitCode, command);
}
}
class StringReplace extends Command {
@override
Future execute(DataCommand command) async {
var data = DataStringReplace.fromJson(getParam(command));
var text = data.text;
var exitCode = 0;
try
{
text = text.replaceAll(data.from, data.to);
await setProperty(data.setValue, text);
}
on Exception catch(e)
{
rethrow;
}
return await complete(exitCode, command);
}
}

View file

@ -11,9 +11,9 @@ import 'package:oto_cli/oto/data/command_data.dart';
class Zip extends Command {
@override
Future execute(DataCommand command) async {
var data = DataZip.fromJson(command.param);
var data = DataZip.fromJson(getParam(command));
try {
var zipFilePath = Path.getNormal(replaceTag(data.zipFile));
var zipFilePath = Path.getNormal(data.zipFile);
print('Start Compress...');
var parent = Directory(Path.getParent(zipFilePath)!);
if (!parent.existsSync()) parent.createSync(recursive: true);
@ -25,7 +25,7 @@ class Zip extends Command {
encoder.create(zipFilePath);
var list = data.zipList;
for (var path in list) {
path = Path.getNormal(replaceTag(path));
path = Path.getNormal(path);
var name = Path.getName(path);
if (name == '*') {
parent = Directory(Path.getParent(path)!);

View file

@ -0,0 +1,84 @@
import 'dart:async';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:http_parser/src/media_type.dart';
class WebBase extends Command {
Future<int> request(DataWebBase data, http.BaseRequest request) async
{
var c = Completer<int>();
if(data.headers != null)
{
for(var head in data.headers!.entries)
{
request.headers[head.key] = head.value;
}
}
var response = await request.send();
var exitCode = 0;
data.successCodes ??= [];
if ((response.statusCode < 300 && response.statusCode >= 200) ||
data.successCodes!.contains(response.statusCode)) {
exitCode = 0;
} else {
exitCode = response.statusCode;
}
c.complete(exitCode);
return c.future;
}
}
class WebRequest extends WebBase {
@override
Future execute(DataCommand command) async {
var data = DataWebBase.fromJson(getParam(command));
print('Request URL: ${data.url}');
data.method ??= 'GET';
var request = http.Request(data.method!, Uri.parse(data.url));
if(data.fields != null)
{
for(var field in data.fields!.entries)
{
request.bodyFields[field.key] = field.value;
}
}
return await complete(await super.request(data, request), command);
}
}
class WebFile extends WebBase {
@override
Future execute(DataCommand command) async {
var data = DataWebFile.fromJson(getParam(command));
print('Upload URL: ${data.url}');
var form = http.MultipartRequest('POST', Uri.parse(data.url));
if(data.fields != null)
{
for(var field in data.fields!.entries)
{
form.fields[field.key] = field.value;
}
}
if(data.filePart != null && data.fileMimeType != null && data.files != null)
{
for(var filePath in data.files!)
{
var file = File(filePath);
if(file.existsSync())
{
form.files.add(await http.MultipartFile.fromPath(data.filePart!, file.path,
contentType: MediaType(HttpHeaders.contentTypeHeader, data.fileMimeType!)));
}
else
{
throw Exception('File not found: $filePath');
}
}
}
return await complete(await super.request(data, form), command);
}
}

View file

@ -8,7 +8,7 @@ import 'package:oto_cli/oto/data/jenkins_data.dart';
import 'package:oto_cli/oto/core/defined_data.dart';
abstract class DataComposer {
DataJenkins? jenkinsData;
DataCommon? commonData;
String buildYaml = '';
Future compose(String? yaml, Future Function(String, Color?) printer) async {
@ -19,7 +19,7 @@ abstract class DataComposer {
class DataComposerTest extends DataComposer {
@override
Future compose(String? yaml, Future Function(String, Color?) printer) async {
jenkinsData = DataJenkins.fromJson(TestData.jenkinsMap!);
commonData = DataCommon.fromJson(TestData.jenkinsMap!);
buildYaml = TestData.buildYaml;
return simpleFuture;
}
@ -28,7 +28,7 @@ class DataComposerTest extends DataComposer {
class DataComposerFile extends DataComposer {
@override
Future compose(String? yaml, Future Function(String, Color?) printer) async {
jenkinsData = DataJenkins.fromJson(FileData.jenkinsMap!);
commonData = DataCommon.fromJson(FileData.jenkinsMap!);
buildYaml = yaml ?? '---';
return simpleFuture;
}
@ -44,7 +44,8 @@ class DataComposerJenkins extends DataComposer {
print('Start build...');
String jsonStr = '';
if (Platform.isMacOS || Platform.isLinux) {
await Process.run('zsh', [
var shellExe = Platform.isMacOS ? 'zsh' : 'bash';
await Process.run(shellExe, [
'${Directory.current.path}/assets/script/shell/jenkins_env_params.sh'
]).then((ProcessResult result) => jsonStr = result.stdout);
jenkinsMap = getMapFromJson(jsonStr)!;
@ -66,7 +67,7 @@ class DataComposerJenkins extends DataComposer {
await printer('Jenkins Variables', Color.green);
print(jsonStr);
}
jenkinsData = DataJenkins.fromJson(jenkinsMap!);
commonData = DataCommon.fromJson(jenkinsMap!);
buildYaml = await getBuildData();
return simpleFuture;
@ -74,13 +75,14 @@ class DataComposerJenkins extends DataComposer {
Future<String> getBuildData() async {
var c = Completer<String>();
var file = File('${jenkinsData!.workspace}/build_data.conf');
var file = File('${commonData!.workspace}/build_data.conf');
var content = '';
if (Platform.isWindows) {
content = file
.readAsStringSync(encoding: utf8)
.replaceAll('BuildData=', '')
.replaceAll('\\', '/');
var index = content.indexOf('=');
content = content.substring(index + 1);
var regEx = RegExp(r'(%)([a-zA-Z0-9]+)(%)');
var list = regEx.allMatches(content);
var params = <String>[];
@ -91,7 +93,7 @@ class DataComposerJenkins extends DataComposer {
}
}
var temp = File('${jenkinsData!.workspace}/param_temp.bat');
var temp = File('${commonData!.workspace}/param_temp.bat');
var bat = '';
for (var param in params) {
bat += '@echo %$param%\n';

View file

@ -3,7 +3,8 @@
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:dart_framework/utils/slack/slack_data.dart';
import 'package:oto_cli/oto/commands/build/build_flutter.dart';
import 'package:oto_cli/oto/commands/build/build_msbuild.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/pipeline_data.dart';
part 'command_data.g.dart';
@ -11,7 +12,7 @@ part 'command_data.g.dart';
/// ***************************** Base Data ****************************///
@JsonSerializable()
class DataBuild {
late Map<String, dynamic> property;
late Map<String, dynamic>? property;
late DataPipeline? pipeline;
late List<DataCommand> commands;
@ -44,6 +45,13 @@ class DataParam {
DataParam();
late String? workspace;
late List<int>? passExitCodes;
late String? setResult;
late String? setExitCode;
factory DataParam.fromJson(Map<String, dynamic> json) =>
_$DataParamFromJson(json);
Map<String, dynamic> toJson() => _$DataParamToJson(this);
}
/// ***************************** Command List ****************************///
@ -59,6 +67,37 @@ class DataSimpleCommand extends DataParam {
Map<String, dynamic> toJson() => _$DataSimpleCommandToJson(this);
}
//Print
@JsonSerializable()
class DataPrint extends DataParam {
DataPrint();
late String message;
factory DataPrint.fromJson(Map<String, dynamic> json) =>
_$DataPrintFromJson(json);
Map<String, dynamic> toJson() => _$DataPrintToJson(this);
}
//SetValue
@JsonSerializable()
class DataSetValue extends DataParam {
DataSetValue();
@JsonKey(name: 'values-int')
late Map<String, dynamic>? values_int;
@JsonKey(name: 'values-float')
late Map<String, dynamic>? values_float;
@JsonKey(name: 'values-string')
late Map<String, dynamic>? values_string;
@JsonKey(name: 'values-bool')
late Map<String, dynamic>? values_bool;
factory DataSetValue.fromJson(Map<String, dynamic> json) =>
_$DataSetValueFromJson(json);
Map<String, dynamic> toJson() => _$DataSetValueToJson(this);
}
//AppDataCreator
@JsonSerializable()
class DataAppDataCreator extends DataParam {
@ -66,10 +105,10 @@ class DataAppDataCreator extends DataParam {
late SCMType scm;
late String relativeAssetPath;
@JsonKey(name: 'return-version')
late String return_version;
@JsonKey(name: 'return-hash')
late String return_hash;
late String setVersion;
late String setHash;
late String? setCount;
late String? setDate;
late String name;
factory DataAppDataCreator.fromJson(Map<String, dynamic> json) =>
@ -77,6 +116,20 @@ class DataAppDataCreator extends DataParam {
Map<String, dynamic> toJson() => _$DataAppDataCreatorToJson(this);
}
//BuildDart
@JsonSerializable()
class DataBuildMSBuild extends DataParam {
DataBuildMSBuild();
late String projectFile;
late MSBuildType type;
late MSBuildConfig config;
factory DataBuildMSBuild.fromJson(Map<String, dynamic> json) =>
_$DataBuildMSBuildFromJson(json);
Map<String, dynamic> toJson() => _$DataBuildMSBuildToJson(this);
}
//BuildDart
@JsonSerializable()
class DataBuildDart extends DataParam {
@ -134,16 +187,81 @@ class DataBuildDotNet extends DataParam {
class DataBuildiOS extends DataParam {
DataBuildiOS();
late String macPassword;
late String scheme;
late String? destination;
late String xcworkspaceFilePath;
late BuildPlatform? os;
late String? xcodeProjectFilePath;
late String? xcworkspaceFilePath;
late String? derivedDataPath;
late bool? cleanPod;
late String? configuration;
late Map<String, String>? settings;
factory DataBuildiOS.fromJson(Map<String, dynamic> json) =>
_$DataBuildiOSFromJson(json);
Map<String, dynamic> toJson() => _$DataBuildiOSToJson(this);
}
//CodeSign
@JsonSerializable()
class DataCodeSign extends DataParam {
DataCodeSign();
late String appPath;
late String certificationName;
late String? entitlementPath;
factory DataCodeSign.fromJson(Map<String, dynamic> json) =>
_$DataCodeSignFromJson(json);
Map<String, dynamic> toJson() => _$DataCodeSignToJson(this);
}
//CodeSignVerify
@JsonSerializable()
class DataCodeSignVerify extends DataParam {
DataCodeSignVerify();
late String appPath;
factory DataCodeSignVerify.fromJson(Map<String, dynamic> json) =>
_$DataCodeSignVerifyFromJson(json);
Map<String, dynamic> toJson() => _$DataCodeSignVerifyToJson(this);
}
//ProductBuild
@JsonSerializable()
class DataProductBuild extends DataParam {
DataProductBuild();
late String appPath;
late String identifier;
late String? scripts;
late String installCertificationName;
late String unsignedResultPath;
late String signedResultPath;
factory DataProductBuild.fromJson(Map<String, dynamic> json) =>
_$DataProductBuildFromJson(json);
Map<String, dynamic> toJson() => _$DataProductBuildToJson(this);
}
//Notarize
@JsonSerializable()
class DataNotarize extends DataParam {
DataNotarize();
late String macPassword;
late String bundleName;
late String teamId;
late String appleAccount;
late String applePassword;
late String resultPath;
factory DataNotarize.fromJson(Map<String, dynamic> json) =>
_$DataNotarizeFromJson(json);
Map<String, dynamic> toJson() => _$DataNotarizeToJson(this);
}
//ArchiveiOS
@JsonSerializable()
class DataArchiveiOS extends DataParam {
@ -152,6 +270,7 @@ class DataArchiveiOS extends DataParam {
late String xcworkspaceFilePath;
late String scheme;
late String archivePath;
late String? destination;
factory DataArchiveiOS.fromJson(Map<String, dynamic> json) =>
_$DataArchiveiOSFromJson(json);
@ -191,19 +310,6 @@ class DataPublishiOS extends DataParam {
Map<String, dynamic> toJson() => _$DataPublishiOSToJson(this);
}
//ExecuteApp
@JsonSerializable()
class DataExecuteApp extends DataParam {
DataExecuteApp();
late String executable;
late String desktopServicePath;
factory DataExecuteApp.fromJson(Map<String, dynamic> json) =>
_$DataExecuteAppFromJson(json);
Map<String, dynamic> toJson() => _$DataExecuteAppToJson(this);
}
//Uploader
@JsonSerializable()
class DataUploader extends DataParam {
@ -232,6 +338,7 @@ class DataCopy extends DataFile {
DataCopy();
late bool? isMove;
late bool? isOverwrite = true;
late Map<String, String> copyMap;
factory DataCopy.fromJson(Map<String, dynamic> json) =>
@ -263,14 +370,65 @@ class DataRename extends DataFile {
Map<String, dynamic> toJson() => _$DataRenameToJson(this);
}
//File Diff Check
@JsonSerializable()
class DataFileDiffCheck extends DataParam {
DataFileDiffCheck();
late List<String> paths;
late String setDiff;
factory DataFileDiffCheck.fromJson(Map<String, dynamic> json) =>
_$DataFileDiffCheckFromJson(json);
Map<String, dynamic> toJson() => _$DataFileDiffCheckToJson(this);
}
//File Read
@JsonSerializable()
class DataFileRead extends DataParam {
DataFileRead();
late String path;
late String setContent;
factory DataFileRead.fromJson(Map<String, dynamic> json) =>
_$DataFileReadFromJson(json);
Map<String, dynamic> toJson() => _$DataFileReadToJson(this);
}
//File Write
@JsonSerializable()
class DataFileWrite extends DataParam {
DataFileWrite();
late String path;
late String content;
factory DataFileWrite.fromJson(Map<String, dynamic> json) =>
_$DataFileWriteFromJson(json);
Map<String, dynamic> toJson() => _$DataFileWriteToJson(this);
}
//Directory Create
@JsonSerializable()
class DataDirectoryCreate extends DataParam {
DataDirectoryCreate();
late String path;
factory DataDirectoryCreate.fromJson(Map<String, dynamic> json) =>
_$DataDirectoryCreateFromJson(json);
Map<String, dynamic> toJson() => _$DataDirectoryCreateToJson(this);
}
//Slack
@JsonSerializable()
class DataSlackSender extends DataParam {
DataSlackSender();
late String token;
late String? property;
late DataSlack? message;
late dynamic property;
late Map<String, dynamic>? message;
factory DataSlackSender.fromJson(Map<String, dynamic> json) =>
_$DataSlackSenderFromJson(json);
@ -303,13 +461,10 @@ class DataJira extends DataParam {
late String token;
late String domain;
late String issue;
@JsonKey(name: 'sub-channel')
late String? sub_channel;
late String? subChannel;
late List<DataJiraUser> users;
@JsonKey(name: 'return-slack-data')
late String return_slack_data;
@JsonKey(name: 'return-slack-channel')
late String return_slack_channel;
late String setSlackData;
late String setSlackChannel;
factory DataJira.fromJson(Map<String, dynamic> json) =>
_$DataJiraFromJson(json);
@ -347,13 +502,24 @@ class DataZip extends DataParam {
class DataShell extends DataParam {
DataShell();
late String path;
late List<String> commands;
factory DataShell.fromJson(Map<String, dynamic> json) =>
_$DataShellFromJson(json);
Map<String, dynamic> toJson() => _$DataShellToJson(this);
}
@JsonSerializable()
class DataShellFile extends DataParam {
DataShellFile();
late String path;
factory DataShellFile.fromJson(Map<String, dynamic> json) =>
_$DataShellFileFromJson(json);
Map<String, dynamic> toJson() => _$DataShellFileToJson(this);
}
//Git
@JsonSerializable()
class DataGit extends DataParam {
@ -366,13 +532,37 @@ class DataGit extends DataParam {
Map<String, dynamic> toJson() => _$DataGitToJson(this);
}
//GitPush
@JsonSerializable()
class DataGitPush extends DataParam {
DataGitPush();
late String? branch;
factory DataGitPush.fromJson(Map<String, dynamic> json) =>
_$DataGitPushFromJson(json);
Map<String, dynamic> toJson() => _$DataGitPushToJson(this);
}
//GitCheckout
@JsonSerializable()
class DataGitCheckout extends DataParam {
DataGitCheckout();
late String branch;
late bool? executePull;
factory DataGitCheckout.fromJson(Map<String, dynamic> json) =>
_$DataGitCheckoutFromJson(json);
Map<String, dynamic> toJson() => _$DataGitCheckoutToJson(this);
}
//GitCount
@JsonSerializable()
class DataGitCount extends DataParam {
DataGitCount();
@JsonKey(name: 'result-value')
late String result_value;
late String setValue;
factory DataGitCount.fromJson(Map<String, dynamic> json) =>
_$DataGitCountFromJson(json);
@ -387,20 +577,90 @@ class DataGitRev extends DataParam {
//null will be show local HEAD. Get last revision must be set branch
late String? branch;
@JsonKey(name: 'result-value')
late String result_value;
late String setValue;
factory DataGitRev.fromJson(Map<String, dynamic> json) =>
_$DataGitRevFromJson(json);
Map<String, dynamic> toJson() => _$DataGitRevToJson(this);
}
//GitRev
//GitHub
@JsonSerializable()
class DataGitHub extends DataParam {
DataGitHub();
late List<String> commands;
factory DataGitHub.fromJson(Map<String, dynamic> json) =>
_$DataGitHubFromJson(json);
Map<String, dynamic> toJson() => _$DataGitHubToJson(this);
}
//GitHub Pull Request Create
//https://cli.github.com/manual/gh_codespace_create
@JsonSerializable()
class DataGitHubPullRequestCreate extends DataParam {
DataGitHubPullRequestCreate();
late String title;
late String body;
late String branch;
late String setURL;
late String setNumber;
factory DataGitHubPullRequestCreate.fromJson(Map<String, dynamic> json) =>
_$DataGitHubPullRequestCreateFromJson(json);
Map<String, dynamic> toJson() => _$DataGitHubPullRequestCreateToJson(this);
}
//GitHub Pull Request List
//https://cli.github.com/manual/gh_pr_list
@JsonSerializable()
class DataGitHubPullRequestList extends DataParam {
DataGitHubPullRequestList();
late List<String> keys;
late String targetKey;
late String targetValue;
late String setValue;
factory DataGitHubPullRequestList.fromJson(Map<String, dynamic> json) =>
_$DataGitHubPullRequestListFromJson(json);
Map<String, dynamic> toJson() => _$DataGitHubPullRequestListToJson(this);
}
//GitHub Pull Request Close
//https://cli.github.com/manual/gh_pr_close
@JsonSerializable()
class DataGitHubPullRequestClose extends DataParam {
DataGitHubPullRequestClose();
late String number;
factory DataGitHubPullRequestClose.fromJson(Map<String, dynamic> json) =>
_$DataGitHubPullRequestCloseFromJson(json);
Map<String, dynamic> toJson() => _$DataGitHubPullRequestCloseToJson(this);
}
//Protobuf
@JsonSerializable()
class DataProtobuf extends DataParam {
DataProtobuf();
late List<String> commands;
factory DataProtobuf.fromJson(Map<String, dynamic> json) =>
_$DataProtobufFromJson(json);
Map<String, dynamic> toJson() => _$DataProtobufToJson(this);
}
//JsonReader
@JsonSerializable()
class DataJsonReader extends DataParam {
DataJsonReader();
late String path;
late dynamic json;
late List<DataPair> pair;
factory DataJsonReader.fromJson(Map<String, dynamic> json) =>
@ -408,10 +668,23 @@ class DataJsonReader extends DataParam {
Map<String, dynamic> toJson() => _$DataJsonReaderToJson(this);
}
//JsonReaderFile
@JsonSerializable()
class DataJsonReaderFile extends DataParam {
DataJsonReaderFile();
late String path;
late List<DataPair> pair;
factory DataJsonReaderFile.fromJson(Map<String, dynamic> json) =>
_$DataJsonReaderFileFromJson(json);
Map<String, dynamic> toJson() => _$DataJsonReaderFileToJson(this);
}
@JsonSerializable()
class DataPair {
late String from;
late String to;
late String setValue;
DataPair();
@ -419,3 +692,140 @@ class DataPair {
_$DataPairFromJson(json);
Map<String, dynamic> toJson() => _$DataPairToJson(this);
}
//AwsCli
@JsonSerializable()
class DataAwsCli extends DataParam {
DataAwsCli();
@JsonKey(name: "sub-command")
late String subCommand;
late List<String> args;
factory DataAwsCli.fromJson(Map<String, dynamic> json) =>
_$DataAwsCliFromJson(json);
Map<String, dynamic> toJson() => _$DataAwsCliToJson(this);
}
//Docker
@JsonSerializable()
class DataDocker extends DataParam {
DataDocker();
late String command;
late List<String> args;
factory DataDocker.fromJson(Map<String, dynamic> json) =>
_$DataDockerFromJson(json);
Map<String, dynamic> toJson() => _$DataDockerToJson(this);
}
//Gradle
@JsonSerializable()
class DataGradle extends DataParam {
DataGradle();
late List<String> args;
factory DataGradle.fromJson(Map<String, dynamic> json) =>
_$DataGradleFromJson(json);
Map<String, dynamic> toJson() => _$DataGradleToJson(this);
}
//String Sub
@JsonSerializable()
class DataStringSub extends DataParam {
DataStringSub();
late int? startIndex;
late int? lastIndex;
late String text;
late String setValue;
factory DataStringSub.fromJson(Map<String, dynamic> json) =>
_$DataStringSubFromJson(json);
Map<String, dynamic> toJson() => _$DataStringSubToJson(this);
}
//String Replace
@JsonSerializable()
class DataStringReplace extends DataParam {
DataStringReplace();
late String text;
late String setValue;
late String from;
late String to;
factory DataStringReplace.fromJson(Map<String, dynamic> json) =>
_$DataStringReplaceFromJson(json);
Map<String, dynamic> toJson() => _$DataStringReplaceToJson(this);
}
//Web Base
@JsonSerializable()
class DataWebBase extends DataParam {
DataWebBase();
late String url;
late String? method;
late Map<String, String>? headers = <String, String>{};
late Map<String, String>? fields = <String, String>{};
late List<dynamic>? successCodes;
factory DataWebBase.fromJson(Map<String, dynamic> json) =>
_$DataWebBaseFromJson(json);
Map<String, dynamic> toJson() => _$DataWebBaseToJson(this);
}
//Web File
@JsonSerializable()
class DataWebFile extends DataWebBase {
DataWebFile();
late String? filePart;
late String? fileMimeType;
late List<String>? files = [];
factory DataWebFile.fromJson(Map<String, dynamic> json) =>
_$DataWebFileFromJson(json);
Map<String, dynamic> toJson() => _$DataWebFileToJson(this);
}
//Process Using Port
@JsonSerializable()
class DataProcessPortUse extends DataParam {
DataProcessPortUse();
late String port;
late String setPid;
factory DataProcessPortUse.fromJson(Map<String, dynamic> json) =>
_$DataProcessPortUseFromJson(json);
Map<String, dynamic> toJson() => _$DataProcessPortUseToJson(this);
}
//Process Run
@JsonSerializable()
class DataProcessRun extends DataParam {
DataProcessRun();
late String executable;
late String? param;
factory DataProcessRun.fromJson(Map<String, dynamic> json) =>
_$DataProcessRunFromJson(json);
Map<String, dynamic> toJson() => _$DataProcessRunToJson(this);
}
//Process Kill
@JsonSerializable()
class DataProcessKill extends DataParam {
DataProcessKill();
late String pid;
factory DataProcessKill.fromJson(Map<String, dynamic> json) =>
_$DataProcessKillFromJson(json);
Map<String, dynamic> toJson() => _$DataProcessKillToJson(this);
}

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@ import 'package:json_annotation/json_annotation.dart';
part 'jenkins_data.g.dart';
@JsonSerializable()
class DataJenkins {
class DataCommon {
late String workspace;
late String jenkinsHome;
late String jenkinsUrl;
@ -16,9 +16,9 @@ class DataJenkins {
late String gitBranch;
late String buildTag;
DataJenkins();
DataCommon();
factory DataJenkins.fromJson(Map<String, dynamic> json) =>
_$DataJenkinsFromJson(json);
Map<String, dynamic> toJson() => _$DataJenkinsToJson(this);
factory DataCommon.fromJson(Map<String, dynamic> json) =>
_$DataCommonFromJson(json);
Map<String, dynamic> toJson() => _$DataCommonToJson(this);
}

View file

@ -6,7 +6,7 @@ part of 'jenkins_data.dart';
// JsonSerializableGenerator
// **************************************************************************
DataJenkins _$DataJenkinsFromJson(Map<String, dynamic> json) => DataJenkins()
DataCommon _$DataCommonFromJson(Map<String, dynamic> json) => DataCommon()
..workspace = json['workspace'] as String
..jenkinsHome = json['jenkinsHome'] as String
..jenkinsUrl = json['jenkinsUrl'] as String
@ -20,7 +20,7 @@ DataJenkins _$DataJenkinsFromJson(Map<String, dynamic> json) => DataJenkins()
..gitBranch = json['gitBranch'] as String
..buildTag = json['buildTag'] as String;
Map<String, dynamic> _$DataJenkinsToJson(DataJenkins instance) =>
Map<String, dynamic> _$DataCommonToJson(DataCommon instance) =>
<String, dynamic>{
'workspace': instance.workspace,
'jenkinsHome': instance.jenkinsHome,

View file

@ -76,6 +76,27 @@ class DataCondition implements DataValidator {
Map<String, dynamic> toJson() => _$DataConditionToJson(this);
}
@JsonSerializable()
class DataExeHandle implements DataValidator {
late String id;
@JsonKey(name: 'on-success')
late List<dynamic> on_success;
@JsonKey(name: 'on-fail')
late List<dynamic> on_fail;
DataExeHandle();
@override
PipelineValidateResult validate() {
var result = PipelineValidateResult();
return result;
}
factory DataExeHandle.fromJson(Map<String, dynamic> json) => _$DataExeHandleFromJson(json);
@override
Map<String, dynamic> toJson() => _$DataExeHandleToJson(this);
}
@JsonSerializable()
class DataIf extends DataCondition {
@JsonKey(name: 'on-true')
@ -105,6 +126,40 @@ class DataIf extends DataCondition {
Map<String, dynamic> toJson() => _$DataIfToJson(this);
}
@JsonSerializable()
class DataContain extends DataValidator {
late dynamic list;
late String target;
@JsonKey(name: 'on-true')
late List<dynamic>? on_true;
@JsonKey(name: 'on-false')
late List<dynamic>? on_false;
DataContain();
@override
PipelineValidateResult validate() {
var result = PipelineValidateResult();
if(!(list is List || list is String))
{
result.message = 'list field Must be type of "List" or "String".';
result.enable = false;
return result;
}
if (on_true == null && on_false == null) {
result.message = 'If syntax requires on-true or on-false.';
result.enable = false;
return result;
}
return result;
}
factory DataContain.fromJson(Map<String, dynamic> json) => _$DataContainFromJson(json);
@override
Map<String, dynamic> toJson() => _$DataContainToJson(this);
}
@JsonSerializable()
class DataWhile extends DataCondition {
@JsonKey(name: 'on-do')
@ -133,6 +188,43 @@ class DataWhile extends DataCondition {
Map<String, dynamic> toJson() => _$DataWhileToJson(this);
}
@JsonSerializable()
class DataForeach extends DataValidator {
late String iterator;
late dynamic setKey;
late dynamic setValue;
@JsonKey(name: 'on-do')
late List<dynamic>? on_do;
DataForeach();
@override
PipelineValidateResult validate() {
var result = PipelineValidateResult();
if(setValue == null)
{
result.message = 'Syntax requires a settable element name.';
result.enable = false;
return result;
}
if (on_do == null) {
result.message = 'foreach syntax requires on-do.';
result.enable = false;
return result;
}
return result;
}
factory DataForeach.fromJson(Map<String, dynamic> json) =>
_$DataForeachFromJson(json);
@override
Map<String, dynamic> toJson() => _$DataForeachToJson(this);
}
@JsonSerializable()
class DataSwitch extends DataCondition {
late List<DataSwitchValue> cases = [];

View file

@ -39,6 +39,19 @@ Map<String, dynamic> _$DataConditionToJson(DataCondition instance) =>
'condition-object': instance.condition_object,
};
DataExeHandle _$DataExeHandleFromJson(Map<String, dynamic> json) =>
DataExeHandle()
..id = json['id'] as String
..on_success = json['on-success'] as List<dynamic>
..on_fail = json['on-fail'] as List<dynamic>;
Map<String, dynamic> _$DataExeHandleToJson(DataExeHandle instance) =>
<String, dynamic>{
'id': instance.id,
'on-success': instance.on_success,
'on-fail': instance.on_fail,
};
DataIf _$DataIfFromJson(Map<String, dynamic> json) => DataIf()
..condition = json['condition'] as String?
..type = json['type'] as String?
@ -64,6 +77,20 @@ Map<String, dynamic> _$DataIfToJson(DataIf instance) => <String, dynamic>{
'on-false': instance.on_false,
};
DataContain _$DataContainFromJson(Map<String, dynamic> json) => DataContain()
..list = json['list']
..target = json['target'] as String
..on_true = json['on-true'] as List<dynamic>?
..on_false = json['on-false'] as List<dynamic>?;
Map<String, dynamic> _$DataContainToJson(DataContain instance) =>
<String, dynamic>{
'list': instance.list,
'target': instance.target,
'on-true': instance.on_true,
'on-false': instance.on_false,
};
DataWhile _$DataWhileFromJson(Map<String, dynamic> json) => DataWhile()
..condition = json['condition'] as String?
..type = json['type'] as String?
@ -87,6 +114,20 @@ Map<String, dynamic> _$DataWhileToJson(DataWhile instance) => <String, dynamic>{
'on-do': instance.on_do,
};
DataForeach _$DataForeachFromJson(Map<String, dynamic> json) => DataForeach()
..iterator = json['iterator'] as String
..setKey = json['setKey']
..setValue = json['setValue']
..on_do = json['on-do'] as List<dynamic>?;
Map<String, dynamic> _$DataForeachToJson(DataForeach instance) =>
<String, dynamic>{
'iterator': instance.iterator,
'setKey': instance.setKey,
'setValue': instance.setValue,
'on-do': instance.on_do,
};
DataSwitch _$DataSwitchFromJson(Map<String, dynamic> json) => DataSwitch()
..condition = json['condition'] as String?
..type = json['type'] as String?

View file

@ -1,5 +1,8 @@
import 'package:dart_framework/utils/system_util.dart';
import 'package:oto_cli/oto/pipeline/pipeline_contain.dart';
import 'package:oto_cli/oto/pipeline/pipeline_exe.dart';
import 'package:oto_cli/oto/pipeline/pipeline_exe_handle.dart';
import 'package:oto_cli/oto/pipeline/pipeline_foreach.dart';
import 'package:oto_cli/oto/pipeline/pipeline_if.dart';
import 'package:oto_cli/oto/pipeline/pipeline_switch.dart';
import 'package:oto_cli/oto/pipeline/pipeline_wait_until.dart';
@ -8,12 +11,16 @@ import 'package:oto_cli/oto/pipeline/pipeline_while.dart';
class Pipeline {
static Map<String, PipelineExecutor Function()> exeMap = {
'exe': () => PipelineExe(),
'exe-handle': () => PipelineExeHandle(),
'async': () => PipelineAsync(),
'if': () => PipelineIf(),
'contain': () => PipelineContain(),
'while': () => PipelineWhile(),
'foreach': () => PipelineForeach(),
'wait-until-int': () => PipelineWaitUntil('int'),
'wait-until-double': () => PipelineWaitUntil('double'),
'wait-until-string': () => PipelineWaitUntil('string'),
'wait-until-seconds': () => PipelineWaitUntilSeconds(),
'switch': () => PipelineSwitch(),
};

View file

@ -25,25 +25,16 @@ abstract class PipelineCondition extends PipelineExecutor {
' != ': (v0, v1, caster) => caster(v0) != caster(v1),
};
typeCaster = {
'int': (value) => (value == 'null' || value == null) ? null : int.parse(value) as int?,
'float': (value) => (value == 'null' || value == null) ? null : double.parse(value) as double?,
'int': (value) => (value == 'null' || value == null) ? null : (value is String) ? int.parse(value) as int : value,
'float': (value) => (value == 'null' || value == null) ? null : (value is String) ? double.parse(value) as double? : value,
'string': (value) => (value == 'null' || value == null) ? null : value,
'bool': (value) => (value == 'null' || value == null) ? null : (value.toLowerCase() == 'true') as bool?,
'bool': (value) => (value == 'null' || value == null) ? null : (value is String) ? (value.toLowerCase() == 'true') as bool? : value,
'version': (value) => (value == 'null' || value == null) ? null : AppDataManager.to.versionToNumber(value) as double?,
'object': (value) => (value == 'null' || value == null) ? null : value,
};
return PipelineValidateResult();
}
Future printCondition(String syntax, String condition, String postfix,
ConditionCheckResult result) async {
await CLI.println('[Pipeline-$syntax]', color: Color.magentaStrong);
print(
' - Condition: $condition\n - Values: ${result.conditionValue}\n - Result: ${result.result} ===> $postfix');
return simpleFuture;
}
ConditionCheckResult checkCondition(String condition) {
var result = ConditionCheckResult();
for (var item in conditions.entries) {

View file

@ -0,0 +1,74 @@
import 'package:dart_framework/utils/system_util.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/pipeline_data.dart';
import 'package:oto_cli/oto/pipeline/pipeline.dart';
import 'package:oto_cli/oto/pipeline/pipeline_condition.dart';
import 'package:oto_cli/oto/pipeline/pipeline_exe.dart';
class PipelineContain extends PipelineExecutor {
late DataContain data;
late Pipeline? _pipelineTrue;
late Pipeline? _pipelineFalse;
@override
PipelineValidateResult initialize(Map<String, dynamic> set) {
var result = PipelineValidateResult();
var data = DataContain.fromJson(set.values.first);
var dataValidateResult = data.validate();
if (!dataValidateResult.enable) {
return dataValidateResult;
}
//set true task
var validateResult = PipelineExecutor.validateTasks(data.on_true);
if (!validateResult.enable) {
return validateResult;
}
_pipelineTrue = validateResult.pipeline;
//set false task
validateResult = PipelineExecutor.validateTasks(data.on_false);
if (!validateResult.enable) {
return validateResult;
}
_pipelineFalse = validateResult.pipeline;
this.data = data;
return result;
}
@override
Future execute() async {
List list;
var listRaw = data.list;
if(listRaw is String) {
list = Command.replaceSingleTagValue(listRaw);
} else {
list = listRaw as List;
}
var result = ConditionCheckResult();
var value = Command.replaceSingleTagValue(data.target);
value ??= data.target;
result.conditionValue = 'Contain in "$value".';
result.result = list.contains(value);
await PipelineExecutor.printCondition('Contain', 'Contain in "${data.target}"', getPostfix(result.result), result);
if (result.result) {
await _pipelineTrue?.execute();
} else {
await _pipelineFalse?.execute();
}
return simpleFuture;
}
String getPostfix(bool condition) {
if (condition) {
return _pipelineTrue == null
? 'on-true not exist. Passed'
: 'Execute: on-true ';
} else {
return _pipelineFalse == null
? 'on-false not exist. Passed'
: 'Execute: on-false ';
}
}
}

View file

@ -4,6 +4,7 @@ import 'package:oto_cli/oto/application.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
import 'package:oto_cli/oto/pipeline/pipeline.dart';
import 'package:oto_cli/oto/pipeline/pipeline_condition.dart';
abstract class PipelineExecutor {
//set & validate data
@ -17,6 +18,15 @@ abstract class PipelineExecutor {
}
return result;
}
static Future printCondition(String syntax, String condition, String postfix,
ConditionCheckResult result) async {
await CLI.println('[Pipeline-$syntax]', color: Color.magentaStrong);
print(
' - Condition: $condition\n - Values: ${result.conditionValue}\n - Result: ${result.result} ===> $postfix');
return simpleFuture;
}
}
class PipelineExe extends PipelineExecutor {
@ -57,7 +67,9 @@ class PipelineExe extends PipelineExecutor {
// print('==================> [$time] Execute: $targetCommandID');
updateState(CommandState.progress);
var data = await commandData;
await Command.byType(data.command).execute(data);
var command = Command.byType(data.command);
command.id = commandID;
await command.execute(data);
updateState(CommandState.complete);
return simpleFuture;
}

View file

@ -0,0 +1,85 @@
import 'package:dart_framework/utils/system_util.dart';
import 'package:oto_cli/cli/cli.dart';
import 'package:oto_cli/oto/application.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/command_data.dart';
import 'package:oto_cli/oto/data/pipeline_data.dart';
import 'package:oto_cli/oto/pipeline/pipeline.dart';
import 'package:oto_cli/oto/pipeline/pipeline_exe.dart';
class ExeHandleData {
late Pipeline? pipelineSuccess;
late Pipeline? pipelineFail;
}
class PipelineExeHandle extends PipelineExecutor {
late DataExeHandle data;
late String commandID;
late ExeHandleData handleData;
@override
PipelineValidateResult initialize(Map<String, dynamic> set) {
var result = PipelineValidateResult();
if(set.values.first == null)
{
result.enable = false;
result.message = 'Yaml Syntex is not valid in "exe-handle"';
return result;
}
var data = DataExeHandle.fromJson(set.values.first);
var dataValidateResult = data.validate();
if (!dataValidateResult.enable) {
return dataValidateResult;
}
commandID = data.id;
if (!Application.instance.dataCommandMap.containsKey(commandID)) {
result.enable = false;
result.message =
'The "$commandID" command does not exist in the command list.';
}
updateState(CommandState.ready);
handleData = ExeHandleData();
//set success task
var validateResult = PipelineExecutor.validateTasks(data.on_success);
if (!validateResult.enable) {
return validateResult;
}
handleData.pipelineSuccess = validateResult.pipeline;
//set fail task
validateResult = PipelineExecutor.validateTasks(data.on_fail);
if (!validateResult.enable) {
return validateResult;
}
handleData.pipelineFail = validateResult.pipeline;
this.data = data;
return result;
}
Future<DataCommand> get commandData async {
var commandID = data.id;
var commandData = Application.instance.dataCommandMap[commandID]!;
await Application.instance.printBuildStep(
'Phase Start: ${commandData.name} ($commandID)',
Color.green);
return dataFutrue(commandData);
}
@override
Future execute() async {
updateState(CommandState.progress);
var data = await commandData;
var command = Command.byType(data.command);
command.id = commandID;
await command.executeHandle(data, handleData);
updateState(CommandState.complete);
return simpleFuture;
}
void updateState(CommandState state) {
Application.instance.updateCommandState(commandID, state);
}
}

View file

@ -0,0 +1,67 @@
import 'package:dart_framework/utils/system_util.dart';
import 'package:oto_cli/cli/cli.dart';
import 'package:oto_cli/oto/commands/command.dart';
import 'package:oto_cli/oto/data/pipeline_data.dart';
import 'package:oto_cli/oto/pipeline/pipeline.dart';
import 'package:oto_cli/oto/pipeline/pipeline_exe.dart';
class PipelineForeach extends PipelineExecutor {
late Pipeline? _pipelineOnDo;
late DataForeach data;
@override
PipelineValidateResult initialize(Map<String, dynamic> set) {
data = DataForeach.fromJson(set.values.first);
var dataValidateResult = data.validate();
if (!dataValidateResult.enable) {
return dataValidateResult;
}
//set do task
var validateResult = PipelineExecutor.validateTasks(data.on_do);
if (!validateResult.enable) {
return validateResult;
}
_pipelineOnDo = validateResult.pipeline;
return PipelineValidateResult();
}
@override
Future execute() async {
var iterator = Command.replaceTagValue(data.iterator);
var iteratorType = '';
if(iterator != null)
{
if(iterator is List)
{
iteratorType = 'List';
var elementTag = data.setValue;
for(var item in iterator)
{
await Command.setPropertyValue(elementTag, item);
await _pipelineOnDo?.execute();
}
}
if(iterator is Map)
{
iteratorType = 'Map';
var keyTag = data.setKey;
var elementTag = data.setValue;
for(var pair in iterator.entries)
{
if(keyTag != null)
{
await Command.setPropertyValue(keyTag, pair.key);
}
await Command.setPropertyValue(elementTag, pair.value);
await _pipelineOnDo?.execute();
}
}
await CLI.println('[Pipeline-Foreach ($iteratorType)]', color: Color.magentaStrong);
print(' - Foreach complete. Loop out');
}
return simpleFuture;
}
}

View file

@ -39,7 +39,7 @@ class PipelineIf extends PipelineCondition {
Future execute() async {
var condition = data.condition!;
var result = checkCondition(condition);
await printCondition('IF', condition, getPostfix(result.result), result);
await PipelineExecutor.printCondition('IF', condition, getPostfix(result.result), result);
if (result.result) {
await _pipelineTrue?.execute();
} else {

View file

@ -32,7 +32,7 @@ class PipelineSwitch extends PipelineCondition {
executed = true;
var validateResult = PipelineExecutor.validateTasks(item.tasks);
_pipeline = validateResult.pipeline;
await printCondition('Switch', data.condition!, 'Start task', result);
await PipelineExecutor.printCondition('Switch', data.condition!, 'Start task', result);
await _pipeline?.execute();
break;
}
@ -41,7 +41,7 @@ class PipelineSwitch extends PipelineCondition {
var result = ConditionCheckResult();
result.conditionValue = 'null';
result.result = false;
await printCondition(
await PipelineExecutor.printCondition(
'Switch', data.condition!, 'not exist Same condition', result);
}
return simpleFuture;

View file

@ -2,6 +2,7 @@ import 'package:dart_framework/utils/system_util.dart';
import 'package:oto_cli/oto/data/pipeline_data.dart';
import 'package:oto_cli/oto/pipeline/pipeline.dart';
import 'package:oto_cli/oto/pipeline/pipeline_condition.dart';
import 'package:oto_cli/oto/pipeline/pipeline_exe.dart';
class PipelineWaitUntil extends PipelineCondition {
PipelineWaitUntil(String type) {
@ -19,12 +20,38 @@ class PipelineWaitUntil extends PipelineCondition {
Future execute() async {
var condition = data.condition!;
var result = checkCondition(condition);
await printCondition('Wait-Until', condition, 'Start wait.', result);
await PipelineExecutor.printCondition('Wait-Until', condition, 'Start wait.', result);
while (result.result) {
await Future.delayed(const Duration(milliseconds: 500));
await Future.delayed(const Duration(milliseconds: 200));
result = checkCondition(data.condition!);
}
await printCondition('Wait-Until', condition, 'Loop escape.', result);
await PipelineExecutor.printCondition('Wait-Until', condition, 'Loop escape.', result);
return simpleFuture;
}
}
class PipelineWaitUntilSeconds extends PipelineExecutor {
PipelineWaitUntilSeconds();
late int milliseconds;
@override
PipelineValidateResult initialize(Map<String, dynamic> set) {
var value = set.values.first.toString();
var seconds = double.tryParse(value);
if (seconds == null) {
var result = PipelineValidateResult();
result.message = 'Failed to cast as double value: "$value"';
result.enable = false;
return result;
}
milliseconds = (seconds * 1000).round();
return PipelineValidateResult();
}
@override
Future execute() async {
await Future.delayed(Duration(milliseconds: milliseconds));
return simpleFuture;
}
}

View file

@ -32,11 +32,11 @@ class PipelineWhile extends PipelineCondition {
var condition = data.condition!;
var result = checkCondition(condition);
while (result.result) {
await printCondition('While', condition, 'Execute: on-do', result);
await PipelineExecutor.printCondition('While', condition, 'Execute: on-do', result);
await _pipelineOnDo?.execute();
result = checkCondition(data.condition!);
}
await printCondition('While', condition, 'Loop escaped.', result);
await PipelineExecutor.printCondition('While', condition, 'Loop escaped.', result);
return simpleFuture;
}
}

View file

@ -10,22 +10,22 @@ environment:
# Add regular dependencies here.
dependencies:
# path: ^1.8.0
json_annotation: ^4.8.0
json_annotation: ^4.8.1
resource_importer: ^0.2.0
dart_framework:
# path: '../dart_framework'
# path: ../dart_framework
git:
url: toki@toki-labs.com:/Volumes/Data2/git/dart_framework.git
ref: master
url: git@github.com:virtualoffice-meta-dev/dart_framework.git
ref: main
color: ^3.0.0
file_hasher: ^0.1.0+0
dev_dependencies:
lints: ^3.0.0
lints: ^4.0.0
test: ^1.24.9
build_runner: ^2.1.4
json_serializable: ^6.0.1
resource_importer:
resources:
silentbatch: assets/bin/silentbatch.exe