Skip to content
Merged
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
33 changes: 27 additions & 6 deletions lib/services/ios/spm-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ export class SPMService implements ISPMService {

const render = () => {
const elapsed = Math.round((Date.now() - startedAt) / 1000);
spinner.text = `${activity}… ${color.dim(`(${elapsed}s)`)}`;
spinner.text = `${activity}… ${color.dim(`(${this.formatElapsed(elapsed)})`)}`;
};
// keep the elapsed timer ticking even when xcodebuild is silent (e.g.
// while a binary artifact downloads) so the user can see it's alive.
Expand Down Expand Up @@ -256,10 +256,10 @@ export class SPMService implements ISPMService {
return "Downloading Swift Package binaries (first build only)";
}
if (/^Fetching\b/i.test(trimmed)) {
return `Fetching ${this.shortenPackageRef(trimmed)}`;
return this.describePackageActivity("Fetching", trimmed);
}
if (/^Cloning\b/i.test(trimmed)) {
return `Cloning ${this.shortenPackageRef(trimmed)}`;
return this.describePackageActivity("Cloning", trimmed);
}
if (/Computing version for/i.test(trimmed)) {
return "Computing package versions";
Expand All @@ -273,18 +273,39 @@ export class SPMService implements ISPMService {
return null;
}

/** Extracts a short, readable name from a SwiftPM repo URL/log line. */
private shortenPackageRef(line: string): string {
/**
* Builds a stable, self-explanatory activity label with the package being
* worked on in parentheses, e.g. "Fetching Swift Packages (Auth0.swift)".
*/
private describePackageActivity(verb: string, line: string): string {
const packageRef = this.shortenPackageRef(line);
return packageRef
? `${verb} Swift Packages (${packageRef})`
: `${verb} Swift Packages`;
}

/**
* Extracts a short, readable name from a SwiftPM repo URL/log line, or null
* when the line contains no URL to name the package by.
*/
private shortenPackageRef(line: string): string | null {
const match = line.match(/https?:\/\/\S+/);
if (!match) {
return "Swift Packages";
return null;
}
return path
.basename(match[0])
.replace(/\.git$/, "")
.replace(/[)\s].*$/, "");
}

/** Formats an elapsed duration in whole seconds as "5m 15s". */
private formatElapsed(totalSeconds: number): string {
const minutes = Math.floor(totalSeconds / 60);
const seconds = totalSeconds % 60;
return `${minutes}m ${seconds}s`;
}

/** True when the Xcode project references any Swift packages. */
private hasSPMReferences(
platformData: IPlatformData,
Expand Down
34 changes: 24 additions & 10 deletions test/spm-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,21 +205,28 @@ describe("SPM Service - resolution log parsing", () => {
);
});

it("summarizes fetching with the package name", () => {
it("summarizes fetching with the package name in parentheses", () => {
assert.equal(
service.describeSPMActivity(
"Fetching from https://github.com/NativeScript/ios-spm.git",
),
"Fetching ios-spm",
"Fetching Swift Packages (ios-spm)",
);
});

it("summarizes cloning with the package name", () => {
it("summarizes cloning with the package name in parentheses", () => {
assert.equal(
service.describeSPMActivity(
"Cloning https://github.com/Alamofire/Alamofire.git",
),
"Cloning Alamofire",
"Cloning Swift Packages (Alamofire)",
);
});

it("omits the parenthesized name when the line has no URL", () => {
assert.equal(
service.describeSPMActivity("Fetching cached package"),
"Fetching Swift Packages",
);
});

Expand Down Expand Up @@ -251,7 +258,7 @@ describe("SPM Service - resolution log parsing", () => {
service.describeSPMActivity(
" Fetching https://github.com/NativeScript/ios-spm.git ",
),
"Fetching ios-spm",
"Fetching Swift Packages (ios-spm)",
);
});

Expand Down Expand Up @@ -286,11 +293,18 @@ describe("SPM Service - resolution log parsing", () => {
);
});

it("falls back to a generic label when there is no URL", () => {
assert.equal(
service.shortenPackageRef("Fetching cached package"),
"Swift Packages",
);
it("returns null when there is no URL", () => {
assert.isNull(service.shortenPackageRef("Fetching cached package"));
});
});

describe("formatElapsed", () => {
it("always renders minutes and seconds", () => {
assert.equal(service.formatElapsed(0), "0m 0s");
assert.equal(service.formatElapsed(42), "0m 42s");
assert.equal(service.formatElapsed(60), "1m 0s");
assert.equal(service.formatElapsed(315), "5m 15s");
assert.equal(service.formatElapsed(3725), "62m 5s");
});
});
});