Skip to content

Feature/Custom Bot Status Messages #12

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Open
wants to merge 13 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
File renamed without changes.
50 changes: 50 additions & 0 deletions Tools/xcode-coverage-report
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/bash
function printHelp() {
cat <<HELP
Usage: xcode-coverage-report [ -h ] | [ <build-directory> ]

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")
4 changes: 3 additions & 1 deletion XcodeGitHub/XGCommand.m
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,12 @@
message:message
statusURL:nil];
if (error) return error;



// Add a completion message to the PR:
if ([botStatus.currentStep isEqualToString:@"completed"]) {
error = [pr addComment:[botStatus.formattedDetailString renderMarkDown]];
error = [pr addComment:[[botStatus formatDetailString:options.successMessage :options.failureMessage :options.perfectMessage] renderMarkDown]];
if (error) return error;
}

Expand Down
3 changes: 3 additions & 0 deletions XcodeGitHub/XGCommandOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ NS_ASSUME_NONNULL_BEGIN
@property (copy) NSString*_Nullable xcodeServerPassword; // Optional
@property (copy) NSString*_Nullable templateBotName;
@property (copy) NSString*_Nullable githubAuthToken;
@property (copy) NSString*_Nullable successMessage;
@property (copy) NSString*_Nullable failureMessage;
@property (copy) NSString*_Nullable perfectMessage;
@property (assign) int verbosity;
@property (assign) BOOL dryRun;
@property (assign) BOOL showStatusOnly;
Expand Down
14 changes: 14 additions & 0 deletions XcodeGitHub/XGCommandOptions.m
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ - (instancetype _Nonnull) initWithArgc:(int)argc argv:(char*const _Nullable[_Nul
{"verbose", no_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
{"xcodeserver", required_argument, NULL, 'x'},
{"successmessage", no_argument, NULL, 'S'},
{"failuremessage", no_argument, NULL, 'F'},
{"perfectmessage", no_argument, NULL, 'P'},
{0, 0, 0, 0}
};

Expand All @@ -54,6 +57,9 @@ - (instancetype _Nonnull) initWithArgc:(int)argc argv:(char*const _Nullable[_Nul
case 'v': self.verbosity++; break;
case 'V': self.showVersion = YES; break;
case 'x': self.xcodeServerName = [self.class stringFromParameter]; break;
case 'S': self.successMessage = [self.class stringFromParameter]; break;
case 'F': self.failureMessage = [self.class stringFromParameter]; break;
case 'P': self.perfectMessage = [self.class stringFromParameter]; break;
default: self.badOptionsError = YES; break;
}
} while (c != -1 && !self.badOptionsError);
Expand Down Expand Up @@ -107,6 +113,14 @@ + (NSString*) helpString {
"\n"
" -x, --xcodeserver <xcode-server-domain-name>\n"
" The network name of the xcode server.\n"
" -S, --successmessage <custom-message>\n"
" Optional custom integration success message.\n"
"\n"
" -F, --failuremessage <custom-message>\n"
" Optional custom integration failure message.\n"
"\n"
" -P, --perfectmessage <custom-message>\n"
" Optional custom perfect integration message.\n"
"\n"
"The tool returns 0 on success, otherwise a non-zero value.\n"
"\n"
Expand Down
3 changes: 2 additions & 1 deletion XcodeGitHub/XGXcodeBot.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,11 @@ NS_ASSUME_NONNULL_BEGIN
@property (strong, readonly) NSArray<NSString*>*_Nullable tags;

@property (strong, readonly) NSString* summaryString;
@property (strong, readonly) APFormattedString* formattedDetailString;

@property (strong, readonly) NSURL* integrationLogURL;

- (APFormattedString*) formatDetailString:(NSString*_Nullable) successMessage : (NSString*_Nullable) failureMessage : (NSString*_Nullable) perfectMessage;

- (instancetype) initWithServerName:(NSString*_Nullable)serverName
dictionary:(NSDictionary*_Nullable)dictionary
NS_DESIGNATED_INITIALIZER;
Expand Down
221 changes: 117 additions & 104 deletions XcodeGitHub/XGXcodeBot.m
Original file line number Diff line number Diff line change
Expand Up @@ -132,112 +132,125 @@ - (NSString*) summaryString {
_Test Coverage_: 65% (193 tests).
*/

- (APFormattedString*) formattedDetailString {
- (APFormattedString*) formatDetailString:(NSString*_Nullable)successMessage :(NSString*_Nullable) failureMessage :(NSString*_Nullable)perfectMessage {
NSTimeInterval duration = [self.endedDate timeIntervalSinceDate:self.startedDate];
NSString*durationString = XGDurationStringFromTimeInterval(duration);

APFormattedString *apstring =
[[[[APFormattedString
plainText:@"Result of Integration %@", self.integrationNumber]
line]
italicText:@"Duration"]
plainText:@": %@\n", durationString];

if ([self.result isEqualToString:@"canceled"]) {
[[[apstring
plainText:@"Build was "]
boldText:@"**manually canceled**"]
plainText:@"."];
return apstring;
}
NSString*durationString = XGDurationStringFromTimeInterval(duration);

APFormattedString *apstring =
[[[[APFormattedString
plainText:@"Result of Integration %@", self.integrationNumber]
line]
italicText:@"Duration"]
plainText:@": %@\n", durationString];

if ([self.result isEqualToString:@"canceled"]) {
[[[apstring
plainText:@"Build was "]
boldText:@"**manually canceled**"]
plainText:@"."];
return apstring;
}

[[apstring
italicText:@"Result"]
plainText:@": "];

if ([self.errorCount integerValue] > 0) {
[[[apstring
boldText:@"%@ errors, failing state: %@", self.errorCount, self.summaryString]
plainText:@"\n%@", failureMessage]
line];
return apstring;
}

if ([self.testFailureCount integerValue] > 0) {
[[[[apstring
plainText:@"%@", failureMessage]
line]
boldText:@"Build failed %@ tests", self.testFailureCount]
plainText:@" out of %@", self.testsCount];
return apstring;
}

if ([self.testsCount integerValue] > 0 &&
[self.warningCount integerValue] > 0 &&
[self.analyzerWarningCount integerValue] > 0) {
[[[[[apstring
plainText:@"All %@ tests passed, but please ", self.testsCount]
boldText:@"fix %@ warnings", self.warningCount]
plainText:@" and "]
boldText:@"%@ analyzer warnings", self.analyzerWarningCount]
plainText:@"."];
if ([self.codeCoveragePercentage doubleValue] > 0) {
[[apstring
italicText:@"\nTest Coverage"]
plainText:@": %@%%", self.codeCoveragePercentage];
}
[[apstring plainText:@"\n%@", successMessage] line];
return apstring;
}

if ([self.testsCount integerValue] > 0 &&
[self.warningCount integerValue] > 0) {
[[apstring
plainText:@"All %@ tests passed, but please ", self.testsCount]
boldText:@"fix %@ warnings.", self.warningCount];
if ([self.codeCoveragePercentage doubleValue] > 0) {
[[apstring
italicText:@"\nTest Coverage"]
plainText:@": %@%%", self.codeCoveragePercentage];
}
[[apstring plainText:@"\n%@", successMessage] line];
return apstring;
}

if ([self.testsCount integerValue] > 0 &&
[self.analyzerWarningCount integerValue] > 0) {
[[apstring
plainText:@"All %@ tests passed, but please ", self.testsCount]
boldText:@"fix %@ analyzer warnings.", self.analyzerWarningCount];
if ([self.codeCoveragePercentage doubleValue] > 0) {
[[apstring
italicText:@"\nTest Coverage"]
plainText:@": %@%%", self.codeCoveragePercentage];
}
return apstring;
}

[[apstring
italicText:@"Result"]
plainText:@": "];

if ([self.errorCount integerValue] > 0) {
[apstring boldText:@"%@ errors, failing state: %@", self.errorCount, self.summaryString];
return apstring;
}

if ([self.testFailureCount integerValue] > 0) {
[[apstring boldText:@"Build failed %@ tests", self.testFailureCount]
plainText:@" out of %@", self.testsCount];
return apstring;
}

if ([self.testsCount integerValue] > 0 &&
[self.warningCount integerValue] > 0 &&
[self.analyzerWarningCount integerValue] > 0) {
[[[[[apstring
plainText:@"All %@ tests passed, but please ", self.testsCount]
boldText:@"fix %@ warnings", self.warningCount]
plainText:@" and "]
boldText:@"%@ analyzer warnings", self.analyzerWarningCount]
plainText:@"."];
if ([self.codeCoveragePercentage doubleValue] > 0) {
[[apstring
italicText:@"\nTest Coverage"]
plainText:@": %@%%", self.codeCoveragePercentage];
}
return apstring;
}

if ([self.testsCount integerValue] > 0 &&
[self.warningCount integerValue] > 0) {
[[apstring
plainText:@"All %@ tests passed, but please ", self.testsCount]
boldText:@"fix %@ warnings.", self.warningCount];
if ([self.codeCoveragePercentage doubleValue] > 0) {
[[apstring
italicText:@"\nTest Coverage"]
plainText:@": %@%%", self.codeCoveragePercentage];
}
return apstring;
}

if ([self.testsCount integerValue] > 0 &&
[self.analyzerWarningCount integerValue] > 0) {
[[apstring
plainText:@"All %@ tests passed, but please ", self.testsCount]
boldText:@"fix %@ analyzer warnings.", self.analyzerWarningCount];
if ([self.codeCoveragePercentage doubleValue] > 0) {
[[apstring
italicText:@"\nTest Coverage"]
plainText:@": %@%%", self.codeCoveragePercentage];
}
return apstring;
}

if ([self.errorCount integerValue] == 0 && [self.result isEqualToString:@"succeeded"]) {
if (self.testsCount.integerValue == 0) {
[apstring boldText:@"Perfect build! 👍"];
} else {
if (self.testFailureCount.integerValue == 0) {
[apstring boldText:@"Perfect build!"];
[apstring plainText:@" All %ld tests passed. 👍\n", (long) self.testsCount.integerValue];
if (self.codeCoveragePercentage.doubleValue > 0.0) {
[[apstring
italicText:@"Test Coverage"]
plainText:@": %@%%", self.codeCoveragePercentage];
}
} else {
[apstring boldText:@"Perfect build!"];
[apstring plainText:@" But please fix %ld failing tests.\n", (long) self.testFailureCount.integerValue];
[[apstring
italicText:@"Test Coverage"]
plainText:@": %@%% (%@ tests).", self.codeCoveragePercentage, self.testsCount];
}
}
return apstring;
}

[apstring boldText:@"Failing state: %@.", self.summaryString];
if ([self.tags containsObject:@"xcs-upgrade"]) {
[apstring italicText:@"\nThe current configuration may not be supported by the Xcode upgrade."];
}

return apstring;
if ([self.testsCount integerValue] == 0) {
[apstring boldText:@"Build Succeeded"];
[apstring plainText:@"\nNo tests ran on this integration"];
[apstring plainText:@"\n%@", successMessage];
return apstring;
}

if ([self.errorCount integerValue] == 0 && [self.result isEqualToString:@"succeeded"]) {
if (self.testFailureCount.integerValue == 0) {
[apstring boldText:@"Perfect build!"];
[apstring plainText:@" All %ld tests passed. 👍\n", (long) self.testsCount.integerValue];
if (self.codeCoveragePercentage.doubleValue > 0.0) {
[[apstring
italicText:@"Test Coverage"]
plainText:@": %@%%", self.codeCoveragePercentage];
}
} else {
[apstring boldText:@"Perfect build!"];
[apstring plainText:@" But please fix %ld failing tests.\n", (long) self.testFailureCount.integerValue];
[[apstring
italicText:@"Test Coverage"]
plainText:@": %@%% (%@ tests).", self.codeCoveragePercentage, self.testsCount];
}
[apstring plainText:@"\n%@", perfectMessage];
return apstring;
}

[apstring boldText:@"Failing state: %@.", self.summaryString];
[apstring plainText:@"\n%@", failureMessage];
if ([self.tags containsObject:@"xcs-upgrade"]) {
[apstring italicText:@"\nThe current configuration may not be supported by the Xcode upgrade."];
}

return apstring;
}

- (NSURL*) integrationLogURL {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
<dict>
<key>PreviewsEnabled</key>
<false/>
</dict>
</plist>
Loading