fastlane을 이용한 버전 컨트롤 & 업로드 작업
This commit is contained in:
parent
3135b4b4ed
commit
2c203c4719
7 changed files with 477 additions and 3 deletions
|
|
@ -1,6 +1,12 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:dart_framework/utils/string_util.dart';
|
||||
import 'package:dart_framework/utils/system_util.dart';
|
||||
import 'package:oto_cli/oto/commands/build/fastlane_template.dart';
|
||||
import 'package:oto_cli/oto/commands/file/file.dart';
|
||||
import 'package:xml/xml.dart';
|
||||
import 'package:oto_cli/oto/application.dart';
|
||||
import 'package:oto_cli/oto/commands/build/build_flutter.dart';
|
||||
import 'package:oto_cli/oto/commands/command.dart';
|
||||
|
|
@ -22,6 +28,100 @@ class BuildiOS extends Command {
|
|||
}
|
||||
var xcworkspaceFilePath = Command.getPathNormal(xcodeProjectPath);
|
||||
|
||||
String? version = data.version;
|
||||
String? buildNumber = data.buildNumber;
|
||||
var xcodeproj = data.xcodeProjectFilePath ??
|
||||
await getMainXcodeprojPath(data.xcworkspaceFilePath!);
|
||||
if (data.autoBuildNumber ?? false) {
|
||||
var appID = await getAppIdentifier(
|
||||
data.workspace, xcodeproj, data.scheme, data.setAppID);
|
||||
if (appID == null) {
|
||||
throw Exception('Can not find App Identifier.');
|
||||
}
|
||||
if (data.apiKeyPath == null) {
|
||||
throw Exception(
|
||||
'If autoVersionNumber = true then must set apiKeyPath.');
|
||||
}
|
||||
var json = jsonDecode(File(data.apiKeyPath!).readAsStringSync());
|
||||
var fastlaneContent = fastlaneTemplete;
|
||||
fastlaneContent = fastlaneContent
|
||||
.replaceFirst('[APP_IDENTIFIER]', appID)
|
||||
.replaceFirst('[API_KEY_ID]', json['key_id'])
|
||||
.replaceFirst('[API_ISSUER_ID]', json['issuer_id'])
|
||||
.replaceFirst('[AUTH_KEY_CONTENT]',
|
||||
json['key'].toString().replaceAll('\n', '\\n'));
|
||||
|
||||
var shell = StringBuffer();
|
||||
shell.write('cd ${data.workspace}');
|
||||
shell.write(' && rm -rf "${data.workspace}/fastlane"');
|
||||
shell.write(' && yes | fastlane init');
|
||||
await ProcessExecutor.run(shell);
|
||||
|
||||
var fastFile = File('${data.workspace}/fastlane/Fastfile');
|
||||
fastFile.writeAsStringSync(fastlaneContent, flush: true);
|
||||
|
||||
//Find PREPARE_FOR_SUBMISSION state Version
|
||||
String? targetVersion;
|
||||
shell = StringBuffer();
|
||||
shell.write('cd ${data.workspace}/fastlane');
|
||||
shell.write(' && fastlane appstore_versions');
|
||||
var process = await ProcessExecutor.run(shell);
|
||||
var arr = process.stdout.toString().split('\n');
|
||||
const result = '[RESULT]: ';
|
||||
for (var item in arr) {
|
||||
if (item.contains(result)) {
|
||||
var jsonArr =
|
||||
jsonDecode(item.substring(item.indexOf(result) + result.length))
|
||||
as List<dynamic>;
|
||||
for (var item in jsonArr) {
|
||||
if (item['state'] == 'PREPARE_FOR_SUBMISSION') {
|
||||
targetVersion = item['version'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (targetVersion == null) {
|
||||
throw Exception(
|
||||
'Can not find target version when state = PREPARE_FOR_SUBMISSION.');
|
||||
}
|
||||
version = targetVersion;
|
||||
|
||||
//Find Last Build Number
|
||||
String? targetBuildNumber;
|
||||
fastlaneContent =
|
||||
fastlaneContent.replaceFirst('[LATEST_VERSION]', version);
|
||||
fastFile.writeAsStringSync(fastlaneContent, flush: true);
|
||||
shell = StringBuffer();
|
||||
shell.write('cd ${data.workspace}/fastlane');
|
||||
shell.write(' && fastlane latest_build_number');
|
||||
process = await ProcessExecutor.run(shell);
|
||||
arr = process.stdout.toString().split('\n');
|
||||
|
||||
for (var item in arr) {
|
||||
if (item.contains(result)) {
|
||||
var json =
|
||||
jsonDecode(item.substring(item.indexOf(result) + result.length));
|
||||
targetBuildNumber = json['latest_build_number'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (targetBuildNumber == null) {
|
||||
throw Exception('Can not find target build number.');
|
||||
}
|
||||
buildNumber = incrementVersion(targetBuildNumber);
|
||||
}
|
||||
|
||||
if (version != null) {
|
||||
await updateMarketingVersion(
|
||||
'${data.workspace}/$xcodeproj/project.pbxproj', version);
|
||||
}
|
||||
if (buildNumber != null) {
|
||||
await updateBuildNumber(
|
||||
'${data.workspace}/$xcodeproj/project.pbxproj', buildNumber);
|
||||
}
|
||||
|
||||
var os = 'iOS';
|
||||
if (data.os != null) {
|
||||
if (data.os == BuildPlatform.Macos) {
|
||||
|
|
@ -92,6 +192,116 @@ class BuildiOS extends Command {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> getAppIdentifier(String? workspace, String? xcodeproj,
|
||||
String scheme, String? setAppID) async {
|
||||
String? identifier;
|
||||
var shell = StringBuffer();
|
||||
shell.write(
|
||||
"xcodebuild -project '$workspace/$xcodeproj' -scheme $scheme -destination 'generic/platform=iOS Simulator' -showBuildSettings | grep 'PRODUCT_BUNDLE_IDENTIFIER' | tail -n1 | awk -F ' = ' '{print \$2}'");
|
||||
|
||||
var process = await ProcessExecutor.start(shell,
|
||||
workspace: workspace,
|
||||
printStderr: false,
|
||||
logHandler: Application.logWithType);
|
||||
for (var item in process.stdoutArr) {
|
||||
var appID = item.trim().replaceAll(' ', '');
|
||||
if (appID.isNotEmpty) {
|
||||
setAppID = (setAppID == null) ? '<@property.appIdentifier>' : setAppID;
|
||||
await setProperty(setAppID, appID);
|
||||
identifier = appID;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dataFutrue(identifier);
|
||||
}
|
||||
|
||||
Future<String?> getMainXcodeprojPath(String workspacePath) async {
|
||||
final contentsPath = '$workspacePath/contents.xcworkspacedata';
|
||||
final file = File(contentsPath);
|
||||
if (!await file.exists()) return null;
|
||||
|
||||
final xmlString = await file.readAsString();
|
||||
final document = XmlDocument.parse(xmlString);
|
||||
|
||||
final fileRef = document.findAllElements('FileRef').firstWhere(
|
||||
(element) =>
|
||||
element.getAttribute('location')?.endsWith('.xcodeproj') ?? false,
|
||||
orElse: () => XmlElement(XmlName('Dummy')), // 타입만 맞추고 null 체크는 나중에
|
||||
);
|
||||
|
||||
final location =
|
||||
fileRef.name.local == 'Dummy' ? null : fileRef.getAttribute('location');
|
||||
if (location != null && location.startsWith('group:')) {
|
||||
return location.replaceFirst('group:', '');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> updateMarketingVersion(
|
||||
String pbxprojPath, String version) async {
|
||||
await _updatePbxprojSetting(
|
||||
pbxprojPath: pbxprojPath,
|
||||
settingKey: 'MARKETING_VERSION',
|
||||
settingValue: version,
|
||||
);
|
||||
print('✅ Updated MARKETING_VERSION = $version');
|
||||
}
|
||||
|
||||
Future<void> updateBuildNumber(String pbxprojPath, String buildNumber) async {
|
||||
await _updatePbxprojSetting(
|
||||
pbxprojPath: pbxprojPath,
|
||||
settingKey: 'CURRENT_PROJECT_VERSION',
|
||||
settingValue: buildNumber,
|
||||
);
|
||||
print('✅ Updated CURRENT_PROJECT_VERSION = $buildNumber');
|
||||
}
|
||||
|
||||
Future<void> _updatePbxprojSetting({
|
||||
required String pbxprojPath,
|
||||
required String settingKey,
|
||||
required String settingValue,
|
||||
}) async {
|
||||
final file = File(pbxprojPath);
|
||||
if (!await file.exists()) throw Exception('File not found: $pbxprojPath');
|
||||
|
||||
final lines = await file.readAsLines();
|
||||
|
||||
final updatedLines = <String>[];
|
||||
bool insideBuildSettings = false;
|
||||
bool hasTargetSetting = false;
|
||||
|
||||
for (var line in lines) {
|
||||
final trimmed = line.trim();
|
||||
|
||||
if (trimmed == 'buildSettings = {') {
|
||||
insideBuildSettings = true;
|
||||
hasTargetSetting = false;
|
||||
updatedLines.add(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (insideBuildSettings && trimmed == '};') {
|
||||
// 삽입 필요 시 추가
|
||||
if (!hasTargetSetting) {
|
||||
updatedLines.add(' $settingKey = $settingValue;');
|
||||
}
|
||||
insideBuildSettings = false;
|
||||
updatedLines.add(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (insideBuildSettings && trimmed.startsWith('$settingKey =')) {
|
||||
line = line.replaceFirst(RegExp('$settingKey = .*?;'),
|
||||
' $settingKey = $settingValue;');
|
||||
hasTargetSetting = true;
|
||||
}
|
||||
|
||||
updatedLines.add(line);
|
||||
}
|
||||
|
||||
await file.writeAsString(updatedLines.join('\n'));
|
||||
}
|
||||
}
|
||||
|
||||
class CodeSign extends Command {
|
||||
|
|
|
|||
116
lib/oto/commands/build/fastlane_template.dart
Normal file
116
lib/oto/commands/build/fastlane_template.dart
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
var fastlaneTemplete = '''
|
||||
default_platform(:ios)
|
||||
|
||||
APP_IDENTIFIER = "[APP_IDENTIFIER]"
|
||||
|
||||
platform :ios do
|
||||
private_lane :base_api_key do
|
||||
app_store_connect_api_key(
|
||||
key_id: "[API_KEY_ID]",
|
||||
issuer_id: "[API_ISSUER_ID]",
|
||||
key_content: "[AUTH_KEY_CONTENT]"
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
desc "지정한 앱 버전 + 빌드 넘버에 대한 TestFlight 상태 추적 (JSON 출력)"
|
||||
lane :testflight_status do
|
||||
require 'spaceship'
|
||||
require 'json'
|
||||
|
||||
api_key = base_api_key
|
||||
|
||||
target_app_version = "[TARGET_VERSION]" # CFBundleShortVersionString
|
||||
target_build_number = "[TARGET_BUILD_NUMBER]" # CFBundleVersion
|
||||
|
||||
app = Spaceship::ConnectAPI::App.find(APP_IDENTIFIER)
|
||||
builds = app.get_builds(includes: "preReleaseVersion")
|
||||
|
||||
matched = builds.find do |b|
|
||||
b.version.to_s == target_build_number &&
|
||||
b.respond_to?(:pre_release_version) &&
|
||||
b.pre_release_version&.version == target_app_version
|
||||
end
|
||||
|
||||
result = {
|
||||
version: target_app_version,
|
||||
build_number: target_build_number,
|
||||
state: matched ? matched.processing_state : "NONE",
|
||||
uploaded: matched ? matched.uploaded_date.to_s : nil
|
||||
}
|
||||
|
||||
puts "[RESULT]: #{JSON.generate(result)}"
|
||||
end
|
||||
|
||||
|
||||
desc "TestFlight에 등록된 특정 버전의 최신 빌드 넘버 가져오기 (JSON 출력)"
|
||||
lane :latest_build_number do
|
||||
require 'json'
|
||||
|
||||
api_key = base_api_key
|
||||
|
||||
target_version = "[LATEST_VERSION]"
|
||||
|
||||
latest_build = app_store_build_number(
|
||||
api_key: api_key,
|
||||
app_identifier: APP_IDENTIFIER,
|
||||
version: target_version,
|
||||
live: false
|
||||
)
|
||||
|
||||
result = {
|
||||
version: target_version,
|
||||
latest_build_number: latest_build
|
||||
}
|
||||
|
||||
puts "[RESULT]: #{JSON.generate(result)}"
|
||||
end
|
||||
|
||||
|
||||
desc "필터 조건에 맞춰 App Store Connect 버전 상태 JSON 출력"
|
||||
lane :appstore_versions do
|
||||
require 'spaceship'
|
||||
require 'json'
|
||||
require 'rubygems' # for Gem::Version
|
||||
|
||||
api_key = base_api_key
|
||||
|
||||
app = Spaceship::ConnectAPI::App.find(APP_IDENTIFIER)
|
||||
|
||||
versions = app.get_app_store_versions
|
||||
.select { |v| v.platform == "IOS" }
|
||||
.reject { |v| v.app_store_state == "REPLACED_WITH_NEW_VERSION" }
|
||||
|
||||
# 1. READY_FOR_SALE 중 최신
|
||||
latest_ready = versions
|
||||
.select { |v| v.app_store_state == "READY_FOR_SALE" }
|
||||
.max_by { |v| v.respond_to?(:created_date) ? v.created_date.to_s : "" }
|
||||
|
||||
# 2. PREPARE_FOR_SUBMISSION 중 가장 버전 낮은 것
|
||||
prepare_versions = versions
|
||||
.select { |v| v.app_store_state == "PREPARE_FOR_SUBMISSION" }
|
||||
.sort_by { |v| Gem::Version.new(v.version_string) }
|
||||
|
||||
lowest_prepare = prepare_versions.first
|
||||
|
||||
# 3. 기타 상태 버전들 (READY_FOR_SALE, PREPARE_FOR_SUBMISSION, REPLACED 제외)
|
||||
included_states = ["READY_FOR_SALE", "PREPARE_FOR_SUBMISSION", "REPLACED_WITH_NEW_VERSION"]
|
||||
others = versions.reject { |v| included_states.include?(v.app_store_state) }
|
||||
|
||||
selected = []
|
||||
selected << latest_ready if latest_ready
|
||||
selected << lowest_prepare if lowest_prepare
|
||||
selected += others
|
||||
|
||||
json_output = selected.map do |v|
|
||||
{
|
||||
version: v.version_string,
|
||||
state: v.app_store_state,
|
||||
created: v.respond_to?(:created_date) ? v.created_date.to_s : nil
|
||||
}
|
||||
end
|
||||
|
||||
puts "[RESULT]: #{JSON.generate(json_output)}"
|
||||
end
|
||||
end
|
||||
''';
|
||||
45
lib/oto/commands/build/testflight_ios.dart
Normal file
45
lib/oto/commands/build/testflight_ios.dart
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
import 'package:dart_framework/platform/process.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';
|
||||
|
||||
class TestflightUpload extends Command {
|
||||
Function? get error => null;
|
||||
|
||||
@override
|
||||
Future execute(DataCommand command) async {
|
||||
var data = DataTestflightUpload.fromJson(getParam(command));
|
||||
var apiKeyPath = Command.getPathNormal(data.apiKeyPath);
|
||||
var ipaPath = Command.getPathNormal(data.ipaPath);
|
||||
|
||||
var shell = StringBuffer();
|
||||
shell.write(
|
||||
'FASTLANE_DISABLE_PRECHECK=1 fastlane deliver upload_binary --ipa "$ipaPath" --api_key_path "$apiKeyPath" --force');
|
||||
|
||||
var process = await ProcessExecutor.start(shell,
|
||||
workspace: workspace,
|
||||
printStderr: false,
|
||||
logHandler: Application.logWithType);
|
||||
|
||||
return await completeProcess(process, command, passExitCodes: [1]);
|
||||
}
|
||||
}
|
||||
|
||||
class IOSVersion extends Command {
|
||||
Function? get error => null;
|
||||
|
||||
@override
|
||||
Future execute(DataCommand command) async {
|
||||
var data = DataiOSVersion.fromJson(getParam(command));
|
||||
|
||||
var shell = StringBuffer();
|
||||
shell.write("echo 'test'");
|
||||
|
||||
var process = await ProcessExecutor.start(shell,
|
||||
workspace: workspace,
|
||||
printStderr: false,
|
||||
logHandler: Application.logWithType);
|
||||
|
||||
return await completeProcess(process, command, passExitCodes: [1]);
|
||||
}
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ 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/build/testflight_ios.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';
|
||||
|
|
@ -53,6 +54,8 @@ enum CommandType {
|
|||
BuildDartCompile,
|
||||
BuildDotNet,
|
||||
BuildiOS,
|
||||
TestflightUpload,
|
||||
IOSVersion,
|
||||
BuildMSBuild,
|
||||
CodeSign,
|
||||
CodeSignVerify,
|
||||
|
|
@ -122,6 +125,8 @@ abstract class Command {
|
|||
CommandType.BuildDartCompile: () => BuildDartCompile(),
|
||||
CommandType.BuildDotNet: () => BuildDotNet(),
|
||||
CommandType.BuildiOS: () => BuildiOS(),
|
||||
CommandType.TestflightUpload: () => TestflightUpload(),
|
||||
CommandType.IOSVersion: () => IOSVersion(),
|
||||
CommandType.BuildMSBuild: () => BuildMSBuild(),
|
||||
CommandType.CodeSign: () => CodeSign(),
|
||||
CommandType.CodeSignVerify: () => CodeSignVerify(),
|
||||
|
|
@ -147,7 +152,7 @@ abstract class Command {
|
|||
CommandType.StringReplace: () => StringReplace(),
|
||||
CommandType.StringReplacePattern: () => StringReplacePattern(),
|
||||
CommandType.StringIndex: () => StringIndex(),
|
||||
CommandType.URLInfo: ()=> URLInfo(),
|
||||
CommandType.URLInfo: () => URLInfo(),
|
||||
CommandType.Jira: () => Jira(),
|
||||
CommandType.Zip: () => Zip(),
|
||||
CommandType.Shell: () => Shell(),
|
||||
|
|
|
|||
|
|
@ -221,6 +221,13 @@ class DataBuildiOS extends DataParam {
|
|||
late String? configuration;
|
||||
late Map<String, String>? settings;
|
||||
|
||||
//Version Setting
|
||||
late String? version;
|
||||
late String? buildNumber;
|
||||
late bool? autoBuildNumber = false;
|
||||
late String? apiKeyPath; //autoVersionNumber 사용시 필수
|
||||
late String? setAppID;
|
||||
|
||||
factory DataBuildiOS.fromJson(Map<String, dynamic> json) =>
|
||||
_$DataBuildiOSFromJson(json);
|
||||
@override
|
||||
|
|
@ -322,6 +329,35 @@ class DataExportiOS extends DataParam {
|
|||
Map<String, dynamic> toJson() => _$DataExportiOSToJson(this);
|
||||
}
|
||||
|
||||
//TestflightUpload
|
||||
@JsonSerializable()
|
||||
class DataTestflightUpload extends DataParam {
|
||||
DataTestflightUpload();
|
||||
|
||||
late String apiKeyPath;
|
||||
late String ipaPath;
|
||||
|
||||
factory DataTestflightUpload.fromJson(Map<String, dynamic> json) =>
|
||||
_$DataTestflightUploadFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$DataTestflightUploadToJson(this);
|
||||
}
|
||||
|
||||
//iOSVersion
|
||||
@JsonSerializable()
|
||||
class DataiOSVersion extends DataParam {
|
||||
DataiOSVersion();
|
||||
|
||||
late String scheme;
|
||||
late String xcworkspacePath;
|
||||
late String? setAppID;
|
||||
|
||||
factory DataiOSVersion.fromJson(Map<String, dynamic> json) =>
|
||||
_$DataiOSVersionFromJson(json);
|
||||
@override
|
||||
Map<String, dynamic> toJson() => _$DataiOSVersionToJson(this);
|
||||
}
|
||||
|
||||
//PublishiOS
|
||||
@JsonSerializable()
|
||||
class DataPublishiOS extends DataParam {
|
||||
|
|
@ -1005,7 +1041,6 @@ class DataURLInfo extends DataParam {
|
|||
Map<String, dynamic> toJson() => _$DataURLInfoToJson(this);
|
||||
}
|
||||
|
||||
|
||||
//Web String Replace Item
|
||||
@JsonSerializable()
|
||||
class DataStringReplacePair extends DataParam {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,8 @@ const _$CommandTypeEnumMap = {
|
|||
CommandType.BuildDartCompile: 'BuildDartCompile',
|
||||
CommandType.BuildDotNet: 'BuildDotNet',
|
||||
CommandType.BuildiOS: 'BuildiOS',
|
||||
CommandType.TestflightUpload: 'TestflightUpload',
|
||||
CommandType.IOSVersion: 'IOSVersion',
|
||||
CommandType.BuildMSBuild: 'BuildMSBuild',
|
||||
CommandType.CodeSign: 'CodeSign',
|
||||
CommandType.CodeSignVerify: 'CodeSignVerify',
|
||||
|
|
@ -391,7 +393,12 @@ DataBuildiOS _$DataBuildiOSFromJson(Map<String, dynamic> json) => DataBuildiOS()
|
|||
..configuration = json['configuration'] as String?
|
||||
..settings = (json['settings'] as Map<String, dynamic>?)?.map(
|
||||
(k, e) => MapEntry(k, e as String),
|
||||
);
|
||||
)
|
||||
..version = json['version'] as String?
|
||||
..buildNumber = json['buildNumber'] as String?
|
||||
..autoBuildNumber = json['autoBuildNumber'] as bool?
|
||||
..apiKeyPath = json['apiKeyPath'] as String?
|
||||
..setAppID = json['setAppID'] as String?;
|
||||
|
||||
Map<String, dynamic> _$DataBuildiOSToJson(DataBuildiOS instance) =>
|
||||
<String, dynamic>{
|
||||
|
|
@ -409,6 +416,11 @@ Map<String, dynamic> _$DataBuildiOSToJson(DataBuildiOS instance) =>
|
|||
'cleanPod': instance.cleanPod,
|
||||
'configuration': instance.configuration,
|
||||
'settings': instance.settings,
|
||||
'version': instance.version,
|
||||
'buildNumber': instance.buildNumber,
|
||||
'autoBuildNumber': instance.autoBuildNumber,
|
||||
'apiKeyPath': instance.apiKeyPath,
|
||||
'setAppID': instance.setAppID,
|
||||
};
|
||||
|
||||
const _$BuildPlatformEnumMap = {
|
||||
|
|
@ -579,6 +591,56 @@ Map<String, dynamic> _$DataExportiOSToJson(DataExportiOS instance) =>
|
|||
'exportPath': instance.exportPath,
|
||||
};
|
||||
|
||||
DataTestflightUpload _$DataTestflightUploadFromJson(
|
||||
Map<String, dynamic> json) =>
|
||||
DataTestflightUpload()
|
||||
..workspace = json['workspace'] as String?
|
||||
..passExitCodes = (json['passExitCodes'] as List<dynamic>?)
|
||||
?.map((e) => (e as num).toInt())
|
||||
.toList()
|
||||
..setResult = json['setResult'] as String?
|
||||
..setExitCode = json['setExitCode'] as String?
|
||||
..showPrint = json['showPrint'] as bool?
|
||||
..apiKeyPath = json['apiKeyPath'] as String
|
||||
..ipaPath = json['ipaPath'] as String;
|
||||
|
||||
Map<String, dynamic> _$DataTestflightUploadToJson(
|
||||
DataTestflightUpload instance) =>
|
||||
<String, dynamic>{
|
||||
'workspace': instance.workspace,
|
||||
'passExitCodes': instance.passExitCodes,
|
||||
'setResult': instance.setResult,
|
||||
'setExitCode': instance.setExitCode,
|
||||
'showPrint': instance.showPrint,
|
||||
'apiKeyPath': instance.apiKeyPath,
|
||||
'ipaPath': instance.ipaPath,
|
||||
};
|
||||
|
||||
DataiOSVersion _$DataiOSVersionFromJson(Map<String, dynamic> json) =>
|
||||
DataiOSVersion()
|
||||
..workspace = json['workspace'] as String?
|
||||
..passExitCodes = (json['passExitCodes'] as List<dynamic>?)
|
||||
?.map((e) => (e as num).toInt())
|
||||
.toList()
|
||||
..setResult = json['setResult'] as String?
|
||||
..setExitCode = json['setExitCode'] as String?
|
||||
..showPrint = json['showPrint'] as bool?
|
||||
..scheme = json['scheme'] as String
|
||||
..xcworkspacePath = json['xcworkspacePath'] as String
|
||||
..setAppID = json['setAppID'] as String?;
|
||||
|
||||
Map<String, dynamic> _$DataiOSVersionToJson(DataiOSVersion instance) =>
|
||||
<String, dynamic>{
|
||||
'workspace': instance.workspace,
|
||||
'passExitCodes': instance.passExitCodes,
|
||||
'setResult': instance.setResult,
|
||||
'setExitCode': instance.setExitCode,
|
||||
'showPrint': instance.showPrint,
|
||||
'scheme': instance.scheme,
|
||||
'xcworkspacePath': instance.xcworkspacePath,
|
||||
'setAppID': instance.setAppID,
|
||||
};
|
||||
|
||||
DataPublishiOS _$DataPublishiOSFromJson(Map<String, dynamic> json) =>
|
||||
DataPublishiOS()
|
||||
..workspace = json['workspace'] as String?
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ dependencies:
|
|||
color: ^3.0.0
|
||||
file_hasher: ^0.1.0+0
|
||||
cron: ^0.6.1
|
||||
xml: ^6.3.0
|
||||
|
||||
dev_dependencies:
|
||||
lints: ^5.0.0
|
||||
|
|
|
|||
Loading…
Reference in a new issue