diff --git a/src/schematics/deploy/actions.spec.ts b/src/schematics/deploy/actions.spec.ts index 24be1aace..31ab0174b 100644 --- a/src/schematics/deploy/actions.spec.ts +++ b/src/schematics/deploy/actions.spec.ts @@ -9,6 +9,7 @@ let firebaseMock: FirebaseTools; const FIREBASE_PROJECT = 'ikachu-aa3ef'; const PROJECT = 'pirojok-project'; +const BUILD_TARGET = `${PROJECT}:build:production`; describe('Deploy Angular apps', () => { beforeEach(() => initMocks()); @@ -16,7 +17,7 @@ describe('Deploy Angular apps', () => { it('should check if the user is authenticated by invoking list', async () => { const spy = spyOn(firebaseMock, 'list'); const spyLogin = spyOn(firebaseMock, 'login'); - await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT); + await deploy(firebaseMock, context, 'host', BUILD_TARGET, FIREBASE_PROJECT); expect(spy).toHaveBeenCalled(); expect(spyLogin).not.toHaveBeenCalled(); }); @@ -25,14 +26,14 @@ describe('Deploy Angular apps', () => { firebaseMock.list = () => Promise.reject(); const spy = spyOn(firebaseMock, 'list').and.callThrough(); const spyLogin = spyOn(firebaseMock, 'login'); - await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT); + await deploy(firebaseMock, context, 'host', BUILD_TARGET, FIREBASE_PROJECT); expect(spy).toHaveBeenCalled(); expect(spyLogin).toHaveBeenCalled(); }); it('should invoke the builder', async () => { const spy = spyOn(context, 'scheduleTarget').and.callThrough(); - await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT); + await deploy(firebaseMock, context, 'host', BUILD_TARGET, FIREBASE_PROJECT); expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledWith({ target: 'build', @@ -41,9 +42,17 @@ describe('Deploy Angular apps', () => { }); }); + it('should allow the buildTarget to be specified', async () => { + const buildTarget = `${PROJECT}:prerender`; + const spy = spyOn(context, 'scheduleTarget').and.callThrough(); + await deploy(firebaseMock, context, 'host', buildTarget, FIREBASE_PROJECT); + expect(spy).toHaveBeenCalled(); + expect(spy).toHaveBeenCalledWith({ target: 'prerender', project: PROJECT }); + }); + it('should invoke firebase.deploy', async () => { const spy = spyOn(firebaseMock, 'deploy').and.callThrough(); - await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT); + await deploy(firebaseMock, context, 'host', BUILD_TARGET, FIREBASE_PROJECT); expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalledWith({ cwd: 'host', only: 'hosting:' + PROJECT @@ -53,7 +62,7 @@ describe('Deploy Angular apps', () => { describe('error handling', () => { it('throws if there is no firebase project', async () => { try { - await deploy(firebaseMock, context, 'host') + await deploy(firebaseMock, context, 'host', BUILD_TARGET) fail(); } catch (e) { expect(e.message).toMatch(/Cannot find firebase project/); @@ -63,7 +72,7 @@ describe('Deploy Angular apps', () => { it('throws if there is no target project', async () => { context.target = undefined; try { - await deploy(firebaseMock, context, 'host', FIREBASE_PROJECT) + await deploy(firebaseMock, context, 'host', BUILD_TARGET, FIREBASE_PROJECT) fail(); } catch (e) { expect(e.message).toMatch(/Cannot execute the build target/); @@ -103,4 +112,4 @@ const initMocks = () => { scheduleBuilder: (_: string, __?: JsonObject, ___?: ScheduleOptions) => Promise.resolve({} as BuilderRun), scheduleTarget: (_: Target, __?: JsonObject, ___?: ScheduleOptions) => Promise.resolve({} as BuilderRun) }; -}; \ No newline at end of file +}; diff --git a/src/schematics/deploy/actions.ts b/src/schematics/deploy/actions.ts index 516fbf651..61d43506d 100644 --- a/src/schematics/deploy/actions.ts +++ b/src/schematics/deploy/actions.ts @@ -1,11 +1,12 @@ -import { BuilderContext } from "@angular-devkit/architect"; +import { BuilderContext, targetFromTargetString } from "@angular-devkit/architect"; import { FirebaseTools } from "../interfaces"; export default async function deploy( firebaseTools: FirebaseTools, context: BuilderContext, projectRoot: string, - firebaseProject?: string + buildTarget: string, + firebaseProject?: string, ) { if (!firebaseProject) { throw new Error("Cannot find firebase project for your app in .firebaserc"); @@ -25,11 +26,7 @@ export default async function deploy( context.logger.info(`📦 Building "${context.target.project}"`); - const run = await context.scheduleTarget({ - target: "build", - project: context.target.project, - configuration: "production" - }); + const run = await context.scheduleTarget(targetFromTargetString(buildTarget)); await run.result; try { diff --git a/src/schematics/deploy/builder.ts b/src/schematics/deploy/builder.ts index 7d3038d56..12a28e247 100644 --- a/src/schematics/deploy/builder.ts +++ b/src/schematics/deploy/builder.ts @@ -5,14 +5,17 @@ import { } from "@angular-devkit/architect"; import { NodeJsSyncHost } from "@angular-devkit/core/node"; import deploy from "./actions"; -import { experimental, normalize } from "@angular-devkit/core"; +import { experimental, normalize, json } from "@angular-devkit/core"; +import { DeployBuilderSchema } from '../interfaces'; import * as path from "path"; import { getFirebaseProjectName } from "../utils"; +type DeployBuilderOptions = DeployBuilderSchema & json.JsonObject; + // Call the createBuilder() function to create a builder. This mirrors // createJobHandler() but add typings specific to Architect Builders. export default createBuilder( - async (_: any, context: BuilderContext): Promise => { + async (options: DeployBuilderOptions, context: BuilderContext): Promise => { // The project root is added to a BuilderContext. const root = normalize(context.workspaceRoot); const workspace = new experimental.workspace.Workspace( @@ -34,11 +37,14 @@ export default createBuilder( context.target.project ); + const buildTarget = options.buildTarget || `build:${context.target.project}:production`; + try { await deploy( require("firebase-tools"), context, path.join(context.workspaceRoot, project.root), + buildTarget, firebaseProject ); } catch (e) { diff --git a/src/schematics/deploy/schema.json b/src/schematics/deploy/schema.json index 566c4cd39..bcc2e088b 100644 --- a/src/schematics/deploy/schema.json +++ b/src/schematics/deploy/schema.json @@ -1,6 +1,13 @@ { + "$schema": "http://json-schema.org/draft-07/schema", "id": "FirebaseDeploySchema", "title": "Firebase Deploy", - "description": "TBD", - "properties": {} + "description": "Ng Deploy target options for Firebase.", + "properties": { + "buildTarget": { + "type": "string", + "description": "Target to build.", + "pattern": "^[^:\\s]+:[^:\\s]+(:[^\\s]+)?$" + } + } } diff --git a/src/schematics/interfaces.ts b/src/schematics/interfaces.ts index a5d98e038..0ab0cde92 100644 --- a/src/schematics/interfaces.ts +++ b/src/schematics/interfaces.ts @@ -42,3 +42,7 @@ export interface FirebaseRcTarget { export interface FirebaseRc { targets?: Record; } + +export interface DeployBuilderSchema { + buildTarget?: string; +}