Skip to content

Commit 25613a6

Browse files
inlinedjoehan
andauthored
Add log lines to clarify what pinning is doing (#5787)
Co-authored-by: joehan <joehanley@google.com>
1 parent f44b1da commit 25613a6

File tree

2 files changed

+54
-7
lines changed

2 files changed

+54
-7
lines changed

src/deploy/hosting/prepare.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ import { FirebaseError } from "../../error";
22
import * as api from "../../hosting/api";
33
import * as config from "../../hosting/config";
44
import * as deploymentTool from "../../deploymentTool";
5+
import * as clc from "colorette";
56
import { Context } from "./context";
67
import { Options } from "../../options";
78
import { HostingOptions } from "../../hosting/options";
89
import { assertExhaustive, zipIn } from "../../functional";
910
import { track } from "../../track";
1011
import * as utils from "../../utils";
11-
import { HostingSource } from "../../firebaseConfig";
12+
import { HostingSource, RunRewrite } from "../../firebaseConfig";
1213
import * as backend from "../functions/backend";
1314
import { ensureTargeted } from "../../functions/ensureTargeted";
1415

@@ -60,8 +61,9 @@ export async function addPinnedFunctionsToOnlyString(
6061
// a scalar to an array now
6162
handlePublicDirectoryFlag(options);
6263

63-
let addedFunctions = false;
64+
const addedFunctions: string[] = [];
6465
for (const c of config.hostingConfig(options)) {
66+
const addedFunctionsPerSite: string[] = [];
6567
for (const r of c.rewrites || []) {
6668
if (!("function" in r) || typeof r.function !== "object" || !r.function.pinTag) {
6769
continue;
@@ -76,10 +78,19 @@ export async function addPinnedFunctionsToOnlyString(
7678
// This endpoint is just being added in this push. We don't know what codebase it is.
7779
options.only = ensureTargeted(options.only, r.function.functionId);
7880
}
79-
addedFunctions = true;
81+
addedFunctionsPerSite.push(r.function.functionId);
82+
}
83+
if (addedFunctionsPerSite.length) {
84+
utils.logLabeledBullet(
85+
"hosting",
86+
"The following function(s) are pinned to site " +
87+
`${clc.bold(c.site)} and will be deployed as well: ` +
88+
addedFunctionsPerSite.map(clc.bold).join(",")
89+
);
90+
addedFunctions.push(...addedFunctionsPerSite);
8091
}
8192
}
82-
return addedFunctions;
93+
return addedFunctions.length !== 0;
8394
}
8495

8596
/**
@@ -103,10 +114,24 @@ export async function prepare(context: Context, options: HostingOptions & Option
103114
}
104115
const unsafe = await unsafePins(context, config);
105116
if (unsafe.length) {
106-
const msg = `Cannot deploy site ${config.site} to channel ${context.hostingChannel} because it would modify one or more rewrites in "live" that are not pinned, breaking production. Please pin "live" before pinning other channels.`;
117+
const msg =
118+
`Cannot deploy site ${clc.bold(config.site)} to channel ` +
119+
`${clc.bold(context.hostingChannel!)} because it would modify one or ` +
120+
`more rewrites in "live" that are not pinned, breaking production. ` +
121+
`Please pin "live" before pinning other channels.`;
107122
utils.logLabeledError("Hosting", msg);
108123
throw new Error(msg);
109124
}
125+
const runPins = config.rewrites
126+
?.filter((r) => "run" in r && r.run.pinTag)
127+
?.map((r) => (r as RunRewrite).run.serviceId);
128+
if (runPins?.length) {
129+
utils.logLabeledBullet(
130+
"hosting",
131+
`The site ${clc.bold(config.site)} will pin rewrites to the current ` +
132+
`latest revision of service(s) ${runPins.map(clc.bold).join(",")}`
133+
);
134+
}
110135
const version: Omit<api.Version, api.VERSION_OUTPUT_FIELDS> = {
111136
status: "CREATED",
112137
labels,

src/test/deploy/hosting/prepare.spec.ts

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { expect } from "chai";
22
import * as sinon from "sinon";
3+
import * as clc from "colorette";
34

45
import { FirebaseConfig } from "../../../firebaseConfig";
56
import { HostingOptions } from "../../../hosting/options";
@@ -9,6 +10,7 @@ import * as hostingApi from "../../../hosting/api";
910
import * as tracking from "../../../track";
1011
import * as deploymentTool from "../../../deploymentTool";
1112
import * as config from "../../../hosting/config";
13+
import * as utils from "../../../utils";
1214
import {
1315
addPinnedFunctionsToOnlyString,
1416
hasPinnedFunctions,
@@ -22,6 +24,7 @@ describe("hosting prepare", () => {
2224
let hostingStub: sinon.SinonStubbedInstance<typeof hostingApi>;
2325
let trackingStub: sinon.SinonStubbedInstance<typeof tracking>;
2426
let backendStub: sinon.SinonStubbedInstance<typeof backend>;
27+
let loggerStub: sinon.SinonStub;
2528
let siteConfig: config.HostingResolved;
2629
let firebaseJson: FirebaseConfig;
2730
let options: HostingOptions & Options;
@@ -30,13 +33,21 @@ describe("hosting prepare", () => {
3033
hostingStub = sinon.stub(hostingApi);
3134
trackingStub = sinon.stub(tracking);
3235
backendStub = sinon.stub(backend);
36+
loggerStub = sinon.stub(utils, "logLabeledBullet");
3337

3438
// We're intentionally using pointer references so that editing site
3539
// edits the results of hostingConfig() and changes firebase.json
3640
siteConfig = {
3741
site: "site",
3842
public: ".",
3943
rewrites: [
44+
{
45+
glob: "run",
46+
run: {
47+
serviceId: "service",
48+
pinTag: true,
49+
},
50+
},
4051
{
4152
glob: "**",
4253
function: {
@@ -103,6 +114,11 @@ describe("hosting prepare", () => {
103114
},
104115
],
105116
});
117+
expect(loggerStub).to.have.been.calledWith(
118+
"hosting",
119+
`The site ${clc.bold("site")} will pin rewrites to the current latest ` +
120+
`revision of service(s) ${clc.bold("service")}`
121+
);
106122
});
107123

108124
it("passes a smoke test without web framework", async () => {
@@ -254,10 +270,11 @@ describe("hosting prepare", () => {
254270

255271
it("detects a lack of function tags", () => {
256272
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
257-
delete (options as any).config.src.hosting?.rewrites?.[0]?.function?.pinTag;
273+
delete (options as any).config.src.hosting?.rewrites?.[1]?.function?.pinTag;
258274
expect(hasPinnedFunctions(options)).to.be.false;
259275
});
260276
});
277+
261278
describe("addPinnedFunctionsToOnlyString", () => {
262279
it("adds functions to deploy targets w/ codebases", async () => {
263280
backendStub.existingBackend.resolves({
@@ -276,6 +293,11 @@ describe("hosting prepare", () => {
276293

277294
await expect(addPinnedFunctionsToOnlyString({} as any, options)).to.eventually.be.true;
278295
expect(options.only).to.equal("hosting,functions:backend:function");
296+
expect(loggerStub).to.have.been.calledWith(
297+
"hosting",
298+
`The following function(s) are pinned to site ${clc.bold("site")} ` +
299+
`and will be deployed as well: ${clc.bold("function")}`
300+
);
279301
});
280302

281303
it("adds functions to deploy targets w/o codebases", async () => {
@@ -298,7 +320,7 @@ describe("hosting prepare", () => {
298320

299321
it("doesn't add untagged functions", async () => {
300322
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
301-
delete (siteConfig as any).rewrites[0].function.pinTag;
323+
delete (siteConfig as any).rewrites[1].function.pinTag;
302324

303325
await expect(addPinnedFunctionsToOnlyString({} as any, options)).to.eventually.be.false;
304326
expect(options.only).to.equal("hosting");

0 commit comments

Comments
 (0)