Skip to content
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
40 changes: 40 additions & 0 deletions src/deploy/functions/release/fabricator.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1598,6 +1598,46 @@ describe("Fabricator", () => {
expect(results[0].error).to.be.instanceOf(reporter.DeploymentError);
expect(results[0].error?.message).to.match(/create function/);
});
it("uses different scrapers for different codebases", async () => {
const ep1 = endpoint({ httpsTrigger: {} }, { codebase: "codebaseA" });
const ep2 = endpoint({ httpsTrigger: {} }, { codebase: "codebaseB" });
const plan: planner.DeploymentPlan = {
"us-central1": {
endpointsToCreate: [ep1],
endpointsToUpdate: [],
endpointsToDelete: [],
endpointsToSkip: [],
},
"us-west1": {
endpointsToCreate: [ep2],
endpointsToUpdate: [],
endpointsToDelete: [],
endpointsToSkip: [],
},
};

const applyUpsertsSpy = sinon.spy(fab, "applyUpserts");

sinon.stub(fab, "createEndpoint").resolves();
sinon.stub(fab, "updateEndpoint").resolves();
sinon.stub(fab, "deleteEndpoint").resolves();

await fab.applyPlan(plan);

expect(applyUpsertsSpy.calledTwice).to.be.true;

const call1 = applyUpsertsSpy.getCall(0);
const call2 = applyUpsertsSpy.getCall(1);

const scraperV1Call1 = call1.args[1];
const scraperV2Call1 = call1.args[2];

const scraperV1Call2 = call2.args[1];
const scraperV2Call2 = call2.args[2];

expect(scraperV1Call1).to.not.equal(scraperV1Call2);
expect(scraperV2Call1).to.not.equal(scraperV2Call2);
});
});

describe("getLogSuccessMessage", () => {
Expand Down
31 changes: 28 additions & 3 deletions src/deploy/functions/release/fabricator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,35 @@ export class Fabricator {
const changesets = Object.values(plan);

// Phase 1: Creates and Updates
const scraperV1 = new SourceTokenScraper();
const scraperV2 = new SourceTokenScraper();
const scrapersV1 = new Map<string, SourceTokenScraper>();
const scrapersV2 = new Map<string, SourceTokenScraper>();

const createAndUpdatePromises = changesets.map((changes) => {
return this.applyUpserts(changes, scraperV1, scraperV2);
// Find codebase from endpoints in changeset
let codebase = "default";
if (changes.endpointsToCreate.length > 0) {
codebase = changes.endpointsToCreate[0].codebase || "default";
} else if (changes.endpointsToUpdate.length > 0) {
codebase = changes.endpointsToUpdate[0].endpoint.codebase || "default";
} else if (changes.endpointsToDelete.length > 0) {
codebase = changes.endpointsToDelete[0].codebase || "default";
} else if (changes.endpointsToSkip.length > 0) {
codebase = changes.endpointsToSkip[0].codebase || "default";
}

let scraperV1 = scrapersV1.get(codebase);
if (!scraperV1) {
scraperV1 = new SourceTokenScraper();
scrapersV1.set(codebase, scraperV1);
}

let scraperV2 = scrapersV2.get(codebase);
if (!scraperV2) {
scraperV2 = new SourceTokenScraper();
scrapersV2.set(codebase, scraperV2);
}

return this.applyUpserts(changes, scraperV1!, scraperV2!);
Comment on lines +107 to +130
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The logic for extracting the codebase and initializing the scrapers can be significantly simplified. Using optional chaining and the nullish coalescing operator reduces boilerplate and eliminates the need for non-null assertions (!), making the code more maintainable and readable.

      const codebase =
        changes.endpointsToCreate[0]?.codebase ||
        changes.endpointsToUpdate[0]?.endpoint.codebase ||
        changes.endpointsToDelete[0]?.codebase ||
        changes.endpointsToSkip[0]?.codebase ||
        "default";

      const scraperV1 = scrapersV1.get(codebase) ?? new SourceTokenScraper();
      scrapersV1.set(codebase, scraperV1);
      const scraperV2 = scrapersV2.get(codebase) ?? new SourceTokenScraper();
      scrapersV2.set(codebase, scraperV2);

      return this.applyUpserts(changes, scraperV1, scraperV2);
References
  1. The repository style guide recommends reducing nesting as much as possible and folding edge cases into the general case to improve clarity. (link)

});
const createAndUpdateResultsArray = await Promise.allSettled(createAndUpdatePromises);

Expand Down