diff --git a/.gitignore b/.gitignore index 82460d3..4e11ca6 100644 --- a/.gitignore +++ b/.gitignore @@ -32,8 +32,6 @@ xcuserdata/ ## Obj-C/Swift specific *.hmap *.ipa -*.dSYM.zip -*.dSYM # CocoaPods # diff --git a/Art/AddServer.png b/Art/AddServer.png new file mode 100644 index 0000000..a855be4 Binary files /dev/null and b/Art/AddServer.png differ diff --git a/Art/AddToken.png b/Art/AddToken.png new file mode 100644 index 0000000..55988af Binary files /dev/null and b/Art/AddToken.png differ diff --git a/Art/MonitorRepo.png b/Art/MonitorRepo.png new file mode 100644 index 0000000..977dad0 Binary files /dev/null and b/Art/MonitorRepo.png differ diff --git a/Art/Monitoring.png b/Art/Monitoring.png new file mode 100644 index 0000000..d7f89cc Binary files /dev/null and b/Art/Monitoring.png differ diff --git a/Art/StatusWindow.png b/Art/StatusWindow.png new file mode 100644 index 0000000..a83abe5 Binary files /dev/null and b/Art/StatusWindow.png differ diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..8f78d54 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# xcode-github Change Log + +## v1.1.2 - February 20, 2019 +* Fixed the build so it works in development and release modes. (#8) + +## v1.1.1 - February 15, 2019 +* Bug fix: Adding another server in the preferences wasn't always persisted. +* Bug fix: If an Xcode server had no bots defined then no items appeared in the status window. +* Bug fix: The wrong git branch was used when a new PR bot was created from the template bot. + +## v1.1.0 - January 29, 2019 +* Fixed Xcode server login. +* Updated documentation. +* Fixed a problem when clone a branch from a template bot. +* Cleaned up menu items and dialogs. diff --git a/xcode-github-app/xcode-github-app.md b/Documentation/xcode-github-app.md similarity index 89% rename from xcode-github-app/xcode-github-app.md rename to Documentation/xcode-github-app.md index bfc5848..05e05bb 100644 --- a/xcode-github-app/xcode-github-app.md +++ b/Documentation/xcode-github-app.md @@ -18,15 +18,17 @@ * [x] On bots, if last integration# != current# then update the status on GitHub. * [x] Clean up code. * [x] Refresh Sec -> Min -* [x] Rename build products: XcodeGitHub.framework, Xcode-GitHub.app, xcode-github (cli tool), Tests +* [x] Rename build products: XcodeGitHub.framework, XcodeGitHub.app, xcode-github (cli tool), Tests * [x] Don't update 'Products' every time, just when making a release with a build script. * [x] Fix testing: fix the project layout, test bundle name, and project bindings. -* [ ] Add 'New' menu items: Add new server. Add new Xcode bot? -* [ ] Add 'About...' panel. +* [x] Add 'Start/Cancel Integration' menu item. +* [x] Add 'New' menu items: Add new server. Add new Xcode bot? +* [x] Add 'About...' panel. * [ ] Add help. ``` - ## Help +## Help + * About - Problems it solves. - What it does. @@ -74,17 +76,20 @@ * Maybe: Button: Start / Stop Button * Maybe: Button: Download logs -- or - +-- or -- #### Tree with Columns +``` | Server | Repo | PRs | Status | Server +------ Repo - +----- PR -- Status + +----- PR -- Status +``` ### Settings Window + * Add server * Add GitHub Token * Dry run, show debug messages, refresh time diff --git a/xcode-github-cli/xcode-github-cli.md b/Documentation/xcode-github-cli.md similarity index 98% rename from xcode-github-cli/xcode-github-cli.md rename to Documentation/xcode-github-cli.md index f33e527..eec1738 100644 --- a/xcode-github-cli/xcode-github-cli.md +++ b/Documentation/xcode-github-cli.md @@ -67,6 +67,9 @@ usage: xcode-github [-dhsVv] -g -x, --xcodeserver The network name of the xcode server. + +The tool returns 0 on success, otherwise a non-zero value. + ``` ## Program Flow @@ -99,6 +102,7 @@ GitHub "Close PR" Event -> xcode-github deletes Xcode Bot ### Xcode Bot Documentation * [Xcode Bot Documentation](https://developer.apple.com/library/content/documentation/Xcode/Conceptual/XcodeServerAPIReference/Bots.html) +* Debugging hint: In console include messages with subsystem contains `xcsd`. #### Xcode Schemes * [Xcode URI Scheme Examples](https://cocoaengineering.com/2018/01/01/some-useful-url-schemes-in-xcode-9/) diff --git a/Products/XcodeGitHub.app.dSYM.zip b/Products/XcodeGitHub.app.dSYM.zip new file mode 100644 index 0000000..ac709d1 Binary files /dev/null and b/Products/XcodeGitHub.app.dSYM.zip differ diff --git a/Products/XcodeGitHub.app.zip b/Products/XcodeGitHub.app.zip new file mode 100644 index 0000000..2eabe0c Binary files /dev/null and b/Products/XcodeGitHub.app.zip differ diff --git a/Products/XcodeGitHub.app/Contents/Info.plist b/Products/XcodeGitHub.app/Contents/Info.plist deleted file mode 100644 index 6483ba7..0000000 --- a/Products/XcodeGitHub.app/Contents/Info.plist +++ /dev/null @@ -1,61 +0,0 @@ - - - - - BuildMachineOSBuild - 17G3025 - CFBundleDevelopmentRegion - en - CFBundleExecutable - XcodeGitHub - CFBundleIconFile - AppIcon - CFBundleIconName - AppIcon - CFBundleIdentifier - io.branch.xcode-github-app - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - XcodeGitHub - CFBundlePackageType - APPL - CFBundleShortVersionString - 1.0.3 - CFBundleSupportedPlatforms - - MacOSX - - CFBundleVersion - 1 - DTCompiler - com.apple.compilers.llvm.clang.1_0 - DTPlatformBuild - 10B61 - DTPlatformVersion - GM - DTSDKBuild - 18B71 - DTSDKName - macosx10.14 - DTXcode - 1010 - DTXcodeBuild - 10B61 - LSApplicationCategoryType - public.app-category.utilities - LSMinimumSystemVersion - 10.11 - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - NSHumanReadableCopyright - Copyright © 2018 Branch. All rights reserved. - NSMainStoryboardFile - Main - NSPrincipalClass - NSApplication - - diff --git a/Products/XcodeGitHub.app/Contents/MacOS/XcodeGitHub b/Products/XcodeGitHub.app/Contents/MacOS/XcodeGitHub deleted file mode 100755 index d2a9032..0000000 Binary files a/Products/XcodeGitHub.app/Contents/MacOS/XcodeGitHub and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/PkgInfo b/Products/XcodeGitHub.app/Contents/PkgInfo deleted file mode 100644 index bd04210..0000000 --- a/Products/XcodeGitHub.app/Contents/PkgInfo +++ /dev/null @@ -1 +0,0 @@ -APPL???? \ No newline at end of file diff --git a/Products/XcodeGitHub.app/Contents/Resources/AppIcon.icns b/Products/XcodeGitHub.app/Contents/Resources/AppIcon.icns deleted file mode 100644 index 6eea55c..0000000 Binary files a/Products/XcodeGitHub.app/Contents/Resources/AppIcon.icns and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/Resources/Assets.car b/Products/XcodeGitHub.app/Contents/Resources/Assets.car deleted file mode 100644 index 71fae76..0000000 Binary files a/Products/XcodeGitHub.app/Contents/Resources/Assets.car and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist b/Products/XcodeGitHub.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist deleted file mode 100644 index 2f3a655..0000000 Binary files a/Products/XcodeGitHub.app/Contents/Resources/Base.lproj/Main.storyboardc/Info.plist and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib b/Products/XcodeGitHub.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib deleted file mode 100644 index f31a7eb..0000000 Binary files a/Products/XcodeGitHub.app/Contents/Resources/Base.lproj/Main.storyboardc/MainMenu.nib and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/Resources/XGAAddServerPanel.nib b/Products/XcodeGitHub.app/Contents/Resources/XGAAddServerPanel.nib deleted file mode 100644 index 418b0e6..0000000 Binary files a/Products/XcodeGitHub.app/Contents/Resources/XGAAddServerPanel.nib and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/Resources/XGALogViewController.nib b/Products/XcodeGitHub.app/Contents/Resources/XGALogViewController.nib deleted file mode 100644 index 5194ea0..0000000 Binary files a/Products/XcodeGitHub.app/Contents/Resources/XGALogViewController.nib and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/Resources/XGAPreferencesViewController.nib b/Products/XcodeGitHub.app/Contents/Resources/XGAPreferencesViewController.nib deleted file mode 100644 index 773fdc6..0000000 Binary files a/Products/XcodeGitHub.app/Contents/Resources/XGAPreferencesViewController.nib and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/Resources/XGAStatusPopover.nib b/Products/XcodeGitHub.app/Contents/Resources/XGAStatusPopover.nib deleted file mode 100644 index 4a1e7d4..0000000 Binary files a/Products/XcodeGitHub.app/Contents/Resources/XGAStatusPopover.nib and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/Resources/XGAStatusViewController.nib b/Products/XcodeGitHub.app/Contents/Resources/XGAStatusViewController.nib deleted file mode 100644 index 2490284..0000000 Binary files a/Products/XcodeGitHub.app/Contents/Resources/XGAStatusViewController.nib and /dev/null differ diff --git a/Products/XcodeGitHub.app/Contents/_CodeSignature/CodeResources b/Products/XcodeGitHub.app/Contents/_CodeSignature/CodeResources deleted file mode 100644 index 50fbfcb..0000000 --- a/Products/XcodeGitHub.app/Contents/_CodeSignature/CodeResources +++ /dev/null @@ -1,252 +0,0 @@ - - - - - files - - Resources/AppIcon.icns - - BzPY50tfR8K3DAqFXJ5vG1zzFKw= - - Resources/Assets.car - - ePFeq4yE+dagtxXyZeWxoL+xAQs= - - Resources/Base.lproj/Main.storyboardc/Info.plist - - M1rS+Tcas1ZdM4/iibTlduTJ22M= - - Resources/Base.lproj/Main.storyboardc/MainMenu.nib - - hpIbmAhHEUabx2N+8zv+81ljp4E= - - Resources/XGAAddServerPanel.nib - - zKqBwYFnODXM4YTjeDcNQjgoiOE= - - Resources/XGALogViewController.nib - - OSinBcz5C8LdOQjK21bCKf0TRo0= - - Resources/XGAPreferencesViewController.nib - - RsnDJgQGQSeUPQ6/cyb96TuMuXY= - - Resources/XGAStatusPopover.nib - - IQYYUWsLytlz7v0DE5zAnAz3mvU= - - Resources/XGAStatusViewController.nib - - 2a9uGOty1vbflvSedWuau0dt0SE= - - - files2 - - Resources/AppIcon.icns - - hash - - BzPY50tfR8K3DAqFXJ5vG1zzFKw= - - hash2 - - sZWW/dBotS8allTjW8bPqJqClVVri5nolraxSkUgI1I= - - - Resources/Assets.car - - hash - - ePFeq4yE+dagtxXyZeWxoL+xAQs= - - hash2 - - v2eM8fD4+r7Cg6bdWJC2TvFQaFGPgFAOg13dQ+8YJTA= - - - Resources/Base.lproj/Main.storyboardc/Info.plist - - hash - - M1rS+Tcas1ZdM4/iibTlduTJ22M= - - hash2 - - 6/2HagpKuzGhxFgQU55Lc/bxgR30qm5eqHSV+p9e4/4= - - - Resources/Base.lproj/Main.storyboardc/MainMenu.nib - - hash - - hpIbmAhHEUabx2N+8zv+81ljp4E= - - hash2 - - h8oGNaxlxwS6SWNq4bkMG3mEzC8x4rcHKUDMwQ4CxLk= - - - Resources/XGAAddServerPanel.nib - - hash - - zKqBwYFnODXM4YTjeDcNQjgoiOE= - - hash2 - - lMwN2ee+lgvAM/p2LRJrFp2kTMYJhJcqvxm2doxSFZg= - - - Resources/XGALogViewController.nib - - hash - - OSinBcz5C8LdOQjK21bCKf0TRo0= - - hash2 - - snoDa+9dulodYPuB9FwkY7T1YA1/o0ZQgmTmCG+4u+c= - - - Resources/XGAPreferencesViewController.nib - - hash - - RsnDJgQGQSeUPQ6/cyb96TuMuXY= - - hash2 - - L+jloOsEhvh+iNEOUPnzj+e80b5xsdZqhGRjlS1lnok= - - - Resources/XGAStatusPopover.nib - - hash - - IQYYUWsLytlz7v0DE5zAnAz3mvU= - - hash2 - - IFXbNJ6cFKQi72AQd3qovngswohuqhAm9852SRzdDrk= - - - Resources/XGAStatusViewController.nib - - hash - - 2a9uGOty1vbflvSedWuau0dt0SE= - - hash2 - - ZlW38XTQevle61GdQkOWTaw2yhuf7mYkoZF3gRhbAfY= - - - - rules - - ^Resources/ - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Resources/Base\.lproj/ - - weight - 1010 - - ^version.plist$ - - - rules2 - - .*\.dSYM($|/) - - weight - 11 - - ^(.*/)?\.DS_Store$ - - omit - - weight - 2000 - - ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/ - - nested - - weight - 10 - - ^.* - - ^Info\.plist$ - - omit - - weight - 20 - - ^PkgInfo$ - - omit - - weight - 20 - - ^Resources/ - - weight - 20 - - ^Resources/.*\.lproj/ - - optional - - weight - 1000 - - ^Resources/.*\.lproj/locversion.plist$ - - omit - - weight - 1100 - - ^Resources/Base\.lproj/ - - weight - 1010 - - ^[^/]+$ - - nested - - weight - 10 - - ^embedded\.provisionprofile$ - - weight - 20 - - ^version\.plist$ - - weight - 20 - - - - diff --git a/Products/XcodeGitHub.framework.zip b/Products/XcodeGitHub.framework.zip new file mode 100644 index 0000000..85d21c5 Binary files /dev/null and b/Products/XcodeGitHub.framework.zip differ diff --git a/Products/XcodeGitHub.framework/Headers b/Products/XcodeGitHub.framework/Headers deleted file mode 120000 index a177d2a..0000000 --- a/Products/XcodeGitHub.framework/Headers +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Headers \ No newline at end of file diff --git a/Products/XcodeGitHub.framework/Modules b/Products/XcodeGitHub.framework/Modules deleted file mode 120000 index 5736f31..0000000 --- a/Products/XcodeGitHub.framework/Modules +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/Modules \ No newline at end of file diff --git a/Products/XcodeGitHub.framework/Versions/A/Headers/APFormattedString.h b/Products/XcodeGitHub.framework/Versions/A/Headers/APFormattedString.h deleted file mode 100644 index 0af41cc..0000000 --- a/Products/XcodeGitHub.framework/Versions/A/Headers/APFormattedString.h +++ /dev/null @@ -1,45 +0,0 @@ -/** - @file APFormattedString.h - @package xcode-github - @brief A generalized formatted string that can render multiple formats. - - @author Edward Smith - @date April 2018 - @copyright Copyright © 2018 Branch. All rights reserved. -*/ - -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface APFormattedString : NSObject - -+ (instancetype) plainText:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2); -+ (instancetype) boldText:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2); -+ (instancetype) italicText:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2); -+ (instancetype) line; - -- (instancetype) plainText:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2); -- (instancetype) boldText:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2); -- (instancetype) italicText:(NSString*)format, ... NS_FORMAT_FUNCTION(1,2); -- (instancetype) line; - -- (instancetype) append:(APFormattedString*)string; - -- (NSString*) renderText; -- (NSString*) renderMarkDown; - -#if TARGET_OS_IOS -- (NSAttributedString*) renderAttributedStringWithFont:(UIFont*)font; -#elif TARGET_OS_OSX -- (NSAttributedString*) renderAttributedStringWithFont:(NSFont*)font; -#endif - -@end - -@interface NSString (APFormattedString) -- (NSRange) rangeOfAlphanumericSubstring; -@end - -NS_ASSUME_NONNULL_END diff --git a/Products/XcodeGitHub.framework/Versions/A/Headers/BNCLog.h b/Products/XcodeGitHub.framework/Versions/A/Headers/BNCLog.h deleted file mode 100644 index f9ce975..0000000 --- a/Products/XcodeGitHub.framework/Versions/A/Headers/BNCLog.h +++ /dev/null @@ -1,242 +0,0 @@ -/** - @file BNCLog.h - @package Branch-SDK - @brief Simple logging functions. - - @author Edward Smith - @date October 2016 - @copyright Copyright © 2016 Branch. All rights reserved. -*/ - -#import - -#ifdef __cplusplus -extern "C" { -#endif - - -///@functiongroup Branch Logging Functions - -#pragma mark Log Initialization - -/// Log facility initialization. Usually there is no need to call this directly. -FOUNDATION_EXPORT void BNCLogInitialize(void) __attribute__((constructor)); - -#pragma mark Log Message Severity - -/// Log message severity -typedef NS_ENUM(NSInteger, BNCLogLevel) { - BNCLogLevelAll = 0, - BNCLogLevelDebugSDK = BNCLogLevelAll, - BNCLogLevelBreakPoint, - BNCLogLevelDebug, - BNCLogLevelWarning, - BNCLogLevelError, - BNCLogLevelAssert, - BNCLogLevelLog, - BNCLogLevelNone, - BNCLogLevelMax -}; - -/*! -* @return Returns the current log severity display level. -*/ -FOUNDATION_EXPORT BNCLogLevel BNCLogDisplayLevel(void); - -/*! -* @param level Sets the current display level for log messages. -*/ -FOUNDATION_EXPORT void BNCLogSetDisplayLevel(BNCLogLevel level); - -/*! -* @param level The log level to convert to a string. -* @return Returns the string indicating the log level. -*/ -FOUNDATION_EXPORT NSString *_Nonnull BNCLogStringFromLogLevel(BNCLogLevel level); - -/*! -* @param string A string indicating the log level. -* @return Returns The log level corresponding to the string. -*/ -FOUNDATION_EXPORT BNCLogLevel BNCLogLevelFromString(NSString*_Null_unspecified string); - - -#pragma mark - Programmatic Breakpoints - - -///@return Returns 'YES' if programmatic breakpoints are enabled. -FOUNDATION_EXPORT BOOL BNCLogBreakPointsAreEnabled(void); - -///@param enabled Sets programmatic breakpoints enabled or disabled. -FOUNDATION_EXPORT void BNCLogSetBreakPointsEnabled(BOOL enabled); - - -#pragma mark - Client Initialization Function - - -typedef void (*BNCLogClientInitializeFunctionPtr)(void); - -///@param clientInitializationFunction The client function that should be called before logging starts. -FOUNDATION_EXPORT BNCLogClientInitializeFunctionPtr _Null_unspecified - BNCLogSetClientInitializeFunction(BNCLogClientInitializeFunctionPtr _Nullable clientInitializationFunction); - - -#pragma mark - Optional Log Output Handlers - - -///@brief Pre-defined log message handlers -- - -typedef void (*BNCLogOutputFunctionPtr)(NSDate*_Nonnull timestamp, BNCLogLevel level, NSString*_Nullable message); - -FOUNDATION_EXPORT void BNCLogFunctionOutputToStdOut(NSDate*_Nonnull timestamp, BNCLogLevel level, NSString *_Nullable message); -FOUNDATION_EXPORT void BNCLogFunctionOutputToStdErr(NSDate*_Nonnull timestamp, BNCLogLevel level, NSString *_Nullable message); - -///@param functionPtr A pointer to the logging function. Setting the parameter to NULL will flush -/// and close the currently set log function and future log messages will be -/// ignored until a non-NULL logging function is set. -FOUNDATION_EXPORT void BNCLogSetOutputFunction(BNCLogOutputFunctionPtr _Nullable functionPtr); - -///@return Returns the current logging function. -FOUNDATION_EXPORT BNCLogOutputFunctionPtr _Nullable BNCLogOutputFunction(void); - -/// If a predefined log handler is being used, the function closes the output file. -FOUNDATION_EXPORT void BNCLogCloseLogFile(void); - -///@param URL Sets the log output function to a function that writes messages to the file at URL. -FOUNDATION_EXPORT void BNCLogSetOutputToURL(NSURL *_Nullable URL); - -///@param URL Sets the log output function to a function that writes messages to the file at URL. -///@param maxRecords Wraps the file at `maxRecords` records. -FOUNDATION_EXPORT void BNCLogSetOutputToURLRecordWrap(NSURL *_Nullable URL, long maxRecords); - -///@param URL Sets the log output function to a function that writes messages to the file at URL. -///@param maxBytes Wraps the file at `maxBytes` bytes. Must be an even number of bytes. -FOUNDATION_EXPORT void BNCLogSetOutputToURLByteWrap(NSURL *_Nullable URL, long maxBytes); - -typedef void (*BNCLogFlushFunctionPtr)(void); - -///@param flushFunction The logging functions use `flushFunction` to flush the outstanding log -/// messages to the output function. For instance, this function may call -/// `fsync` to assure that the log messages are written to disk. -FOUNDATION_EXPORT void BNCLogSetFlushFunction(BNCLogFlushFunctionPtr _Nullable flushFunction); - -///@return Returns the current flush function. -FOUNDATION_EXPORT BNCLogFlushFunctionPtr _Nullable BNCLogFlushFunction(void); - - -#pragma mark - BNCLogWriteMessage - - -/// The main logging function used in the variadic logging defines. -FOUNDATION_EXPORT void BNCLogWriteMessageFormat( - BNCLogLevel logLevel, - const char *_Nullable sourceFileName, - int32_t sourceLineNumber, - NSString* _Nullable messageFormat, - ... -) NS_FORMAT_FUNCTION(4,5); - -/// Swift-friendly wrapper for BNCLogWriteMessageFormat -FOUNDATION_EXPORT void BNCLogWriteMessage( - BNCLogLevel logLevel, - NSString *_Nonnull sourceFileName, - int32_t sourceLineNumber, - NSString *_Nonnull message -); - -/// This function synchronizes all outstanding log messages and writes them to the logging function -/// set by BNCLogSetOutputFunction. -FOUNDATION_EXPORT void BNCLogFlushMessages(void); - -///@return Returns true if the app is currently attached to a debugger. -FOUNDATION_EXPORT BOOL BNCLogDebuggerIsAttached(void); - -#pragma mark - Logging -///@info Logging - -///@param format Log an info message with the specified formatting. -#define BNCLogDebugSDK(...) \ - do { BNCLogWriteMessageFormat(BNCLogLevelDebugSDK, __FILE__, __LINE__, __VA_ARGS__); } while (0) - -///@param format Log a debug message with the specified formatting. -#define BNCLogDebug(...) \ - do { BNCLogWriteMessageFormat(BNCLogLevelDebug, __FILE__, __LINE__, __VA_ARGS__); } while (0) - -///@param format Log a warning message with the specified formatting. -#define BNCLogWarning(...) \ - do { BNCLogWriteMessageFormat(BNCLogLevelWarning, __FILE__, __LINE__, __VA_ARGS__); } while (0) - -///@param format Log an error message with the specified formatting. -#define BNCLogError(...) \ - do { BNCLogWriteMessageFormat(BNCLogLevelError, __FILE__, __LINE__, __VA_ARGS__); } while (0) - -///@param format Log a message with the specified formatting. -#define BNCLog(...) \ - do { BNCLogWriteMessageFormat(BNCLogLevelLog, __FILE__, __LINE__, __VA_ARGS__); } while (0) - -///Cause a programmatic breakpoint if breakpoints are enabled. -#define BNCLogBreakPoint() \ - do { \ - if (BNCLogBreakPointsAreEnabled()) { \ - BNCLogWriteMessageFormat(BNCLogLevelBreakPoint, __FILE__, __LINE__, @"Programmatic breakpoint."); \ - if (BNCDebuggerIsAttached()) { \ - BNCLogFlushMessages(); \ - BNCDebugBreakpoint(); \ - } \ - } \ - } while (0) - -///Log a message and cause a programmatic breakpoint if breakpoints are enabled. -#define BNCBreakPointWithMessage(...) \ - do { \ - if (BNCLogBreakPointsAreEnabled() { \ - BNCLogWriteMessageFormat(BNCLogLevelBreakPoint, __FILE__, __LINE__, __VA_ARGS__); \ - if (BNCDebuggerIsAttached()) { \ - BNCLogFlushMessages(); \ - BNCDebugBreakpoint(); \ - } \ - } \ - } while (0) - -///Check if an asserting is true. If programmatic breakpoints are enabled then break. -#define BNCLogAssert(condition) \ - do { \ - if (!(condition)) { \ - BNCLogWriteMessageFormat(BNCLogLevelAssert, __FILE__, __LINE__, @"(%s) !!!", #condition); \ - if (BNCLogBreakPointsAreEnabled() && BNCDebuggerIsAttached()) { \ - BNCLogFlushMessages(); \ - BNCDebugBreakpoint(); \ - } \ - } \ - } while (0) - -///Check if an asserting is true logging a message if the assertion fails. -///If programmatic breakpoints are enabled then break. -#define BNCLogAssertWithMessage(condition, message, ...) \ - do { \ - if (!(condition)) { \ - NSString *m = [NSString stringWithFormat:message, __VA_ARGS__]; \ - BNCLogWriteMessageFormat(BNCLogLevelAssert, __FILE__, __LINE__, @"(%s) !!! %@", #condition, m); \ - if (BNCLogBreakPointsAreEnabled() && BNCDebuggerIsAttached()) { \ - BNCLogFlushMessages(); \ - BNCDebugBreakpoint(); \ - } \ - } \ - } while (0) - -///Assert that the current thread is the main thread. -#define BNCLogAssertIsMainThread() \ - BNCLogAssert([NSThread isMainThread]) - -///Write the name of the current method to the log. -#define BNCLogMethodName() \ - BNCLogDebug(@"Method '%@'.", NSStringFromSelector(_cmd)) - -///Write the name of the current function to the log. -#define BNCLogFunctionName() \ - BNCLogDebug(@"Function '%s'.", __FUNCTION__) - - -#ifdef __cplusplus -} -#endif diff --git a/Products/XcodeGitHub.framework/Versions/A/Headers/BNCNetworkService.h b/Products/XcodeGitHub.framework/Versions/A/Headers/BNCNetworkService.h deleted file mode 100644 index 8534a6a..0000000 --- a/Products/XcodeGitHub.framework/Versions/A/Headers/BNCNetworkService.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - @file BNCNetworkService.h - @package Branch-SDK - @brief Basic Networking Services - - @author Edward Smith - @date April 2017 - @copyright Copyright © 2017 Branch. All rights reserved. -*/ - -#import - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark BNCNetworkOperation - -@interface BNCNetworkOperation : NSObject -@property (readonly) NSURLSessionTaskState sessionState; -@property (readonly) NSMutableURLRequest*_Nullable request; -@property (readonly) NSInteger HTTPStatusCode; -@property (readonly) NSError*_Nullable error; -@property (readonly) NSDate*_Nullable dateStart; -@property (readonly) NSDate*_Nullable dateFinish; -@property (readonly) id responseData; - -- (void) start; -- (void) cancel; - -- (void) deserializeJSONResponseData; -- (NSString*_Nullable) stringFromResponseData; -- (void) setUser:(NSString*)user password:(NSString*)password; -@end - -#pragma mark - BNCNetworkService - -@interface BNCNetworkService : NSObject -+ (BNCNetworkService*) shared; - -- (BNCNetworkOperation*) getOperationWithURL:(NSURL *)URL - completion:(void (^)(BNCNetworkOperation*operation))completion; - -- (BNCNetworkOperation*) postOperationWithURL:(NSURL *)URL - contentType:(NSString*)contentType - data:(NSData *)data - completion:(void (^)(BNCNetworkOperation*operation))completion; - -- (BNCNetworkOperation*) postOperationWithURL:(NSURL *)URL - JSONData:(id)dictionaryOrArray - completion:(void (^)(BNCNetworkOperation*operation))completion; - -- (NSError*_Nullable) pinSessionToPublicSecKeyRefs:(NSArray/***/*)publicKeys; - -/// An array of host domains that we will allow with a self-signed SSL cert. -@property (strong) NSMutableSet*_Nullable anySSLCertHosts; - -/// Allow self-signed certs from any host. Trumps `anySSLCertHosts`. -@property (assign) BOOL allowAnySSLCert; -@end - -NS_ASSUME_NONNULL_END diff --git a/Products/XcodeGitHub.framework/Versions/A/Headers/XGCommand.h b/Products/XcodeGitHub.framework/Versions/A/Headers/XGCommand.h deleted file mode 100644 index d200dd1..0000000 --- a/Products/XcodeGitHub.framework/Versions/A/Headers/XGCommand.h +++ /dev/null @@ -1,32 +0,0 @@ -/** - @file XGCommand.h - @package xcode-github - @brief Main body of the xcode-github app. - - @author Edward Smith - @date April 24, 2018 - @copyright Copyright © 2018 Branch. All rights reserved. -*/ - -#import -#import "XGCommandOptions.h" - -NS_ASSUME_NONNULL_BEGIN - -/** - Creates or updates an Xcode bot when a new GitHub pull request is created on a GitHub project. - - @param options The options for the new bot. The options specify the Xcode server, and the template bot. - @return Returns an error if one occurs else nil. -*/ -FOUNDATION_EXPORT NSError*_Nullable XGUpdateXcodeBotsWithGitHub(XGCommandOptions* options); - -/** - Writes the current Xcode server status to the output device. - - @param options The command options with the Xcode server, user, and pass of which to show the status. - @return Returns an NSError if an error occurs or nil on success. -*/ -FOUNDATION_EXPORT NSError*_Nullable XGShowXcodeBotStatus(XGCommandOptions* options); - -NS_ASSUME_NONNULL_END diff --git a/Products/XcodeGitHub.framework/Versions/A/Headers/XGCommandOptions.h b/Products/XcodeGitHub.framework/Versions/A/Headers/XGCommandOptions.h deleted file mode 100644 index 5e047d2..0000000 --- a/Products/XcodeGitHub.framework/Versions/A/Headers/XGCommandOptions.h +++ /dev/null @@ -1,33 +0,0 @@ -/** - @file XGCommandOptions.h - @package xcode-github - @brief Command options for the xcode-github app. - - @author Edward Smith - @date March 7, 2018 - @copyright Copyright © 2018 Branch. All rights reserved. -*/ - -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface XGCommandOptions : NSObject -@property (copy) NSString*_Nullable xcodeServerName; -@property (copy) NSString*_Nullable xcodeServerUser; // Optional -@property (copy) NSString*_Nullable xcodeServerPassword; // Optional -@property (copy) NSString*_Nullable templateBotName; -@property (copy) NSString*_Nullable githubAuthToken; -@property (assign) int verbosity; -@property (assign) BOOL dryRun; -@property (assign) BOOL showStatusOnly; -@property (assign) BOOL showVersion; -@property (assign) BOOL showHelp; -@property (assign) BOOL badOptionsError; -@property (assign) BOOL repeatForever; - -- (instancetype _Nonnull) initWithArgc:(int)argc argv:(char*const _Nullable[_Nullable])argv; -+ (NSString*) helpString; -@end - -NS_ASSUME_NONNULL_END diff --git a/Products/XcodeGitHub.framework/Versions/A/Headers/XGGitHubPullRequest.h b/Products/XcodeGitHub.framework/Versions/A/Headers/XGGitHubPullRequest.h deleted file mode 100644 index ba51b9e..0000000 --- a/Products/XcodeGitHub.framework/Versions/A/Headers/XGGitHubPullRequest.h +++ /dev/null @@ -1,68 +0,0 @@ -/** - @file XGGitHubPullRequest.h - @package xcode-github - @brief A class for working with GitHub PR statuses. - - @author Edward Smith - @date February 28, 2018 - @copyright Copyright © 2018 Branch. All rights reserved. -*/ - -#import - -NS_ASSUME_NONNULL_BEGIN - -typedef NS_ENUM(NSInteger, XGPullRequestStatus) { - XGPullRequestStatusError = 0, - XGPullRequestStatusFailure, - XGPullRequestStatusPending, - XGPullRequestStatusSuccess, - }; - -FOUNDATION_EXPORT NSString*_Nonnull NSStringFromXGPullRequestStatus(XGPullRequestStatus status); - -#pragma mark - XGGitHubPullRequestStatus - -@interface XGGitHubPullRequestStatus : NSObject -- (instancetype) init NS_UNAVAILABLE; -+ (instancetype) new NS_UNAVAILABLE; -@property (assign, readonly) XGPullRequestStatus status; -@property (strong, readonly) NSString*_Nullable message; -@property (strong, readonly) NSDate*_Nullable updateDate; -@end - -#pragma mark - XGGitHubPullRequest - -@interface XGGitHubPullRequest : NSObject -@property (strong, readonly) NSString*_Nullable repoOwner; -@property (strong, readonly) NSString*_Nullable repoName; -@property (strong, readonly) NSString*_Nullable branch; -@property (strong, readonly) NSString*_Nullable number; -@property (strong, readonly) NSString*_Nullable title; -@property (strong, readonly) NSString*_Nullable body; -@property (strong, readonly) NSString*_Nullable state; -@property (strong, readonly) NSDictionary*_Nullable dictionary; -@property (strong, readonly) NSString*_Nullable sha; -@property (strong, readonly) NSString*_Nullable githubPRURL; - -+ (instancetype _Nonnull) new NS_UNAVAILABLE; -- (instancetype _Nonnull) init NS_UNAVAILABLE; - -- (instancetype _Nonnull) initWithDictionary:(NSDictionary*_Nullable)dictionary NS_DESIGNATED_INITIALIZER; - -- (NSArray*_Nullable) statusesWithError:(NSError*_Nullable __autoreleasing *_Nullable)error; - -- (NSError*_Nullable) setStatus:(XGPullRequestStatus)status - message:(NSString*)message - statusURL:(NSURL*_Nullable)statusURL; - -- (NSError*_Nullable) addComment:(NSString*)comment; - -+ (NSDictionary*_Nullable) - pullsRequestsForRepository:(NSString*_Nonnull)sourceControlRepository - authToken:(NSString*_Nonnull)authToken - error:(NSError*_Nullable __autoreleasing *_Nullable)error; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Products/XcodeGitHub.framework/Versions/A/Headers/XGXcodeBot.h b/Products/XcodeGitHub.framework/Versions/A/Headers/XGXcodeBot.h deleted file mode 100644 index c15ac2d..0000000 --- a/Products/XcodeGitHub.framework/Versions/A/Headers/XGXcodeBot.h +++ /dev/null @@ -1,147 +0,0 @@ -/** - @file XGXcodeBot.h - @package xcode-github - @brief A class for working with Xcode bot statuses. - - @author Edward Smith - @date February 28, 2018 - @copyright Copyright © 2018 Branch. All rights reserved. -*/ - -#import -#import "APFormattedString.h" - -NS_ASSUME_NONNULL_BEGIN - -#pragma mark XGServer - -@interface XGServer : NSObject -@property (copy) NSString*server; -@property (copy) NSString*user; -@property (copy) NSString*password; -@end - -#pragma mark - XGXcodeBotStatus - -@interface XGXcodeBotStatus : NSObject -@property (strong, readonly) NSString*_Nullable botID; -@property (strong, readonly) NSString*_Nullable botTinyID; -@property (strong, readonly) NSString*_Nullable botName; -@property (strong, readonly) NSString*_Nullable serverName; -@property (strong, readonly) NSString*_Nullable integrationID; -@property (strong, readonly) NSNumber*_Nullable integrationNumber; -/** - currentStep possible values: - "pending" - "preparing" - "checkout" - "before-triggers" - "building" - "testing" - "archiving" - "processing" - "after-triggers" - "uploading" - "completed" -*/ -@property (strong, readonly) NSString*_Nullable currentStep; -/** - result possible values: - "unknown" - "succeeded" - "build-errors" - "test-failures" - "warnings" - "analyzer-warnings" - "build-failed" - "checkout-error" - "internal-error" - "internal-checkout-error" - "internal-build-error" - "internal-processing-error" - "canceled" - "trigger-error" -*/ -@property (strong, readonly) NSString*_Nullable result; -@property (strong, readonly) NSDictionary*_Nullable dictionary; -@property (strong, readonly) NSError*_Nullable error; - -@property (strong, readonly) NSDate*_Nullable queuedDate; -@property (strong, readonly) NSDate*_Nullable startedDate; -@property (strong, readonly) NSDate*_Nullable endedDate; - -@property (strong, readonly) NSNumber*_Nullable errorCount; -@property (strong, readonly) NSNumber*_Nullable warningCount; -@property (strong, readonly) NSNumber*_Nullable analyzerWarningCount; -@property (strong, readonly) NSNumber*_Nullable testsCount; -@property (strong, readonly) NSNumber*_Nullable testFailureCount; -@property (strong, readonly) NSNumber*_Nullable codeCoveragePercentage; - -@property (strong, readonly) NSArray*_Nullable tags; - -@property (strong, readonly) NSString* summaryString; -@property (strong, readonly) APFormattedString* formattedDetailString; - -@property (strong, readonly) NSURL* integrationLogURL; - -- (instancetype) initWithServerName:(NSString*_Nullable)serverName - dictionary:(NSDictionary*_Nullable)dictionary - NS_DESIGNATED_INITIALIZER; - -+ (instancetype) new NS_UNAVAILABLE; -- (instancetype) init NS_UNAVAILABLE; -@end - -#pragma mark - XGXcodeBot - -@interface XGXcodeBot : NSObject - -/// @brief Bot Information - -@property (strong, readonly) NSString*_Nullable name; -@property (strong, readonly) NSString*_Nullable botID; -@property (strong, readonly) NSString*_Nonnull serverName; - -/// @brief Repo Information - -@property (strong, readonly) NSString*_Nonnull repoOwner; -@property (strong, readonly) NSString*_Nonnull repoName; -@property (strong, readonly) NSString*_Nonnull branch; -@property (strong, readonly) NSString*_Nullable sourceControlRepository; -@property (strong, readonly) NSString*_Nonnull sourceControlWorkspaceBlueprintLocationsID; - -/// @brief Pull Request Information - -@property (strong, readonly) NSString*_Nullable pullRequestNumber; -@property (strong, readonly) NSString*_Nullable pullRequestTitle; -@property (strong, readonly) NSString*_Nullable templateBotName; -@property (assign, readonly) BOOL botIsFromTemplateBot; - -/// The raw bot dictionary. -@property (strong, readonly) NSDictionary*_Nullable dictionary; - -+ (instancetype) new NS_UNAVAILABLE; -- (instancetype) init NS_UNAVAILABLE; - -/** - @param xcodeServer The network name of the Xcode server. - @param error If not nil, on exit, any error encountered is returned here. - @return A dictionary with a key of the bot name and value of the bot status. -*/ -+ (NSDictionary*_Nullable) botsForServer:(XGServer*)xcodeServer - error:(NSError*__autoreleasing _Nullable*_Nullable)error; - -+ (NSString*_Nonnull) botNameFromPRNumber:(NSString*_Nonnull)number title:(NSString*_Nonnull)title; - -- (XGXcodeBot*_Nullable) duplicateBotWithNewName:(NSString*_Nonnull)newBotName - branchName:(NSString*_Nonnull)branchName - gitHubPullRequestNumber:(NSString*_Nonnull)pullRequestNumber - gitHubPullRequestTitle:(NSString*_Nonnull)pullRequestTitle - error:(NSError*__autoreleasing _Nullable*_Nullable)error; - -- (NSError*_Nullable) startIntegration; -- (XGXcodeBotStatus*_Nonnull) status; -- (NSError*_Nullable) deleteBot; -@end - -NS_ASSUME_NONNULL_END diff --git a/Products/XcodeGitHub.framework/Versions/A/Headers/XcodeGitHub.h b/Products/XcodeGitHub.framework/Versions/A/Headers/XcodeGitHub.h deleted file mode 100644 index ac5d062..0000000 --- a/Products/XcodeGitHub.framework/Versions/A/Headers/XcodeGitHub.h +++ /dev/null @@ -1,20 +0,0 @@ -/** - @file XcodeGitHub.h - @package xcode-github - @brief XcodeGitHub umbrella header file. - - @author Edward Smith - @date October 7, 2018 - @copyright Copyright © 2018 Branch. All rights reserved. -*/ - -#import -#import "APFormattedString.h" -#import "BNCLog.h" -#import "BNCNetworkService.h" -#import "XGCommand.h" -#import "XGCommandOptions.h" -#import "XGGitHubPullRequest.h" -#import "XGXcodeBot.h" - -FOUNDATION_EXPORT NSString*_Nonnull XGVersion(void); diff --git a/Products/XcodeGitHub.framework/Versions/A/Modules/module.modulemap b/Products/XcodeGitHub.framework/Versions/A/Modules/module.modulemap deleted file mode 100644 index b6de7db..0000000 --- a/Products/XcodeGitHub.framework/Versions/A/Modules/module.modulemap +++ /dev/null @@ -1,5 +0,0 @@ -framework module XcodeGitHub { - umbrella header "XcodeGitHub.h" - export * - module * { export * } -} diff --git a/Products/XcodeGitHub.framework/Versions/A/XcodeGitHub b/Products/XcodeGitHub.framework/Versions/A/XcodeGitHub deleted file mode 100644 index d58d4b6..0000000 Binary files a/Products/XcodeGitHub.framework/Versions/A/XcodeGitHub and /dev/null differ diff --git a/Products/XcodeGitHub.framework/Versions/Current b/Products/XcodeGitHub.framework/Versions/Current deleted file mode 120000 index 8c7e5a6..0000000 --- a/Products/XcodeGitHub.framework/Versions/Current +++ /dev/null @@ -1 +0,0 @@ -A \ No newline at end of file diff --git a/Products/XcodeGitHub.framework/XcodeGitHub b/Products/XcodeGitHub.framework/XcodeGitHub deleted file mode 120000 index 1b6be8d..0000000 --- a/Products/XcodeGitHub.framework/XcodeGitHub +++ /dev/null @@ -1 +0,0 @@ -Versions/Current/XcodeGitHub \ No newline at end of file diff --git a/Products/xcode-github b/Products/xcode-github index 6cf19be..0d76cb1 100755 Binary files a/Products/xcode-github and b/Products/xcode-github differ diff --git a/Products/xcode-github.dSYM.zip b/Products/xcode-github.dSYM.zip new file mode 100644 index 0000000..5cd0a83 Binary files /dev/null and b/Products/xcode-github.dSYM.zip differ diff --git a/README.md b/README.md index 59952d3..7245dd8 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,222 @@ +![](https://img.shields.io/badge/macOS-10.12+-brightgreen.svg) +![](https://img.shields.io/badge/Xcode-9.0+-darkgreen.svg) +[![MIT licensed](https://img.shields.io/badge/license-MIT-orange.svg)](https://raw.githubusercontent.com/hyperium/hyper/master/LICENSE) +![](https://img.shields.io/github/release/E-B-Smith/xcode-github/all.svg) + + # xcode-github -GitHub has a great git hosting service. +

+Xcode-GitHub App Icon +

+ +### Automate your Xcode test and build process with the XcodeGitHub app + +Quickly automate your test and build process with XcodeGitHub, a macOS app that monitors your GitHub repos for new pull requests and creates Xcode bots that test them. + +![Status Window](Art/StatusWindow.png) + +### Features + +* Runs on your own build computer so you can easily do on-device testing with your own phones or Macs. +* Runs inside your network without any firewall changes. +* Easy to configure and run. + +### What's Included + +* A light weight macOS app with a clean UI that monitors your GitHub repos and creates Xcode test bots for them. +* An optional command line tool that has most of the same functions of the macOS app. +* A static library that has interfaces for working with GitHub repositories and Xcode test bot system. + +### Requirements + +* Xcode 9 and above to run the bots. +* macOS 10.12 and above to run Xcode. + +## Contents + +* [Getting Started](#getting-started) + - [Installation](#installation) + - [Monitoring Your First Repo](#monitoring-your-first-repo) + - [The Command Line Tool](#the-command-line-tool) +* [Trouble Shooting & Support](#trouble-shooting--support) + - [Diagnosing Problems](#diagnosing-problems) + - [Reporting Issues & Feature Requests](#reporting-issues--feature-requests) +* [Project Goals](#project-goals) + - [Goal 1: Write a useful test automation tool](#goal-1-write-a-useful-test-automation-tool) + - [Goal 2: Write a new macOS app](#goal-2-write-a-new-macos-app) + - [Goal 3: Experiment with using XCTest for macOS / iOS libraries](#goal-3-experiment-with-using-xctest-for-macos--ios-libraries +) + +## Getting Started + +### Installation + +##### The Easy Installation + +Download this file: [`Products/XcodeGitHub.app.zip`](Products/XcodeGitHub.app.zip) from the project, unzip it, and move it to your Applications directory. Done. The app is code signed, but you'll have to approve the app in the system dialog that pops up the first time you run the app. + +##### The Slightly Harder Installation + +Clone this repo, open the `xcode-github-app.xcodeproj` project file in Xcode, and select *Product > Build* to build the project. After the project finishes compiling the app can be found in the Xcode project tree under the 'Products' folder. Right click to show the app in the Finder and move the app to your Applications directory. + +### Monitoring Your First Repo + +XcodeGitHub works by using an existing Xcode test bot you've already set up as a template for the new bots it creates for the pull requests on your GitHub repo. + +You'll have to set up a build/test computer with Xcode, enable Xcode server, and then create a template test bot to get started. + +#### 1. Set Up an Xcode Bot Server + +Here are some guides for setting Xcode server and configuring bots: + +[Xcode Help: Continuous Integration Overview](https://help.apple.com/xcode/mac/10.1/index.html?localePath=en.lproj#/dev466720061) +
+[How to use Xcode server in Xcode 9](https://medium.com/bobo-shone/how-to-use-xcode-server-in-xcode-9-93d6d2ee128f) + +#### 2. Create a Template Test Bot in Xcode + +I usually create my template test bot on the `staging` or `master` branch of my repo and configure the bot exactly as I want the PRs to be tested. + +[Xcode Help: Create a bot](https://help.apple.com/xcode/mac/10.1/index.html?localePath=en.lproj#/devc4a08a3ef) + +#### 3. Create a GitHub Access Token + +Xcode-GitHub updates the status of the PR at GitHub with the result of the tests. + +For the Xcode-GitHub to update the status, create an access token on the GitHub web site by navigating to your *Setting > Developer Settings > Personal Access Tokens* and creating a token with **repo** access. + +*Pro tip:* I created a special GitHub account just for my test bots to limit any security exposure. + +[GitHub: Personal access tokens](https://github.com/settings/tokens) + +#### 4. Run Xcode-GitHub + +The first time you run Xcode-GitHub it will prompt you to add an Xcode server to monitor. + +Also enter the user name and password to access the Xcode server. The user name and password are stored securely in the Mac keychain. + +You can leave these fields blank if a user name and password aren't required to access your Xcode server. + +![Add Server](Art/AddServer.png) + +Next, add your GitHub access token in the Preferences window. + +Again, the GitHub access token is stored securely in the Mac keychain. + +![Add Token](Art/AddToken.png) -Xcode has a great continuous integration service. +Finally, in the status window you'll see the test bot you set up previously. Select the bot, right click on it, and select 'Monitor Repo'. -But Xcode can't monitor your GitHub repo for new pull requests and create new integration bots -for testing. +![Monitor Repo](Art/MonitorRepo.png) -xcode-github is the Reeses(tm) that puts two great things, Xcode and GitHub, together so that you -can have great Xcode testing on new GitHub pull requests. +New test bots will be created for your PRs: -Finally! +![Monitoring Repos](Art/Monitoring.png) -## What's Included +That's it! -* A macOS app that monitors your GitHub repos for PRs and creates new Xcode bots for them. -* A command line utility that has many of the same functions of the macOS app. -* A static library that has interfaces for GitHub and the Xcode CI system. -* An xctest test bundle for testing. +Keep the Xcode-GitHub app running so that it can continue monitoring your repos. + +### The Command Line Tool + +There's also an optional command line tool included that has most of the same functionality as the macOS app. It that can be handy for scripted builds. + +The tool is built with the `xcode-github-cli.xcodeproj` project. For your convenience the pre-compiled tool downloaded from [`Products/xcode-github.`](Products/xcode-github) + +``` +xcode-github - Creates Xcode test bots for new GitHub PRs. + +usage: xcode-github [-dhsVv] -g + -t -x + + + -d, --dryrun + Dry run. Print what would be done. + + -g, --github + A GitHub auth token that allows checking the status of a repo + and change a PR's status. + + -h, --help + Print this help information. + + -p, --password + Password for the Xcode server. + + -r, --repeat + Repeat updating the status forever, waiting 60 seconds between updates. + + -s, --status + Only print the status of the Xcode server bots and quit. + + -t --template + An existing bot on the Xcode server that is used as a template + for the new GitHub PR bots. + + -u, --user + User for the Xcode server. + + -V, --version + Show version and exit. + + -v, --verbose + Verbose. Extra 'v' increases the verbosity. + + -x, --xcodeserver + The network name of the Xcode server. + +The tool returns 0 on success, otherwise a non-zero value. +``` + +## Trouble Shooting & Support + +### Diagnosing Problems + +If you're having problems the first diagnostic step is to open the log window (under the 'Window' menu) and look for any issues there. Toggling 'Show debug messages' on the lower right will show more verbose logging. + +### Reporting Issues & Feature Requests + +Report issues and make suggestions [here, at the issue section of this repository on GitHub.](https://github.com/E-B-Smith/xcode-github/issues) ## Project Goals -The project goals +I had several goals for the project when I started. First, I needed an automated way to build and test software on a local computer with specific test devices attached. I couldn't find anything that fit my needs, so I this seemed like a good opportunity to explore some other things I'd been thinking about, such as writing a new macOS app to see how the landscape has changed during the years I had been concentrating on iOS development. Finally I wanted to try some different ways of testing libraries with the Xcode XCTest environment. + +### Goal 1: Write a useful test automation tool + +While working at Branch Metrics I needed a way to automate the build and test process for our SDKs and other projects. Because of the nature of our SDK it had to be tested on real devices since the simulators just don't have all the features and quirks of an actual device. + +For a while I used [Buildasaur](https://github.com/buildasaurs/Buildasaur) for automating tests and builds, a great app that just chugged along until Xcode 9, when the two became incompatible. I considered updating Buildasaur, but it was written in Swift 2.3 and I just didn't want to spend the effort converting the code to Swift 4 and then updating all the Xcode server parts. + +It was much easier to start over and write a light weight app in Objective-C which is more stable than Swift, is pretty fast to write, and has the option create static and dynamic libraries. + +As a shout out to Buildasaur I used much of the charming messaging it used for the PR statuses that are shown in GitHub. + +### Goal 2: Write a new macOS app + +I've been writing iOS code almost exclusively for a number of years and I wanted to see how macOS has been evolving. + +The first thing that stood out is that AppKit, the Mac UI library, hasn't been getting the same amount of love as iOS has and feels neglected. + +There's a lot of old NextStep ways of doing things in AppKit, and I mean really old, and it shows. This isn't going away any time soon because it'll break too much stuff, but it could be handled better. + +For instance, user interface cells made a lot of sense in the 90s when memory and computing power where absolutely constrained compared to today. But now their purpose isn't clear and they get in the way. + +Some things have been updated, like `NSTableView`, which can now be view-based or cell-based. + +On the other hand I really appreciated again how feature rich macOS and the development environment is. Native apps are kind of on their way out which is kind of too bad, since native apps have the potential to be very powerful and expressive, and the developement environment is generally pretty good. + +### Goal 3: Experiment with using XCTest for macOS / iOS libraries + +At Branch we distribute iOS, tvOS, and macOS SDK libraries that are widely used and have to be tested and correct. Further, many developers want to run the Branch SDK tests as part of their testing. + +I wanted to figure out how to modularize XCTest bundles so that they could be included in other project's test suites. + +What I envisioned was creating XCTest bundles that could be shipped with a library and included in the main project test suite. They could be dropped in and would automatically run. + +I never figured out a great way to do this. -## Installation and Usage +I tried different combinations of complicated build configurations using xcconfig files that set the `TEST_HOST` and other flags. But the solutions were fragile and required un-intuitive set up. Worse, the working solutions I found increasing got further from the original goal of simple drag-and-drop testing. +I'd love to hear other people's thoughts on this. Ultimately Xcode testing is just not built to do this, so any solution is simply fighting Xcode. diff --git a/build-release b/Tools/build-release similarity index 62% rename from build-release rename to Tools/build-release index 8daf0fc..de42606 100755 --- a/build-release +++ b/Tools/build-release @@ -1,9 +1,12 @@ #!/bin/bash set -euo pipefail -marketing_version=1.0.3 +marketing_version=1.1.2 build_version=1 +textBold="\e[1m\e[34m" # Dark Blue +textNormal="\e[0m" + function full_path_of_directory() { local directory_name directory_name="$1" @@ -42,23 +45,45 @@ mkdir -p "$build_products_directory" function build_project() { local project="$1" + local executable="$2" + printf "${textBold}>>> Building '$project'...${textNormal}\n" 1>&2 update_version "$project" xcodebuild \ -project "${project}".xcodeproj \ -scheme "${project}" \ + -configuration Release \ -quiet clean build \ CONFIGURATION_BUILD_DIR="$build_products_directory" + # Show the codesigning: + codesign -dv --verbose=4 "$build_products_directory"/"$executable" + echo "" +} + +function compress_product() { + local product="$build_products_directory"/"$1" + ditto -c -k --sequesterRsrc --keepParent "$product" "$product".zip + rm -rf "$product" } -build_project XcodeGitHub -build_project xcode-github-cli -build_project xcode-github-app +build_project XcodeGitHub XcodeGitHub.framework/Versions/A/XcodeGitHub +build_project xcode-github-cli xcode-github +build_project xcode-github-app XcodeGitHub.app + +compress_product xcode-github.dSYM +compress_product XcodeGitHub.app +compress_product XcodeGitHub.app.dSYM +compress_product XcodeGitHub.framework rm -Rf "$build_products_directory"/libXcodeGitHub.a rm -Rf "$build_products_directory"/usr -echo ">>> Build ${marketing_version}(${build_version}) products in 'Products':" -ls -al Products +printf "${textBold}>>> Build ${marketing_version}(${build_version}) products in 'Products':${textNormal}\n" +ls -al "$build_products_directory" + +if ! askYN "Release version ${marketing_version}?" +then + exit 1 +fi git add --all git commit --allow-empty -m "Release ${marketing_version}." diff --git a/Tools/xcode-coverage-report b/Tools/xcode-coverage-report new file mode 100755 index 0000000..ea398d1 --- /dev/null +++ b/Tools/xcode-coverage-report @@ -0,0 +1,50 @@ +#!/bin/bash +function printHelp() { +cat < ] + +Reads Xcode coverage data and outputs it in a format suitable for phabit ingestion. +HELP +} + +build_dir="" +while (( $# > 0 )) +do + if [[ $1 == -h ]] + then + printHelp + exit 0 + fi + if (( ${#build_dir} != 0 )) + then + echo ">>> Error: Build directory already set: '$build_dir'. Scanning '$1'." 1>&2 + exit 1 + fi + build_dir="$1" + shift +done + +if (( ${#build_dir} == 0 )) +then + if [ -e "./Build" ] + then + build_dir="./Build" + else + build_dir=".build" + fi +fi + +test_run=$(echo ./Build/Logs/Test/**/**/*.xccovarchive) +if (( $(echo "$test_run" | wc -l) != 1 )) +then + echo ">>> Error: can't find xccovarchive file: '$test_run'." 1>&2 + exit 1 +fi + +while IFS= read -r file +do + echo "File: \"$file\"" + xcrun xccov view \ + --file "$file" \ + "$test_run" +done < <(xcrun xccov view --file-list "$test_run") diff --git a/Vendor/Branch/BNCLog.h b/Vendor/Branch/BNCLog.h index f9ce975..799fccf 100644 --- a/Vendor/Branch/BNCLog.h +++ b/Vendor/Branch/BNCLog.h @@ -151,6 +151,17 @@ FOUNDATION_EXPORT void BNCLogFlushMessages(void); ///@return Returns true if the app is currently attached to a debugger. FOUNDATION_EXPORT BOOL BNCLogDebuggerIsAttached(void); +#pragma - Debugging + +///@return Returns true if the app is currently attached to a debugger. +extern BOOL BNCLogDebuggerIsAttached(void); + +/// Stops execution at the current execution point. +/// If attached to a debugger, current app will halt and wait for the debugger. +/// If not attached to a debugger then the current app will probably quit executing. +#define BNCLogDebugBreakpoint() \ + do { raise(SIGINT); } while (0) + #pragma mark - Logging ///@info Logging @@ -179,9 +190,9 @@ FOUNDATION_EXPORT BOOL BNCLogDebuggerIsAttached(void); do { \ if (BNCLogBreakPointsAreEnabled()) { \ BNCLogWriteMessageFormat(BNCLogLevelBreakPoint, __FILE__, __LINE__, @"Programmatic breakpoint."); \ - if (BNCDebuggerIsAttached()) { \ + if (BNCLogDebuggerIsAttached()) { \ BNCLogFlushMessages(); \ - BNCDebugBreakpoint(); \ + BNCLogDebugBreakpoint(); \ } \ } \ } while (0) @@ -191,9 +202,9 @@ FOUNDATION_EXPORT BOOL BNCLogDebuggerIsAttached(void); do { \ if (BNCLogBreakPointsAreEnabled() { \ BNCLogWriteMessageFormat(BNCLogLevelBreakPoint, __FILE__, __LINE__, __VA_ARGS__); \ - if (BNCDebuggerIsAttached()) { \ + if (BNCLogDebuggerIsAttached()) { \ BNCLogFlushMessages(); \ - BNCDebugBreakpoint(); \ + BNCLogDebugBreakpoint(); \ } \ } \ } while (0) @@ -203,9 +214,9 @@ FOUNDATION_EXPORT BOOL BNCLogDebuggerIsAttached(void); do { \ if (!(condition)) { \ BNCLogWriteMessageFormat(BNCLogLevelAssert, __FILE__, __LINE__, @"(%s) !!!", #condition); \ - if (BNCLogBreakPointsAreEnabled() && BNCDebuggerIsAttached()) { \ + if (BNCLogBreakPointsAreEnabled() && BNCLogDebuggerIsAttached()) { \ BNCLogFlushMessages(); \ - BNCDebugBreakpoint(); \ + BNCLogDebugBreakpoint(); \ } \ } \ } while (0) @@ -217,9 +228,9 @@ FOUNDATION_EXPORT BOOL BNCLogDebuggerIsAttached(void); if (!(condition)) { \ NSString *m = [NSString stringWithFormat:message, __VA_ARGS__]; \ BNCLogWriteMessageFormat(BNCLogLevelAssert, __FILE__, __LINE__, @"(%s) !!! %@", #condition, m); \ - if (BNCLogBreakPointsAreEnabled() && BNCDebuggerIsAttached()) { \ + if (BNCLogBreakPointsAreEnabled() && BNCLogDebuggerIsAttached()) { \ BNCLogFlushMessages(); \ - BNCDebugBreakpoint(); \ + BNCLogDebugBreakpoint(); \ } \ } \ } while (0) diff --git a/Vendor/Branch/BNCLog.m b/Vendor/Branch/BNCLog.m index 52c9260..3c17d98 100644 --- a/Vendor/Branch/BNCLog.m +++ b/Vendor/Branch/BNCLog.m @@ -43,7 +43,7 @@ BOOL BNCLogDebuggerIsAttached() { size = sizeof(info); junk = sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0); if (junk != 0) { - NSLog(@"Program error in BNCDebuggerIsAttached. Junk != 0!"); + NSLog(@"Program error in BNCLogDebuggerIsAttached. Junk != 0!"); } // We're being debugged if the P_TRACED flag is set. diff --git a/Vendor/Branch/BNCNetworkService.h b/Vendor/Branch/BNCNetworkService.h index 8534a6a..aa10c92 100644 --- a/Vendor/Branch/BNCNetworkService.h +++ b/Vendor/Branch/BNCNetworkService.h @@ -41,11 +41,11 @@ NS_ASSUME_NONNULL_BEGIN - (BNCNetworkOperation*) postOperationWithURL:(NSURL *)URL contentType:(NSString*)contentType - data:(NSData *)data + data:(NSData*_Nullable)data completion:(void (^)(BNCNetworkOperation*operation))completion; - (BNCNetworkOperation*) postOperationWithURL:(NSURL *)URL - JSONData:(id)dictionaryOrArray + JSONData:(id _Nullable)dictionaryOrArray completion:(void (^)(BNCNetworkOperation*operation))completion; - (NSError*_Nullable) pinSessionToPublicSecKeyRefs:(NSArray/***/*)publicKeys; diff --git a/Vendor/Branch/BNCNetworkService.m b/Vendor/Branch/BNCNetworkService.m index 0bc000b..fcb2d30 100644 --- a/Vendor/Branch/BNCNetworkService.m +++ b/Vendor/Branch/BNCNetworkService.m @@ -172,7 +172,6 @@ - (void) setAnySSLCertHosts:(NSMutableSet*)anySSLCertHosts_ { } - (BNCNetworkOperation*) networkOperationWithURL:(NSURL*)URL { - BNCNetworkOperation *operation = [BNCNetworkOperation new]; operation.request = [[NSMutableURLRequest alloc] diff --git a/Vendor/Branch/BNCThreads.h b/Vendor/Branch/BNCThreads.h index 95d2351..7f9b9be 100644 --- a/Vendor/Branch/BNCThreads.h +++ b/Vendor/Branch/BNCThreads.h @@ -38,6 +38,10 @@ static inline void BNCPerformBlockOnMainThreadSync(dispatch_block_t block) { } } +static inline void BNCPerformBlockAsync(dispatch_block_t block) { + dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), block); +} + static inline void BNCSleepForTimeInterval(NSTimeInterval seconds) { double secPart = trunc(seconds); double nanoPart = trunc((seconds - secPart) * ((double)NSEC_PER_SEC)); diff --git a/XcodeGitHub.xcodeproj/project.pbxproj b/XcodeGitHub.xcodeproj/project.pbxproj index fdff54a..6b0ec1d 100644 --- a/XcodeGitHub.xcodeproj/project.pbxproj +++ b/XcodeGitHub.xcodeproj/project.pbxproj @@ -160,7 +160,6 @@ 4DDAA4D2216ABF40002F3F8E /* Headers */, 4DDAA4D3216ABF40002F3F8E /* Sources */, 4DDAA4D4216ABF40002F3F8E /* Frameworks */, - 4DF8729A219BA41A00EDCB98 /* Build Static Library */, ); buildRules = ( ); @@ -178,7 +177,7 @@ isa = PBXProject; attributes = { CLASSPREFIX = XG; - LastUpgradeCheck = 1000; + LastUpgradeCheck = 1030; ORGANIZATIONNAME = Branch; TargetAttributes = { 4DDAA4D5216ABF40002F3F8E = { @@ -192,6 +191,7 @@ hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 4DDAA4CD216ABF40002F3F8E; productRefGroup = 4DDAA4D7216ABF40002F3F8E /* Products */; @@ -203,28 +203,6 @@ }; /* End PBXProject section */ -/* Begin PBXShellScriptBuildPhase section */ - 4DF8729A219BA41A00EDCB98 /* Build Static Library */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - ); - inputPaths = ( - "$(CONFIGURATION_BUILD_DIR)/libXcodeGitHub.a", - ); - name = "Build Static Library"; - outputFileListPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/bash; - shellScript = "\"${SOURCE_ROOT}\"/\"${PRODUCT_NAME}\"/make-static-lib.sh\n"; - }; -/* End PBXShellScriptBuildPhase section */ - /* Begin PBXSourcesBuildPhase section */ 4DDAA4D3216ABF40002F3F8E /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -278,8 +256,12 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_ALLOWED = YES; CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = WRWLR8VRUH; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -297,12 +279,14 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = Info.plist; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = Build; }; name = Debug; }; @@ -338,8 +322,12 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGNING_ALLOWED = YES; CODE_SIGN_IDENTITY = "Mac Developer"; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + CODE_SIGN_STYLE = Manual; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = WRWLR8VRUH; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu11; @@ -351,21 +339,20 @@ GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; INFOPLIST_FILE = Info.plist; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = macosx; SKIP_INSTALL = YES; + STRIP_INSTALLED_PRODUCT = NO; + SYMROOT = Build; }; name = Release; }; 4DDAA4E0216ABF40002F3F8E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Automatic; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; - DEVELOPMENT_TEAM = R63EM248DP; - EXECUTABLE_PREFIX = lib; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Debug; @@ -373,10 +360,7 @@ 4DDAA4E1216ABF40002F3F8E /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Automatic; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; - DEVELOPMENT_TEAM = R63EM248DP; - EXECUTABLE_PREFIX = lib; PRODUCT_NAME = "$(TARGET_NAME)"; }; name = Release; diff --git a/XcodeGitHub.xcodeproj/xcshareddata/xcschemes/XcodeGitHub.xcscheme b/XcodeGitHub.xcodeproj/xcshareddata/xcschemes/XcodeGitHub.xcscheme index a7c1c90..7721fe3 100644 --- a/XcodeGitHub.xcodeproj/xcshareddata/xcschemes/XcodeGitHub.xcscheme +++ b/XcodeGitHub.xcodeproj/xcshareddata/xcschemes/XcodeGitHub.xcscheme @@ -1,10 +1,29 @@ + LastUpgradeVersion = "1030" + version = "1.7"> + + + + + + + + + + CFBundlePackageType FMWK CFBundleShortVersionString - 1.0.3 + 1.1.2 CFBundleVersion 1 NSHumanReadableCopyright - Copyright © 2018 Branch. All rights reserved. + Copyright © 2018 Branch Metrics. All rights reserved. NSPrincipalClass diff --git a/XcodeGitHub/XGCommand.m b/XcodeGitHub/XGCommand.m index fae30c6..3afeabd 100644 --- a/XcodeGitHub/XGCommand.m +++ b/XcodeGitHub/XGCommand.m @@ -39,7 +39,11 @@ gitHubPullRequestTitle:pr.title error:&error]; if (error) { - BNCLogError(@"Can't create Xcode bot: %@.", error); + if (error.code == -999) { + BNCLogError(@"Can't create Xcode bot, permission error: %@.", error); + } else { + BNCLogError(@"Can't create Xcode bot: %@.", error); + } } return error; } diff --git a/XcodeGitHub/XGCommandOptions.m b/XcodeGitHub/XGCommandOptions.m index a89779e..b7ad1f9 100644 --- a/XcodeGitHub/XGCommandOptions.m +++ b/XcodeGitHub/XGCommandOptions.m @@ -67,7 +67,7 @@ + (NSString*) stringFromParameter { + (NSString*) helpString { NSString *kHelpString = - @"xcode-github - Creates an Xcode test bots for new GitHub PRs.\n" + @"xcode-github - Creates Xcode test bots for new GitHub PRs.\n" "\n" "usage: xcode-github [-dhsVv] -g \n" " -t -x \n" @@ -108,6 +108,8 @@ + (NSString*) helpString { " -x, --xcodeserver \n" " The network name of the xcode server.\n" "\n" + "The tool returns 0 on success, otherwise a non-zero value.\n" + "\n" ; return kHelpString; } diff --git a/XcodeGitHub/XGGitHubPullRequest.h b/XcodeGitHub/XGGitHubPullRequest.h index ba51b9e..a2b97d6 100644 --- a/XcodeGitHub/XGGitHubPullRequest.h +++ b/XcodeGitHub/XGGitHubPullRequest.h @@ -42,7 +42,8 @@ FOUNDATION_EXPORT NSString*_Nonnull NSStringFromXGPullRequestStatus(XGPullReques @property (strong, readonly) NSString*_Nullable body; @property (strong, readonly) NSString*_Nullable state; @property (strong, readonly) NSDictionary*_Nullable dictionary; -@property (strong, readonly) NSString*_Nullable sha; +@property (strong, readonly) NSString*_Nullable headSHA; +@property (strong, readonly) NSString*_Nullable baseSHA; @property (strong, readonly) NSString*_Nullable githubPRURL; + (instancetype _Nonnull) new NS_UNAVAILABLE; diff --git a/XcodeGitHub/XGGitHubPullRequest.m b/XcodeGitHub/XGGitHubPullRequest.m index 48d169f..46c0061 100644 --- a/XcodeGitHub/XGGitHubPullRequest.m +++ b/XcodeGitHub/XGGitHubPullRequest.m @@ -99,7 +99,8 @@ - (instancetype) initWithDictionary:(NSDictionary *)dictionary { NSInteger index = range.location + range.length; if (index < fullname.length) _repoName = [fullname substringFromIndex:index]; } - _sha = _dictionary[@"head"][@"sha"]; + _headSHA = _dictionary[@"head"][@"sha"]; + _baseSHA = _dictionary[@"base"][@"sha"]; _githubPRURL = _dictionary[@"url"]; return self; } @@ -231,7 +232,7 @@ + (NSString*) stringFromStatus:(XGPullRequestStatus)status { { NSString* string = [NSString stringWithFormat: @"https://api.github.com/repos/%@/%@/commits/%@/statuses", - self.repoOwner, self.repoName, self.sha]; + self.repoOwner, self.repoName, self.headSHA]; NSURL *URL = [NSURL URLWithString:string]; if (!URL) { error = @@ -305,7 +306,7 @@ - (NSError*_Nullable) setStatus:(XGPullRequestStatus)status NSError *error = nil; NSString* string = [NSString stringWithFormat: @"https://api.github.com/repos/%@/%@/statuses/%@", - self.repoOwner, self.repoName, self.sha]; + self.repoOwner, self.repoName, self.headSHA]; NSURL *URL = [NSURL URLWithString:string]; if (!URL) { error = @@ -366,7 +367,7 @@ - (NSError*_Nullable) addComment:(NSString*)comment { NSError *error = nil; NSString* string = [NSString stringWithFormat: @"https://api.github.com/repos/%@/%@/commits/%@/comments", - self.repoOwner, self.repoName, self.sha]; + self.repoOwner, self.repoName, self.headSHA]; NSURL *URL = [NSURL URLWithString:string]; if (!URL) { error = diff --git a/XcodeGitHub/XGSettings.m b/XcodeGitHub/XGSettings.m index 3968e48..5f681a7 100644 --- a/XcodeGitHub/XGSettings.m +++ b/XcodeGitHub/XGSettings.m @@ -9,6 +9,7 @@ */ #import "XGSettings.h" +#import "BNCLog.h" @interface NSMutableDictionary (XG) + (instancetype _Nonnull) mutableDeepCopy:(NSDictionary*)dictionary; @@ -33,7 +34,7 @@ + (instancetype _Nonnull) mutableDeepCopy:(NSDictionary*)dictionary { } exit: - if (error) NSLog(@"Error creating mutable dictionary: %@.", error); + if (error) BNCLogError(@"Error creating mutable dictionary: %@.", error); if (!result) result = [NSMutableDictionary new]; return result; } diff --git a/XcodeGitHub/XGXcodeBot.h b/XcodeGitHub/XGXcodeBot.h index c15ac2d..8388fca 100644 --- a/XcodeGitHub/XGXcodeBot.h +++ b/XcodeGitHub/XGXcodeBot.h @@ -100,7 +100,7 @@ NS_ASSUME_NONNULL_BEGIN @property (strong, readonly) NSString*_Nullable name; @property (strong, readonly) NSString*_Nullable botID; -@property (strong, readonly) NSString*_Nonnull serverName; +@property (strong, readonly) XGServer*_Nonnull server; /// @brief Repo Information @@ -129,7 +129,7 @@ NS_ASSUME_NONNULL_BEGIN @return A dictionary with a key of the bot name and value of the bot status. */ + (NSDictionary*_Nullable) botsForServer:(XGServer*)xcodeServer - error:(NSError*__autoreleasing _Nullable*_Nullable)error; + error:(NSError*__autoreleasing _Nullable*_Nullable)error; + (NSString*_Nonnull) botNameFromPRNumber:(NSString*_Nonnull)number title:(NSString*_Nonnull)title; @@ -140,6 +140,7 @@ NS_ASSUME_NONNULL_BEGIN error:(NSError*__autoreleasing _Nullable*_Nullable)error; - (NSError*_Nullable) startIntegration; +- (NSError*_Nullable) cancelIntegrationID:(NSString*)integrationID; - (XGXcodeBotStatus*_Nonnull) status; - (NSError*_Nullable) deleteBot; @end diff --git a/XcodeGitHub/XGXcodeBot.m b/XcodeGitHub/XGXcodeBot.m index 41202dd..abf3632 100644 --- a/XcodeGitHub/XGXcodeBot.m +++ b/XcodeGitHub/XGXcodeBot.m @@ -254,11 +254,11 @@ - (NSURL*) integrationLogURL { @implementation XGXcodeBot -- (instancetype) initWithServerName:(NSString *)serverName dictionary:(NSDictionary *)dictionary { +- (instancetype) initWithServer:(XGServer*)server dictionary:(NSDictionary *)dictionary { self = [super init]; if (!self) return self; - _serverName = [serverName copy]; + _server = server; _dictionary = dictionary; _name = _dictionary[@"name"]; _botID = _dictionary[@"_id"]; @@ -295,11 +295,15 @@ - (instancetype) initWithServerName:(NSString *)serverName dictionary:(NSDiction _repoOwner = [self.sourceControlRepository substringWithRange:NSMakeRange(ownerRange.location+1, repoRange.location - ownerRange.location - 1)]; _repoName = [self.sourceControlRepository - substringWithRange:NSMakeRange(repoRange.location+1, self.sourceControlRepository.length - repoRange.location - 1)]; + substringWithRange:NSMakeRange( + repoRange.location+1, + self.sourceControlRepository.length - repoRange.location - 1 + )]; if ([_repoName hasSuffix:@".git"]) { _repoName = [_repoName substringWithRange:NSMakeRange(0, _repoName.length-4)]; } - NSDictionary*locations = _dictionary[@"configuration"][@"sourceControlBlueprint"][@"DVTSourceControlWorkspaceBlueprintLocationsKey"]; + NSDictionary*locations = + _dictionary[@"configuration"][@"sourceControlBlueprint"][@"DVTSourceControlWorkspaceBlueprintLocationsKey"]; for (NSDictionary*location in locations.objectEnumerator) { _branch = location[@"DVTSourceControlBranchIdentifierKey"]; } @@ -377,7 +381,7 @@ + (NSString*) botNameFromPRNumber:(NSString *)number title:(NSString *)title { bots = [NSMutableDictionary new]; for (NSDictionary *d in results) { - XGXcodeBot *bot = [[XGXcodeBot alloc] initWithServerName:xcodeServer.server dictionary:d]; + XGXcodeBot *bot = [[XGXcodeBot alloc] initWithServer:xcodeServer dictionary:d]; if (bot && bot.name) { bots[bot.name] = bot; } @@ -406,7 +410,7 @@ - (XGXcodeBotStatus*_Nonnull) status { NSString *statusString = [NSString stringWithFormat: @"https://%@:20343/api/bots/%@/integrations?last=1", - self.serverName, self.botID]; + self.server.server, self.botID]; NSURL *statusURL = [NSURL URLWithString:statusString]; dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); @@ -415,6 +419,8 @@ - (XGXcodeBotStatus*_Nonnull) status { getOperationWithURL:statusURL completion:^(BNCNetworkOperation *operation) { dispatch_semaphore_signal(semaphore); }]; + if (self.server.user.length > 0) + [operation setUser:self.server.user password:self.server.password]; [operation start]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); @@ -433,12 +439,12 @@ - (XGXcodeBotStatus*_Nonnull) status { NSArray *a = response[@"results"]; if ([a isKindOfClass:NSArray.class]) { if (a.count >= 1) - status = [[XGXcodeBotStatus alloc] initWithServerName:self.serverName dictionary:a[0]]; + status = [[XGXcodeBotStatus alloc] initWithServerName:self.server.server dictionary:a[0]]; else { - status = [[XGXcodeBotStatus alloc] initWithServerName:self.serverName dictionary:nil]; + status = [[XGXcodeBotStatus alloc] initWithServerName:self.server.server dictionary:nil]; status.botID = self.botID; status.botName = self.name; - status.serverName = self.serverName; + status.serverName = self.server.server; status.integrationNumber = [NSNumber numberWithInteger:0]; status.currentStep = @"no integrations"; status.result = @"unknown"; @@ -453,7 +459,7 @@ - (XGXcodeBotStatus*_Nonnull) status { } exit: - if (!status) status = [[XGXcodeBotStatus alloc] initWithServerName:self.serverName dictionary:nil]; + if (!status) status = [[XGXcodeBotStatus alloc] initWithServerName:self.server.server dictionary:nil]; if (localError) status.error = localError; return status; } @@ -461,7 +467,7 @@ - (XGXcodeBotStatus*_Nonnull) status { - (NSError*_Nullable) deleteBot { NSError *localError = nil; NSString *string = [NSString stringWithFormat: - @"https://%@:20343/api/bots/%@", self.serverName, self.botID]; + @"https://%@:20343/api/bots/%@", self.server.server, self.botID]; NSURL *URL = [NSURL URLWithString:string]; if (!URL) { localError = @@ -469,10 +475,10 @@ - (NSError*_Nullable) deleteBot { code:NSURLErrorBadURL userInfo:@{ NSLocalizedDescriptionKey: - [NSString stringWithFormat:@"Bad server name '%@'.", self.serverName] + [NSString stringWithFormat:@"Bad server name '%@'.", self.server.server] } ]; - BNCLogError(@"Bad server name '%@'.", self.serverName); + BNCLogError(@"Bad server name '%@'.", self.server.server); return localError; } @@ -484,6 +490,8 @@ - (NSError*_Nullable) deleteBot { dispatch_semaphore_signal(semaphore); }]; operation.request.HTTPMethod = @"DELETE"; + if (self.server.user.length > 0) + [operation setUser:self.server.user password:self.server.password]; [operation start]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); if (operation.error) return operation.error; @@ -506,10 +514,21 @@ - (XGXcodeBot*_Nullable) duplicateBotWithNewName:(NSString*_Nonnull)newBotName XGXcodeBot *bot = nil; NSError *localError = nil; { + // Simply using the 'duplicate' bot api and changing the git branch won't actually change + // the git branch to the branch of the PR. + // + // Steps: + // 1. Duplicate the bot. + // 2. Get the new bot. + // 3. Modify the bot to the new branch with a PATCH. + + // + // Duplicate the bot: + // + NSString *string = [NSString stringWithFormat:@"https://%@:20343/api/bots/%@/duplicate", - self.serverName, - self.botID]; + self.server.server, self.botID]; NSURL *URL = [NSURL URLWithString:string]; if (!URL) { localError = @@ -517,38 +536,149 @@ - (XGXcodeBot*_Nullable) duplicateBotWithNewName:(NSString*_Nonnull)newBotName code:NSURLErrorBadURL userInfo:@{ NSLocalizedDescriptionKey: - [NSString stringWithFormat:@"Bad server name '%@'.", self.serverName] + [NSString stringWithFormat:@"Bad server name '%@'.", self.server.server] } ]; - BNCLogError(@"Bad server name '%@'.", self.serverName); + BNCLogError(@"Bad server name '%@'.", self.server.server); goto exit; } + __auto_type dictionary = [NSMutableDictionary new]; + dictionary[@"name"] = newBotName; + dictionary[@"templateBotName"] = self.name; + dictionary[@"pullRequestNumber"] = pullRequestNumber; + dictionary[@"pullRequestTitle"] = pullRequestTitle; - NSMutableDictionary *dictionary = (__bridge_transfer NSMutableDictionary*) + NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&localError]; + if (!data) { + localError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSKeyValueValidationError + userInfo:@{ NSLocalizedDescriptionKey: @"Can't create bot dictionary."}]; + } + if (localError || !data) goto exit; + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + BNCNetworkOperation *operation = + [[BNCNetworkService shared] + postOperationWithURL:URL + contentType:@"application/json" + data:data + completion:^(BNCNetworkOperation *operation) { + dispatch_semaphore_signal(semaphore); + }]; + if (self.server.user.length > 0) + [operation setUser:self.server.user password:self.server.password]; + [operation.request addValue:@"7" forHTTPHeaderField:@"X-XCSClientVersion"]; + [operation start]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (operation.error) { + localError = operation.error; + goto exit; + } + if (operation.HTTPStatusCode != 201) { + localError = [NSError errorWithDomain:NSNetServicesErrorDomain + code:NSNetServicesInvalidError userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"HTTP Status %ld", (long) operation.HTTPStatusCode]}]; + BNCLogDebug(@"Response was: %@.", [operation stringFromResponseData]); + goto exit; + } + [operation deserializeJSONResponseData]; + NSDictionary *d = (id) operation.responseData; + if (!([d isKindOfClass:NSDictionary.class] && [d[@"_id"] isKindOfClass:NSString.class])) { + localError = + [NSError errorWithDomain:NSNetServicesErrorDomain + code:NSURLErrorBadServerResponse + userInfo:@{ NSLocalizedDescriptionKey: @"Expected an Xcode bot response." }]; + goto exit; + } + NSString*newBotID = d[@"_id"]; + + // + // Get the just created bot: + // + + string = + [NSString stringWithFormat:@"https://%@:20343/api/bots/%@", + self.server.server, newBotID]; + URL = [NSURL URLWithString:string]; + semaphore = dispatch_semaphore_create(0); + operation = + [[BNCNetworkService shared] + getOperationWithURL:URL + completion:^(BNCNetworkOperation *operation) { + dispatch_semaphore_signal(semaphore); + }]; + if (self.server.user.length > 0) + [operation setUser:self.server.user password:self.server.password]; + [operation.request addValue:@"7" forHTTPHeaderField:@"X-XCSClientVersion"]; + [operation start]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (operation.error) { + localError = operation.error; + goto exit; + } + if (operation.HTTPStatusCode != 200) { + localError = [NSError errorWithDomain:NSNetServicesErrorDomain + code:NSNetServicesInvalidError userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"HTTP Status %ld", (long) operation.HTTPStatusCode]}]; + BNCLogDebug(@"Response was: %@.", [operation stringFromResponseData]); + goto exit; + } + [operation deserializeJSONResponseData]; + d = (id) operation.responseData; + if (!([d isKindOfClass:NSDictionary.class] && + [d[@"_id"] isKindOfClass:NSString.class] && + [newBotID isEqualToString:d[@"_id"]])) { + localError = + [NSError errorWithDomain:NSNetServicesErrorDomain + code:NSURLErrorBadServerResponse + userInfo:@{ NSLocalizedDescriptionKey: @"Expected an Xcode bot response." }]; + goto exit; + } + + // + // Fix up the git branch of the duplicated bot: + // + + string = + [NSString stringWithFormat:@"https://%@:20343/api/bots/%@?overwriteBlueprint=true", + self.server.server, newBotID]; + URL = [NSURL URLWithString:string]; + + dictionary = (__bridge_transfer NSMutableDictionary*) CFPropertyListCreateDeepCopy( kCFAllocatorDefault, - (CFDictionaryRef)self.dictionary, + (CFDictionaryRef)d, kCFPropertyListMutableContainers ); + dictionary[@"_id"] = nil; + dictionary[@"_rev"] = nil; + dictionary[@"tinyID"] = nil; dictionary[@"configuration"] [@"sourceControlBlueprint"] [@"DVTSourceControlWorkspaceBlueprintLocationsKey"] [self.sourceControlWorkspaceBlueprintLocationsID] - [@"DVTSourceControlBranchIdentifierKey"] = - branchName; + [@"DVTSourceControlBranchIdentifierKey"] + = branchName; + dictionary[@"configuration"] + [@"sourceControlBlueprint"] + [@"DVTSourceControlWorkspaceBlueprintRemoteRepositoryAuthenticationStrategiesKey"] + = @{}; + dictionary[@"configuration"] + [@"sourceControlBlueprint"] + [@"DVTSourceControlWorkspaceBlueprintIdentifierKey"] + = [NSUUID UUID].UUIDString; dictionary[@"configuration"][@"scheduleType"] = @2; // 2: On commit - dictionary[@"integration_counter"] = nil; + dictionary[@"sourceControlBlueprintIdentifier"] = nil; dictionary[@"lastRevisionBlueprint"] = nil; - dictionary[@"name"] = newBotName; - dictionary[@"templateBotName"] = self.name; - dictionary[@"pullRequestNumber"] = pullRequestNumber; - dictionary[@"pullRequestTitle"] = pullRequestTitle; - NSData *data = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&localError]; - if (localError) goto exit; + data = [NSJSONSerialization dataWithJSONObject:dictionary options:0 error:&localError]; + if (!data) { + localError = [NSError errorWithDomain:NSCocoaErrorDomain code:NSKeyValueValidationError + userInfo:@{ NSLocalizedDescriptionKey: @"Can't create bot dictionary."}]; + } + if (localError || !data) goto exit; - dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); - BNCNetworkOperation *operation = + semaphore = dispatch_semaphore_create(0); + operation = [[BNCNetworkService shared] postOperationWithURL:URL contentType:@"application/json" @@ -556,25 +686,27 @@ - (XGXcodeBot*_Nullable) duplicateBotWithNewName:(NSString*_Nonnull)newBotName completion:^(BNCNetworkOperation *operation) { dispatch_semaphore_signal(semaphore); }]; + if (self.server.user.length > 0) + [operation setUser:self.server.user password:self.server.password]; + operation.request.HTTPMethod = @"PATCH"; + [operation.request addValue:@"7" forHTTPHeaderField:@"X-XCSClientVersion"]; [operation start]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); if (operation.error) { localError = operation.error; goto exit; } - - if (operation.HTTPStatusCode != 201) { + if (operation.HTTPStatusCode != 200) { localError = [NSError errorWithDomain:NSNetServicesErrorDomain code:NSNetServicesInvalidError userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat:@"HTTP Status %ld", (long) operation.HTTPStatusCode]}]; BNCLogDebug(@"Response was: %@.", [operation stringFromResponseData]); goto exit; } - [operation deserializeJSONResponseData]; - NSDictionary *d = (id) operation.responseData; + d = (id) operation.responseData; if ([d isKindOfClass:NSDictionary.class]) { - bot = [[XGXcodeBot alloc] initWithServerName:self.serverName dictionary:d]; + bot = [[XGXcodeBot alloc] initWithServer:self.server dictionary:d]; if (bot) { [bot startIntegration]; goto exit; @@ -594,7 +726,7 @@ - (XGXcodeBot*_Nullable) duplicateBotWithNewName:(NSString*_Nonnull)newBotName - (NSError*) startIntegration { NSError *localError = nil; NSString *string = [NSString stringWithFormat: - @"https://%@:20343/api/bots/%@/integrations", self.serverName, self.botID]; + @"https://%@:20343/api/bots/%@/integrations", self.server.server, self.botID]; NSURL *URL = [NSURL URLWithString:string]; if (!URL) { localError = @@ -602,10 +734,10 @@ - (NSError*) startIntegration { code:NSURLErrorBadURL userInfo:@{ NSLocalizedDescriptionKey: - [NSString stringWithFormat:@"Bad server name '%@'.", self.serverName] + [NSString stringWithFormat:@"Bad server name '%@'.", self.server.server] } ]; - BNCLogError(@"Bad server name '%@'.", self.serverName); + BNCLogError(@"Bad server name '%@'.", self.server.server); return localError; } @@ -621,6 +753,8 @@ - (NSError*) startIntegration { completion:^(BNCNetworkOperation *operation) { dispatch_semaphore_signal(semaphore); }]; + if (self.server.user.length > 0) + [operation setUser:self.server.user password:self.server.password]; [operation start]; dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); if (operation.error) return operation.error; @@ -635,4 +769,49 @@ - (NSError*) startIntegration { return nil; } +- (NSError*_Nullable) cancelIntegrationID:(NSString*)integrationID { + NSError *localError = nil; + NSString *string = [NSString stringWithFormat: + @"https://%@:20343/api/integrations/%@/cancel", self.server.server, integrationID]; + NSURL *URL = [NSURL URLWithString:string]; + if (!URL) { + localError = + [NSError errorWithDomain:NSNetServicesErrorDomain + code:NSURLErrorBadURL + userInfo:@{ + NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"Bad server name '%@'.", self.server.server] + } + ]; + BNCLogError(@"Bad server name '%@'.", self.server.server); + return localError; + } + + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + BNCNetworkOperation *operation = + [[BNCNetworkService shared] + postOperationWithURL:URL + JSONData:nil + completion:^(BNCNetworkOperation *operation) { + dispatch_semaphore_signal(semaphore); + }]; + if (self.server.user.length > 0) + [operation setUser:self.server.user password:self.server.password]; + [operation start]; + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + if (operation.error) return operation.error; + + if (operation.HTTPStatusCode != 204) { + [operation deserializeJSONResponseData]; + localError = [NSError errorWithDomain:NSNetServicesErrorDomain + code:NSNetServicesInvalidError userInfo:@{NSLocalizedDescriptionKey: + [NSString stringWithFormat:@"HTTP Status %ld: %@", + (long) operation.HTTPStatusCode, + (id) operation.responseData] }]; + return localError; + } + + return nil; +} + @end diff --git a/XcodeGitHub/make-static-lib.sh b/XcodeGitHub/make-static-lib.sh index 4823ce8..c7999aa 100755 --- a/XcodeGitHub/make-static-lib.sh +++ b/XcodeGitHub/make-static-lib.sh @@ -7,6 +7,9 @@ set -euo pipefail # Created by Edward Smith on 10/7/18. # Copyright © 2018 Branch. All rights reserved. +echo "Building: ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework" + +cd "${PROJECT_DIR}" /bin/rm -Rf "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework" # Headers: @@ -42,10 +45,10 @@ set -euo pipefail "Versions/Current/${PRODUCT_NAME}" \ "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework/${PRODUCT_NAME}" -## Copy to Products directory: -#/usr/bin/ditto \ -# "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework" \ -# "${SOURCE_ROOT}/Products/${PRODUCT_NAME}.framework" +# Copy to Products directory: +/usr/bin/ditto \ + "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework" \ + "${SOURCE_ROOT}/Build/${PRODUCT_NAME}.framework" -echo "Result:" -echo "${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework" +echo " Result: ${BUILT_PRODUCTS_DIR}/${PRODUCT_NAME}.framework" +echo " Ditto: ${SOURCE_ROOT}/Build/${PRODUCT_NAME}.framework" diff --git a/xcode-github-app.xcodeproj/project.pbxproj b/xcode-github-app.xcodeproj/project.pbxproj index ae7aba4..ceab214 100644 --- a/xcode-github-app.xcodeproj/project.pbxproj +++ b/xcode-github-app.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 2BB6F4D321F9E3FF001E8693 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2BB6F4D121F9E3FF001E8693 /* Credits.rtf */; }; + 2BE8B585221D2C9E006D8B3D /* libXcodeGitHub.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DC9E5C9216DCD6700F1F4EE /* libXcodeGitHub.a */; }; 4D12BA0D20A252CE00E5B1DB /* XGALogViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D12BA0B20A252CE00E5B1DB /* XGALogViewController.m */; }; 4D12BA0E20A252CE00E5B1DB /* XGALogViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4D12BA0C20A252CE00E5B1DB /* XGALogViewController.xib */; }; 4D5CC05E2090CAB60042E98B /* BNCKeyChain.m in Sources */ = {isa = PBXBuildFile; fileRef = 4D5CC05D2090CAB60042E98B /* BNCKeyChain.m */; }; @@ -24,7 +26,6 @@ 4D8352D120A516A200184259 /* XGAPreferencesViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4D8352CF20A516A200184259 /* XGAPreferencesViewController.xib */; }; 4DAA4666214CBEFF007A39EB /* XGAAddServerPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DAA4664214CBEFF007A39EB /* XGAAddServerPanel.m */; }; 4DAA4667214CBEFF007A39EB /* XGAAddServerPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4DAA4665214CBEFF007A39EB /* XGAAddServerPanel.xib */; }; - 4DD6B69C219B972300A38210 /* libXcodeGitHub.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DC9E5C9216DCD6700F1F4EE /* libXcodeGitHub.a */; }; 4DED4891209BDFCC008DE877 /* BNCGeometry.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DED4890209BDFCC008DE877 /* BNCGeometry.m */; }; 4DEE32E42162EB20006BD06C /* XGAStatusViewItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DEE32E32162EB20006BD06C /* XGAStatusViewItem.m */; }; 4DF0F58E208F923E0015D1F7 /* BNCThreads.m in Sources */ = {isa = PBXBuildFile; fileRef = 4DF0F588208F923E0015D1F7 /* BNCThreads.m */; }; @@ -34,24 +35,27 @@ /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 4DC9E5C8216DCD6700F1F4EE /* PBXContainerItemProxy */ = { + 2BE8B583221D2C96006D8B3D /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4DC9E5C4216DCD6700F1F4EE /* XcodeGitHub.xcodeproj */; - proxyType = 2; - remoteGlobalIDString = 4DDAA4D6216ABF40002F3F8E; + proxyType = 1; + remoteGlobalIDString = 4DDAA4D5216ABF40002F3F8E; remoteInfo = XcodeGitHub; }; - 4DD6B69D219B973700A38210 /* PBXContainerItemProxy */ = { + 4DC9E5C8216DCD6700F1F4EE /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 4DC9E5C4216DCD6700F1F4EE /* XcodeGitHub.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 4DDAA4D5216ABF40002F3F8E; + proxyType = 2; + remoteGlobalIDString = 4DDAA4D6216ABF40002F3F8E; remoteInfo = XcodeGitHub; }; /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ - 4D0DD54420597FE6001721C1 /* xcode-github-app.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = "xcode-github-app.md"; path = "xcode-github-app/xcode-github-app.md"; sourceTree = ""; }; + 2BB6F4D221F9E3FF001E8693 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = Base; path = Base.lproj/Credits.rtf; sourceTree = ""; }; + 2BC31A1222041978003B0EE4 /* xcode-github-cli.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = "xcode-github-cli.md"; path = "Documentation/xcode-github-cli.md"; sourceTree = ""; }; + 2BFD78962216A06E00E63692 /* CHANGELOG.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = CHANGELOG.md; sourceTree = ""; }; + 4D0DD54420597FE6001721C1 /* xcode-github-app.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; name = "xcode-github-app.md"; path = "Documentation/xcode-github-app.md"; sourceTree = ""; }; 4D12BA0A20A252CE00E5B1DB /* XGALogViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = XGALogViewController.h; sourceTree = ""; }; 4D12BA0B20A252CE00E5B1DB /* XGALogViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = XGALogViewController.m; sourceTree = ""; }; 4D12BA0C20A252CE00E5B1DB /* XGALogViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = XGALogViewController.xib; sourceTree = ""; }; @@ -101,7 +105,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 4DD6B69C219B972300A38210 /* libXcodeGitHub.a in Frameworks */, + 2BE8B585221D2C9E006D8B3D /* libXcodeGitHub.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -111,7 +115,9 @@ 4D76615F2057565200216B72 = { isa = PBXGroup; children = ( + 2BFD78962216A06E00E63692 /* CHANGELOG.md */, 4D0DD54420597FE6001721C1 /* xcode-github-app.md */, + 2BC31A1222041978003B0EE4 /* xcode-github-cli.md */, 4DC9E5C4216DCD6700F1F4EE /* XcodeGitHub.xcodeproj */, 4D76616A2057565200216B72 /* xcode-github-app */, 4D7661692057565200216B72 /* Products */, @@ -131,6 +137,7 @@ isa = PBXGroup; children = ( 4D7661712057565200216B72 /* Assets.xcassets */, + 2BB6F4D121F9E3FF001E8693 /* Credits.rtf */, 4D7661762057565200216B72 /* Info.plist */, 4D7661772057565300216B72 /* main.m */, 4D7661732057565200216B72 /* Main.storyboard */, @@ -220,7 +227,7 @@ buildRules = ( ); dependencies = ( - 4DD6B69E219B973700A38210 /* PBXTargetDependency */, + 2BE8B584221D2C96006D8B3D /* PBXTargetDependency */, ); name = "xcode-github-app"; productName = XcodeGitHub; @@ -234,12 +241,12 @@ isa = PBXProject; attributes = { CLASSPREFIX = XGA; - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1030; ORGANIZATIONNAME = Branch; TargetAttributes = { 4D7661672057565200216B72 = { CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; + ProvisioningStyle = Manual; SystemCapabilities = { com.apple.HardenedRuntime = { enabled = 1; @@ -293,6 +300,7 @@ 4D7661722057565200216B72 /* Assets.xcassets in Resources */, 4D8352D120A516A200184259 /* XGAPreferencesViewController.xib in Resources */, 4D6536382150486B000812E1 /* XGAStatusPopover.xib in Resources */, + 2BB6F4D321F9E3FF001E8693 /* Credits.rtf in Resources */, 4D12BA0E20A252CE00E5B1DB /* XGALogViewController.xib in Resources */, 4D8352C620A3F30A00184259 /* XGAStatusViewController.xib in Resources */, 4DAA4667214CBEFF007A39EB /* XGAAddServerPanel.xib in Resources */, @@ -329,14 +337,22 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 4DD6B69E219B973700A38210 /* PBXTargetDependency */ = { + 2BE8B584221D2C96006D8B3D /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = XcodeGitHub; - targetProxy = 4DD6B69D219B973700A38210 /* PBXContainerItemProxy */; + targetProxy = 2BE8B583221D2C96006D8B3D /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ + 2BB6F4D121F9E3FF001E8693 /* Credits.rtf */ = { + isa = PBXVariantGroup; + children = ( + 2BB6F4D221F9E3FF001E8693 /* Base */, + ); + name = Credits.rtf; + sourceTree = ""; + }; 4D7661732057565200216B72 /* Main.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -384,6 +400,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Build"; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -398,7 +415,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -442,6 +459,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/Build"; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -450,7 +468,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.11; + MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; VALID_ARCHS = x86_64; @@ -462,17 +480,15 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "xcode-github-app/xcode-github-app.entitlements"; + CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = R63EM248DP; + DEVELOPMENT_TEAM = WRWLR8VRUH; ENABLE_HARDENED_RUNTIME = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Products", - ); INFOPLIST_FILE = "$(SRCROOT)/xcode-github-app/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.branch.xcode-github-app"; PRODUCT_NAME = XcodeGitHub; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Debug; }; @@ -481,17 +497,16 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_ENTITLEMENTS = "xcode-github-app/xcode-github-app.entitlements"; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Manual; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = R63EM248DP; + DEVELOPMENT_TEAM = WRWLR8VRUH; ENABLE_HARDENED_RUNTIME = YES; - FRAMEWORK_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/Products", - ); INFOPLIST_FILE = "$(SRCROOT)/xcode-github-app/Info.plist"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "io.branch.xcode-github-app"; PRODUCT_NAME = XcodeGitHub; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Release; }; diff --git a/xcode-github-app.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/xcode-github-app.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..0c67376 --- /dev/null +++ b/xcode-github-app.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,5 @@ + + + + + diff --git a/xcode-github-app.xcodeproj/xcshareddata/xcschemes/xcode-github-app.xcscheme b/xcode-github-app.xcodeproj/xcshareddata/xcschemes/xcode-github-app.xcscheme index 42c2789..1a4f931 100644 --- a/xcode-github-app.xcodeproj/xcshareddata/xcschemes/xcode-github-app.xcscheme +++ b/xcode-github-app.xcodeproj/xcshareddata/xcschemes/xcode-github-app.xcscheme @@ -1,6 +1,6 @@ - + - + @@ -11,11 +11,11 @@ - + - + - + @@ -33,7 +33,7 @@ - + @@ -51,7 +51,7 @@ - + @@ -63,9 +63,9 @@ - + - + @@ -369,7 +369,7 @@ - + diff --git a/xcode-github-app/Info.plist b/xcode-github-app/Info.plist index 2eab773..98c8f00 100644 --- a/xcode-github-app/Info.plist +++ b/xcode-github-app/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0.3 + 1.1.2 CFBundleVersion 1 LSApplicationCategoryType @@ -30,7 +30,7 @@ NSHumanReadableCopyright - Copyright © 2018 Branch. All rights reserved. + Copyright © 2018–2019 Branch Metrics. All rights reserved. NSMainStoryboardFile Main NSPrincipalClass diff --git a/xcode-github-app/XGAAddServerPanel.m b/xcode-github-app/XGAAddServerPanel.m index bd38a57..c90cf70 100644 --- a/xcode-github-app/XGAAddServerPanel.m +++ b/xcode-github-app/XGAAddServerPanel.m @@ -12,6 +12,7 @@ #import "XGAAddServerPanel.h" #import "XGANetworkServiceBrowser.h" #import "BNCThreads.h" +#import NSTimeInterval const kNetworkRefreshInterval = 7.0; @@ -93,26 +94,48 @@ - (IBAction)cancel:(id)sender { [self.sheetParent endSheet:self returnCode:NSModalResponseCancel]; } -- (void) showAlertWithError:(NSError*)error { - NSAlert*alert = [[NSAlert alloc] init]; - alert.messageText = [NSString stringWithFormat:@"Can't connect to '%@'", self.server.server]; - alert.informativeText = [error localizedDescription]; - alert.alertStyle = NSAlertStyleCritical; - [alert beginSheetModalForWindow:self completionHandler:nil]; -} - - (IBAction)add:(id)sender { - self.server.server = XGACleanString(self.serverTextField.stringValue); - self.server.user = XGACleanString(self.userTextField.stringValue); + self.server.server = XGACleanString(self.serverTextField.stringValue); + self.server.user = XGACleanString(self.userTextField.stringValue); self.server.password = XGACleanString(self.passwordTextField.stringValue); if (self.server.server.length <= 0) return; - NSError*error = nil; - [XGXcodeBot botsForServer:self.server error:&error]; - if (error) { - [self showAlertWithError:error]; - return; + // Timeout in a few seconds-- + + __block _Atomic(BOOL) timedOut = NO; + __block _Atomic(NSError*) error = nil; + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + BNCPerformBlockAsync(^{ + BNCSleepForTimeInterval(5.0); + atomic_exchange(&timedOut, YES); + dispatch_semaphore_signal(semaphore); + }); + BNCPerformBlockAsync(^{ + NSError*localError = nil; + [XGXcodeBot botsForServer:self.server error:&localError]; + atomic_exchange(&error, localError); + dispatch_semaphore_signal(semaphore); + }); + dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); + + if (error != nil || timedOut) { + NSAlert*alert = [[NSAlert alloc] init]; + alert.messageText = [NSString stringWithFormat:@"Can't connect to '%@'.", self.server.server]; + if (error != nil) + alert.informativeText = [error localizedDescription]; + alert.alertStyle = NSAlertStyleWarning; + [alert addButtonWithTitle:@"Add Anyway"]; + [alert addButtonWithTitle:@"Cancel"]; + [alert beginSheetModalForWindow:self completionHandler:^(NSModalResponse returnCode) { + if (returnCode == NSAlertFirstButtonReturn) + [self finishSheetWithResponseOK]; + }]; + } else { + [self finishSheetWithResponseOK]; } +} + +- (void) finishSheetWithResponseOK { [self stopNetworkLookup]; self.serverArrayController = nil; [self.sheetParent endSheet:self returnCode:NSModalResponseOK]; @@ -145,7 +168,7 @@ - (void) updateNetworkSpinner { - (void) restartNetworkLookup { @synchronized(self) { - NSLog(@"restartNetworkLookup"); + //NSLog(@"restartNetworkLookup"); [self stopNetworkLookup]; self.networkLookupDate = [NSDate dateWithTimeInterval:kNetworkRefreshInterval sinceDate:[NSDate date]]; self.activityWheel.doubleValue = 0.0; diff --git a/xcode-github-app/XGAAppDelegate.m b/xcode-github-app/XGAAppDelegate.m index 39f6e1d..2b2d386 100644 --- a/xcode-github-app/XGAAppDelegate.m +++ b/xcode-github-app/XGAAppDelegate.m @@ -12,8 +12,14 @@ #import "XGALogViewController.h" #import "XGAStatusViewController.h" #import "XGAPreferencesViewController.h" +#import "XGASettings.h" #import +/* + All about About Panels: + http://cocoadevcentral.com/articles/000071.php +*/ + @interface XGAAppDelegate () @property (nonatomic, strong) IBOutlet XGALogViewController*logController; @property (nonatomic, strong) IBOutlet XGAStatusViewController*statusController; @@ -47,9 +53,22 @@ - (IBAction)showPreferences:(id)sender { [self.preferencesController.window makeKeyAndOrderFront:self]; } +- (IBAction)addNewServer:(id)sender { + [self showPreferences:sender]; + [self.preferencesController addServerAction:sender]; +} + - (BOOL)windowShouldClose:(NSWindow*)window { - self.preferencesController = nil; - return YES; + if (window == self.preferencesController.window) { + self.preferencesController = nil; + return YES; + } + return NO; +} + +- (void)applicationDidFinishLaunching:(NSNotification *)notification { + if (XGASettings.shared.servers.count == 0 && XGASettings.shared.gitHubSyncTasks.count == 0) + [self addNewServer:nil]; } @end diff --git a/xcode-github-app/XGALogViewController.m b/xcode-github-app/XGALogViewController.m index cd8ca88..f6adbd4 100644 --- a/xcode-github-app/XGALogViewController.m +++ b/xcode-github-app/XGALogViewController.m @@ -36,6 +36,7 @@ + (NSImage*) imageForLogLevel:(BNCLogLevel)level; @property (strong) NSDateFormatter*dateFormatter; @property (strong) IBOutlet NSArrayController *arrayController; @property (weak) IBOutlet NSTableView*tableView; +@property (strong) IBOutlet XGASettings*settings; @property (strong) XGAStatusPopover*statusPopover; @end @@ -84,6 +85,7 @@ + (void) startLog { + (instancetype) new { XGALogViewController*controller = [[XGALogViewController alloc] init]; + controller.settings = XGASettings.shared; [[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self) owner:controller @@ -179,6 +181,7 @@ - (void) updateMessageFilter { self.arrayController.filterPredicate = [NSPredicate predicateWithFormat:@"logLevel > 2"]; } + [self.settings save]; } - (void)logUpdatedNotification:(NSNotification*)notification { diff --git a/xcode-github-app/XGALogViewController.xib b/xcode-github-app/XGALogViewController.xib index 2a89111..d7f82b7 100644 --- a/xcode-github-app/XGALogViewController.xib +++ b/xcode-github-app/XGALogViewController.xib @@ -1,8 +1,8 @@ - + - + @@ -17,7 +17,7 @@ - + @@ -27,20 +27,46 @@ + + + + + + + + + + + - + - + - + - + @@ -81,7 +107,7 @@ - + @@ -121,7 +147,7 @@ - + @@ -172,11 +198,11 @@ - + - + + + - + diff --git a/xcode-github-app/XGANetworkServiceBrowser.m b/xcode-github-app/XGANetworkServiceBrowser.m index 017989e..c24c53e 100644 --- a/xcode-github-app/XGANetworkServiceBrowser.m +++ b/xcode-github-app/XGANetworkServiceBrowser.m @@ -20,6 +20,7 @@ - (instancetype) initWithService:(NSNetService*)service NS_DESIGNATED_INITIALI @property (strong) NSNetService*service; @property (strong) NSArray*names; @property (strong) NSArray*addresses; +@property (strong) NSError*_Nullable error; @property (copy) void (^completion)(XGANetworkServiceHost*serviceHost); @end @@ -48,7 +49,7 @@ - (void)netServiceDidResolveAddress:(NSNetService *)service { - (void)netService:(NSNetService *)netService didNotResolve:(NSDictionary *)errorDict { BNCLogDebug(@"Can't resolve %@: %@.", netService, errorDict); -// self.error = [NSError errorWithDomain:NSNetworkDomain code:-1 userInfo:errorDict]; + self.error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorDNSLookupFailed userInfo:errorDict]; } - (void)netServiceDidStop:(NSNetService *)service { diff --git a/xcode-github-app/XGAPreferencesViewController.h b/xcode-github-app/XGAPreferencesViewController.h index e019799..6a42fdb 100644 --- a/xcode-github-app/XGAPreferencesViewController.h +++ b/xcode-github-app/XGAPreferencesViewController.h @@ -10,7 +10,12 @@ #import +NS_ASSUME_NONNULL_BEGIN + @interface XGAPreferencesViewController : NSViewController + (instancetype) new; +- (IBAction)addServerAction:(id _Nullable)sender; @property (strong) IBOutlet NSWindow*window; @end + +NS_ASSUME_NONNULL_END diff --git a/xcode-github-app/XGAPreferencesViewController.m b/xcode-github-app/XGAPreferencesViewController.m index 8dd1519..984c124 100644 --- a/xcode-github-app/XGAPreferencesViewController.m +++ b/xcode-github-app/XGAPreferencesViewController.m @@ -11,10 +11,11 @@ #import "XGAPreferencesViewController.h" #import "XGASettings.h" #import "XGAAddServerPanel.h" +#import @interface XGAPreferencesViewController () @property (strong) IBOutlet XGASettings*settings; -@property (strong) IBOutlet NSArrayController*serverArrayController; +@property (strong) IBOutlet NSDictionaryController*serverDictionaryController; @property (strong) IBOutlet NSTextField*gitHubTokenTextField; @property (strong) IBOutlet NSButton *removeButton; @property (strong) IBOutlet NSTableView *tableView; @@ -31,7 +32,8 @@ + (instancetype) new { loadNibNamed:NSStringFromClass(self) owner:controller topLevelObjects:nil]; - return (loaded) ? controller : nil; + BNCLogAssert(loaded && controller); + return controller; } - (void)awakeFromNib { @@ -40,7 +42,7 @@ - (void)awakeFromNib { if (self.settings) return; self.settings = [XGASettings shared]; self.removeButton.enabled = NO; - self.serverArrayController.content = self.settings.servers; + //self.serverDictionaryController.content = self.settings.servers; self.refreshTimeFormatter.multiplier = @(1.0/60.0); self.refreshTimeFormatter.minimumFractionDigits = 0; self.refreshTimeFormatter.maximumFractionDigits = 0; @@ -53,7 +55,8 @@ - (IBAction)valueChanged:(id)sender { - (void)tableViewSelectionDidChange:(NSNotification *)notification { NSInteger idx = self.tableView.selectedRow; - self.removeButton.enabled = (idx >= 0 && idx < [self.serverArrayController.arrangedObjects count]); + self.removeButton.enabled = + (idx >= 0 && idx < [self.serverDictionaryController.arrangedObjects count]); } - (IBAction)addServerAction:(id)sender { @@ -62,8 +65,10 @@ - (IBAction)addServerAction:(id)sender { - (IBAction)serverDoubleAction:(id)sender { NSInteger idx = self.tableView.selectedRow; - if (idx >= 0 && idx < [self.serverArrayController.arrangedObjects count]) { - XGAServer*server = [self.serverArrayController.arrangedObjects objectAtIndex:idx]; + if (idx >= 0 && idx < [self.serverDictionaryController.arrangedObjects count]) { + NSDictionaryControllerKeyValuePair*pair = + [self.serverDictionaryController.arrangedObjects objectAtIndex:idx]; + XGAServer*server = pair.value; [self showServer:server]; } } @@ -73,9 +78,15 @@ - (void) showServer:(XGAServer*)server { self.addServerPanel = [[XGAAddServerPanel alloc] initWithServer:server]; [self.window beginSheet:self.addServerPanel completionHandler:^(NSModalResponse returnCode) { __auto_type result = self.addServerPanel.server; - if (returnCode == NSModalResponseOK && result.server.length) { - [self.settings.servers addObject:result]; + if (returnCode == NSModalResponseOK && + result.server.length && + self.settings.servers[result.server] == nil) { + self.settings.servers[result.server] = result; [self.settings save]; + NSDictionaryControllerKeyValuePair*pair = [self.serverDictionaryController newObject]; + pair.key = result.server; + pair.value = result; + [self.serverDictionaryController addObject:pair]; } self.addServerPanel = nil; }]; @@ -83,8 +94,8 @@ - (void) showServer:(XGAServer*)server { - (IBAction)removeServerAction:(id)sender { NSInteger idx = self.tableView.selectedRow; - if (idx >= 0 && idx < [self.serverArrayController.arrangedObjects count]) { - [self.serverArrayController removeObjectAtArrangedObjectIndex:idx]; + if (idx >= 0 && idx < [self.serverDictionaryController.arrangedObjects count]) { + [self.serverDictionaryController removeObjectAtArrangedObjectIndex:idx]; [self.settings save]; [self tableViewSelectionDidChange:nil]; } @@ -93,7 +104,7 @@ - (IBAction)removeServerAction:(id)sender { - (IBAction) resetSettingsAction:(id)sender { [self.settings clear]; [self.settings save]; - self.serverArrayController.content = self.settings.servers; + self.serverDictionaryController.content = self.settings.servers; } @end diff --git a/xcode-github-app/XGAPreferencesViewController.xib b/xcode-github-app/XGAPreferencesViewController.xib index 1d75b15..31ba7fb 100644 --- a/xcode-github-app/XGAPreferencesViewController.xib +++ b/xcode-github-app/XGAPreferencesViewController.xib @@ -1,8 +1,8 @@ - + - + @@ -11,7 +11,7 @@ - + @@ -110,6 +110,14 @@ + + + + + + + + @@ -150,22 +158,30 @@ + + + + + + + + - + - diff --git a/xcode-github-app/XGASettings.h b/xcode-github-app/XGASettings.h index feac22f..73ef0cd 100644 --- a/xcode-github-app/XGASettings.h +++ b/xcode-github-app/XGASettings.h @@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN FOUNDATION_EXPORT NSString*_Nonnull XGACleanString(NSString*_Nullable string); -@interface XGAServer : XGServer +@interface XGAServer : XGServer @end #pragma mark XGGitHubSyncTask @@ -37,7 +37,7 @@ FOUNDATION_EXPORT NSString*_Nonnull XGACleanString(NSString*_Nullable string); @property (assign) BOOL showDebugMessages; @property (assign) NSTimeInterval refreshSeconds; @property (copy) NSString*gitHubToken; -@property (strong, null_resettable) NSMutableArray*servers; +@property (strong, null_resettable) NSMutableDictionary*servers; @property (strong, null_resettable) NSMutableArray*gitHubSyncTasks; @end diff --git a/xcode-github-app/XGASettings.m b/xcode-github-app/XGASettings.m index 6dfa2a7..64fed7a 100644 --- a/xcode-github-app/XGASettings.m +++ b/xcode-github-app/XGASettings.m @@ -67,6 +67,14 @@ - (void) encodeWithCoder:(NSCoder *)aCoder { } } +- (id) copyWithZone:(NSZone *)zone { + XGAServer*server = [[XGAServer alloc] init]; + server.server = self.server; + server.user = self.user; + server.password = self.password; + return server; +} + @end #pragma mark - XGAGitHubSyncTask @@ -77,7 +85,7 @@ @implementation XGAGitHubSyncTask #pragma mark - XGASettings @interface XGASettings () { - NSMutableArray*_servers; + NSMutableDictionary*_servers; NSMutableArray*_gitHubSyncTasks; } @end @@ -127,14 +135,14 @@ - (void) setGitHubToken:(NSString *)token { } } -- (NSMutableArray*) servers { +- (NSMutableDictionary*) servers { @synchronized (self) { - if (_servers == nil) _servers = [NSMutableArray new]; + if (_servers == nil) _servers = [NSMutableDictionary new]; return _servers; } } -- (void) setServers:(NSMutableArray*)servers_ { +- (void) setServers:(NSMutableDictionary*)servers_ { @synchronized (self) { _servers = servers_; } @@ -200,20 +208,24 @@ - (void) validate { // Assure that servers are unique: NSMutableDictionary*d = NSMutableDictionary.new; - for (XGAServer*server in self.servers) { - if (server.server.length) d[server.server] = server; + for (XGAServer*server in self.servers.objectEnumerator) { + NSString*name = XGACleanString(server.server); + if (name.length) { + server.server = name; + d[name] = server; + } } [self.servers removeAllObjects]; - [self.servers addObjectsFromArray:d.allValues]; + [self.servers addEntriesFromDictionary:d]; // Assure that tasks are unique: - [d removeAllObjects]; + NSMutableDictionary*t = NSMutableDictionary.new; for (XGAGitHubSyncTask*task in self.gitHubSyncTasks) { NSString*string = [NSString stringWithFormat:@"%@:%@", task.xcodeServer, task.botNameForTemplate]; - d[string] = task; + t[string] = task; } [self.gitHubSyncTasks removeAllObjects]; - [self.gitHubSyncTasks addObjectsFromArray:d.allValues]; + [self.gitHubSyncTasks addObjectsFromArray:t.allValues]; } @end diff --git a/xcode-github-app/XGAStatusViewController.h b/xcode-github-app/XGAStatusViewController.h index 3053ae1..01d043f 100644 --- a/xcode-github-app/XGAStatusViewController.h +++ b/xcode-github-app/XGAStatusViewController.h @@ -10,7 +10,11 @@ #import +NS_ASSUME_NONNULL_BEGIN + @interface XGAStatusViewController : NSViewController + (instancetype) new; @property (strong) IBOutlet NSWindow*window; @end + +NS_ASSUME_NONNULL_END diff --git a/xcode-github-app/XGAStatusViewController.m b/xcode-github-app/XGAStatusViewController.m index 476aed0..e2cc42c 100644 --- a/xcode-github-app/XGAStatusViewController.m +++ b/xcode-github-app/XGAStatusViewController.m @@ -113,6 +113,9 @@ - (IBAction) showInfo:(id)sender { [detail append:status.statusDetail]; if (status.botName.length) [detail italicText:@"\n\nBot: %@", status.botName]; + if (status.branchOrPRName.length) + [detail italicText:@"\nRepo: %@/%@ %@", + status.bot.repoOwner, status.bot.repoName, status.bot.branch]; self.statusPopover.detailTextField.attributedStringValue = [detail renderAttributedStringWithFont:font]; @@ -146,7 +149,7 @@ - (IBAction) monitorRepo:(id)sender { } else { __auto_type task = [XGAGitHubSyncTask new]; - task.xcodeServer = item.bot.serverName; + task.xcodeServer = item.bot.server.server; task.botNameForTemplate = item.botName; [[XGASettings shared].gitHubSyncTasks addObject:task]; @@ -213,6 +216,36 @@ - (IBAction) downloadAssets:(id)sender { [[NSWorkspace sharedWorkspace] openURL:URL]; } +- (IBAction)startStopIntegration:(id)sender { + XGAStatusViewItem*item = [self selectedTableItem]; + if (!item) return; + + BNCPerformBlockAsync(^ { + if (item.botStatus.integrationID != nil && + ![item.botStatus.currentStep isEqualToString:@"completed"]) { + [item.bot cancelIntegrationID:item.botStatus.integrationID]; + } else { + [item.bot startIntegration]; + } + BNCSleepForTimeInterval(0.5); + BNCPerformBlockOnMainThreadSync(^{ + [self reload:nil]; + }); + }); +} + +- (IBAction)showPullRequest:(id)sender { + XGAStatusViewItem*item = [self selectedTableItem]; + if (item.bot.repoOwner == nil || item.bot.repoName == nil || item.bot.pullRequestNumber == nil) + return; + + NSString*string = [NSString stringWithFormat:@"https://github.com/%@/%@/pull/%@", + item.bot.repoOwner, item.bot.repoName, item.bot.pullRequestNumber]; + NSURL*URL = [NSURL URLWithString:string]; + if (!URL) return; + [[NSWorkspace sharedWorkspace] openURL:URL]; +} + - (IBAction)reload:(id)sender { [self updateStatusNow]; } @@ -249,6 +282,24 @@ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem { } return NO; } + XGAStatusViewItem*statusItem = [self selectedTableItem]; + if (menuItem.action == @selector(startStopIntegration:)) { + if (!statusItem) return NO; + if (statusItem.botStatus.integrationID != nil && + ![statusItem.botStatus.currentStep isEqualToString:@"completed"]) + menuItem.title = @"Cancel Integration"; + else + menuItem.title = @"Start Integration"; + return YES; + } + if (menuItem.action == @selector(showPullRequest:)) { + if (statusItem.bot.repoOwner == nil || + statusItem.bot.repoName == nil || + statusItem.bot.pullRequestNumber == nil) + return NO; + return YES; + } + SEL contextMenuItems[] = { @selector(showInfo:), @selector(monitorRepo:), @@ -335,24 +386,30 @@ - (void) updateStatus { BNCLogDebug(@"Start updateStatus."); BNCPerformBlockOnMainThreadAsync(^{ self.statusTextField.stringValue = @""; }); - NSMutableDictionary*statusServers = [NSMutableDictionary new]; - for (XGAServer*server in XGASettings.shared.servers) { - if (server.server.length > 0) - statusServers[server.server] = server; - } + + // Create new bots as needed: NSArray* syncTasks = XGASettings.shared.gitHubSyncTasks; + NSDictionary*statusServers = XGASettings.shared.servers; for (XGAGitHubSyncTask*task in syncTasks) { - if (task.xcodeServer.length == 0 || statusServers[task.xcodeServer] == nil) - continue; - [self updateSyncBots:task]; + if (task.xcodeServer.length != 0 && statusServers[task.xcodeServer] != nil) + [self updateSyncBots:task]; } + + // Update the status: + NSMutableArray *statusArray = [NSMutableArray new]; for (XGAServer*server in statusServers.objectEnumerator) { - [self updateXcodeServerStatus:server]; + NSArray*a = [self updateXcodeServerStatus:server]; + if (a) [statusArray addObjectsFromArray:a]; } - if (syncTasks.count == 0 && statusServers.count == 0) { - // Update with 'nil' to add content for an empty display: - [self updateXcodeServerStatus:nil]; + if (statusArray.count == 0) { + XGAStatusViewItem *status = [XGAStatusViewItem new]; + status.statusImage = [NSImage imageNamed:@"RoundBlue"]; + status.statusSummary = [APFormattedString boldText:@"< No Xcode servers added yet >"]; + [statusArray addObject:status]; } + BNCPerformBlockOnMainThreadAsync(^{ + self.arrayController.content = statusArray; + }); BNCLogDebug(@"End updateStatus."); self.lastUpdateDate = [NSDate date]; @@ -364,10 +421,16 @@ - (void) updateStatus { - (void) updateSyncBots:(XGAGitHubSyncTask*)syncTask { NSError*error = nil; - if (syncTask.xcodeServer.length && - syncTask.botNameForTemplate.length) { + if (syncTask.xcodeServer.length && syncTask.botNameForTemplate.length) { + XGAServer*server = [XGASettings shared].servers[syncTask.xcodeServer]; + if (!server) { + server = [XGAServer new]; + server.server = syncTask.xcodeServer; + } XGCommandOptions*options = [XGCommandOptions new]; - options.xcodeServerName = syncTask.xcodeServer; + options.xcodeServerName = server.server; + options.xcodeServerUser = server.user; + options.xcodeServerPassword = server.password; options.templateBotName = syncTask.botNameForTemplate; options.githubAuthToken = XGASettings.shared.gitHubToken; options.dryRun = XGASettings.shared.dryRun; @@ -387,7 +450,7 @@ - (void) updateSyncBots:(XGAGitHubSyncTask*)syncTask { } } -- (void) updateXcodeServerStatus:(XGServer*)server { +- (NSArray*) updateXcodeServerStatus:(XGServer*)server { NSError*error = nil; NSMutableArray *statusArray = [NSMutableArray new]; if (server.server.length > 0) { @@ -402,20 +465,19 @@ - (void) updateXcodeServerStatus:(XGServer*)server { } else { for (XGXcodeBot *bot in bots.objectEnumerator) { XGXcodeBotStatus*botStatus = [bot status]; - __auto_type item = [XGAStatusViewItem itemWithBot:bot status:botStatus]; + __auto_type item = [XGAStatusViewItem newItemWithBot:bot status:botStatus]; if (item) [statusArray addObject:item]; } } } if (statusArray.count == 0) { XGAStatusViewItem *status = [XGAStatusViewItem new]; + status.server = server.server; status.statusImage = [NSImage imageNamed:@"RoundBlue"]; - status.statusSummary = [APFormattedString boldText:@"< No Xcode servers added yet >"]; + status.statusSummary = [APFormattedString boldText:@"< No Xcode bots found >"]; [statusArray addObject:status]; } - BNCPerformBlockOnMainThreadAsync(^{ - self.arrayController.content = statusArray; - }); + return statusArray; } @end diff --git a/xcode-github-app/XGAStatusViewController.xib b/xcode-github-app/XGAStatusViewController.xib index 271e2fc..9f82e98 100644 --- a/xcode-github-app/XGAStatusViewController.xib +++ b/xcode-github-app/XGAStatusViewController.xib @@ -22,7 +22,7 @@ - + @@ -306,12 +306,26 @@ + + + + + + + + + + + + + + @@ -319,7 +333,7 @@ - + diff --git a/xcode-github-app/XGAStatusViewItem.h b/xcode-github-app/XGAStatusViewItem.h index 0cfc453..f416524 100644 --- a/xcode-github-app/XGAStatusViewItem.h +++ b/xcode-github-app/XGAStatusViewItem.h @@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN @property (copy) NSString*_Nullable templateBotName; @property (copy) NSNumber*_Nullable botIsFromTemplate; -+ (instancetype) itemWithBot:(XGXcodeBot*)bot status:(XGXcodeBotStatus*)botStatus; ++ (instancetype) newItemWithBot:(XGXcodeBot*)bot status:(XGXcodeBotStatus*)botStatus; @property (strong, readonly) XGXcodeBot*_Nullable bot; @property (strong, readonly) XGXcodeBotStatus*_Nullable botStatus; diff --git a/xcode-github-app/XGAStatusViewItem.m b/xcode-github-app/XGAStatusViewItem.m index 200180f..d02f483 100644 --- a/xcode-github-app/XGAStatusViewItem.m +++ b/xcode-github-app/XGAStatusViewItem.m @@ -13,7 +13,7 @@ @implementation XGAStatusViewItem -+ (instancetype) itemWithBot:(XGXcodeBot*)bot status:(XGXcodeBotStatus*)botStatus { ++ (instancetype) newItemWithBot:(XGXcodeBot*)bot status:(XGXcodeBotStatus*)botStatus { if (bot == nil || botStatus == nil) return nil; XGAStatusViewItem *status = [XGAStatusViewItem new]; NSAssert(status, @"Nil XGAStatusViewItem!"); diff --git a/xcode-github-cli.xcodeproj/project.pbxproj b/xcode-github-cli.xcodeproj/project.pbxproj index 9e090ce..a26ee55 100644 --- a/xcode-github-cli.xcodeproj/project.pbxproj +++ b/xcode-github-cli.xcodeproj/project.pbxproj @@ -12,7 +12,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ - 4D7335452097CF6700A0D416 /* xcode-github-cli.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = "xcode-github-cli.md"; path = "xcode-github-cli/xcode-github-cli.md"; sourceTree = ""; }; + 4D7335452097CF6700A0D416 /* xcode-github-cli.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; name = "xcode-github-cli.md"; path = "Documentation/xcode-github-cli.md"; sourceTree = ""; }; 4D744C032047A53B002CA796 /* xcode-github */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "xcode-github"; sourceTree = BUILT_PRODUCTS_DIR; }; 4D744C062047A53B002CA796 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 4DDAA55A216AEC95002F3F8E /* XcodeGitHub.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XcodeGitHub.framework; path = Products/XcodeGitHub.framework; sourceTree = ""; }; @@ -91,12 +91,12 @@ 4D744BFB2047A53B002CA796 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0930; + LastUpgradeCheck = 1030; ORGANIZATIONNAME = Branch; TargetAttributes = { 4D744C022047A53B002CA796 = { CreatedOnToolsVersion = 9.2; - ProvisioningStyle = Automatic; + ProvisioningStyle = Manual; }; }; }; @@ -106,6 +106,7 @@ hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 4D744BFA2047A53B002CA796; productRefGroup = 4D744C042047A53B002CA796 /* Products */; @@ -179,7 +180,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -230,7 +231,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.12; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; }; @@ -239,42 +240,45 @@ 4D744C0B2047A53B002CA796 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_STYLE = Manual; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; - DEVELOPMENT_TEAM = R63EM248DP; + DEVELOPMENT_TEAM = WRWLR8VRUH; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Products", + "$(PROJECT_DIR)/Build", ); INFOPLIST_FILE = "$(SRCROOT)/xcode-github-cli/Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Products", ); - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = "io.branch.xcode-github.command"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Debug; }; 4D744C0C2047A53B002CA796 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - CODE_SIGN_STYLE = Automatic; + CODE_SIGN_IDENTITY = "Mac Developer"; + CODE_SIGN_STYLE = Manual; CREATE_INFOPLIST_SECTION_IN_BINARY = YES; - DEVELOPMENT_TEAM = R63EM248DP; + DEVELOPMENT_TEAM = WRWLR8VRUH; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", - "$(PROJECT_DIR)/Products", + "$(PROJECT_DIR)/Build", ); INFOPLIST_FILE = "$(SRCROOT)/xcode-github-cli/Info.plist"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "$(PROJECT_DIR)/Products", ); - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.12; PRODUCT_BUNDLE_IDENTIFIER = "io.branch.xcode-github.command"; PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; }; name = Release; }; diff --git a/xcode-github-cli.xcodeproj/xcshareddata/xcschemes/xcode-github-cli.xcscheme b/xcode-github-cli.xcodeproj/xcshareddata/xcschemes/xcode-github-cli.xcscheme index 1eb02f6..0c843f0 100644 --- a/xcode-github-cli.xcodeproj/xcshareddata/xcschemes/xcode-github-cli.xcscheme +++ b/xcode-github-cli.xcodeproj/xcshareddata/xcschemes/xcode-github-cli.xcscheme @@ -1,6 +1,6 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0.3 + 1.1.2 CFBundleSignature ???? CFBundleVersion diff --git a/xcode-github-cli/main.m b/xcode-github-cli/main.m index 66167aa..4feb854 100644 --- a/xcode-github-cli/main.m +++ b/xcode-github-cli/main.m @@ -10,7 +10,7 @@ #import #import -#include +#import static BNCLogLevel global_logLevel = BNCLogLevelWarning; diff --git a/xcode-github-tests.xcodeproj/project.pbxproj b/xcode-github-tests.xcodeproj/project.pbxproj index 2d9e818..c83768a 100644 --- a/xcode-github-tests.xcodeproj/project.pbxproj +++ b/xcode-github-tests.xcodeproj/project.pbxproj @@ -240,6 +240,7 @@ hasScannedForEncodings = 0; knownRegions = ( en, + Base, ); mainGroup = 4D262C3F2090FE5800DD80F4; productRefGroup = 4D262C4A2090FE5800DD80F4 /* Products */; @@ -435,7 +436,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = R63EM248DP; + DEVELOPMENT_TEAM = WRWLR8VRUH; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -460,7 +461,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEFINES_MODULE = YES; - DEVELOPMENT_TEAM = R63EM248DP; + DEVELOPMENT_TEAM = WRWLR8VRUH; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; @@ -483,7 +484,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = R63EM248DP; + DEVELOPMENT_TEAM = WRWLR8VRUH; FRAMEWORK_SEARCH_PATHS = "Vendor/**"; HEADER_SEARCH_PATHS = "Vendor/**"; INFOPLIST_FILE = "xcode-github-tests/xcode-github-tests-info.plist"; @@ -502,7 +503,7 @@ buildSettings = { CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; - DEVELOPMENT_TEAM = R63EM248DP; + DEVELOPMENT_TEAM = WRWLR8VRUH; FRAMEWORK_SEARCH_PATHS = "Vendor/**"; HEADER_SEARCH_PATHS = "Vendor/**"; INFOPLIST_FILE = "xcode-github-tests/xcode-github-tests-info.plist"; diff --git a/xcode-github-tests/xcode-github-test-lib-info.plist b/xcode-github-tests/xcode-github-test-lib-info.plist index 017a83a..dd7eab0 100644 --- a/xcode-github-tests/xcode-github-test-lib-info.plist +++ b/xcode-github-tests/xcode-github-test-lib-info.plist @@ -19,7 +19,7 @@ CFBundleVersion $(CURRENT_PROJECT_VERSION) NSHumanReadableCopyright - Copyright © 2018 Branch. All rights reserved. + Copyright © 2018 Branch Metrics. All rights reserved. NSPrincipalClass