├── .all-contributorsrc ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── nodejs.yml │ └── npm-publish.yml ├── .gitignore ├── LICENSE ├── README.md ├── renovate.json ├── screenshots ├── api-id.png ├── personal-access-token.png ├── step-1.png └── step-2.png └── src ├── .editorconfig ├── README.md ├── builders.json ├── collection.json ├── deploy ├── index.ts ├── schema.d.ts └── schema.json ├── index.ts ├── interfaces.ts ├── ng-add ├── index.ts └── schema.json ├── package.json └── tsconfig.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "contributors": [ 8 | { 9 | "login": "nitishk72", 10 | "name": "Nitish Kumar Singh", 11 | "avatar_url": "https://avatars2.githubusercontent.com/u/15886737?v=4", 12 | "profile": "https://www.youtube.com/c/NitishKumarSingh", 13 | "contributions": [ 14 | "code" 15 | ] 16 | }, 17 | { 18 | "login": "Shaikh-Ubaid", 19 | "name": "Shaikh-Ubaid", 20 | "avatar_url": "https://avatars2.githubusercontent.com/u/43722035?v=4", 21 | "profile": "https://github.com/Shaikh-Ubaid", 22 | "contributions": [ 23 | "doc" 24 | ] 25 | }, 26 | { 27 | "login": "iamsurajdc", 28 | "name": "Suraj Chandgude", 29 | "avatar_url": "https://avatars0.githubusercontent.com/u/32074031?v=4", 30 | "profile": "https://iamsurajdc.js.org", 31 | "contributions": [ 32 | "code" 33 | ] 34 | }, 35 | { 36 | "login": "santoshyadav198613", 37 | "name": "Santosh Yadav", 38 | "avatar_url": "https://avatars3.githubusercontent.com/u/11923975?v=4", 39 | "profile": "https://www.santoshyadav.dev", 40 | "contributions": [ 41 | "code" 42 | ] 43 | }, 44 | { 45 | "login": "alan-agius4", 46 | "name": "Alan Agius", 47 | "avatar_url": "https://avatars3.githubusercontent.com/u/17563226?v=4", 48 | "profile": "https://github.com/alan-agius4", 49 | "contributions": [ 50 | "code" 51 | ] 52 | }, 53 | { 54 | "login": "imranmomin", 55 | "name": "Imran Momin", 56 | "avatar_url": "https://avatars3.githubusercontent.com/u/6071075?v=4", 57 | "profile": "https://github.com/imranmomin", 58 | "contributions": [ 59 | "code" 60 | ] 61 | }, 62 | { 63 | "login": "BioPhoton", 64 | "name": "Michael Hladky", 65 | "avatar_url": "https://avatars1.githubusercontent.com/u/10064416?v=4", 66 | "profile": "https://github.com/BioPhoton", 67 | "contributions": [ 68 | "code" 69 | ] 70 | }, 71 | { 72 | "login": "NileshPatel17", 73 | "name": "Nilesh Patel", 74 | "avatar_url": "https://avatars2.githubusercontent.com/u/27020381?v=4", 75 | "profile": "https://github.com/NileshPatel17", 76 | "contributions": [ 77 | "doc" 78 | ] 79 | }, 80 | { 81 | "login": "joshuamorony", 82 | "name": "Josh Morony", 83 | "avatar_url": "https://avatars.githubusercontent.com/u/2578009?v=4", 84 | "profile": "https://www.joshmorony.com", 85 | "contributions": [ 86 | "code" 87 | ] 88 | } 89 | ], 90 | "contributorsPerLine": 7, 91 | "projectName": "netlify-builder", 92 | "projectOwner": "ngx-builders", 93 | "repoType": "github", 94 | "repoHost": "https://github.com", 95 | "skipCi": true 96 | } 97 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | defaults: 17 | run: 18 | working-directory: ./src 19 | strategy: 20 | matrix: 21 | node-version: [14.x] 22 | 23 | steps: 24 | - uses: actions/checkout@v2 25 | - name: Use Node.js ${{ matrix.node-version }} 26 | uses: actions/setup-node@v1 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | - run: npm install 30 | - run: npm run build 31 | env: 32 | CI: true 33 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/publishing-nodejs-packages 3 | 4 | name: Node.js Package 5 | 6 | on: 7 | push: 8 | branches: 9 | - 'release/**' 10 | release: 11 | types: [created] 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - uses: actions/checkout@v2 18 | - uses: actions/setup-node@v2 19 | with: 20 | node-version: 12 21 | - run: npm install 22 | 23 | publish-npm: 24 | needs: build 25 | runs-on: ubuntu-latest 26 | defaults: 27 | run: 28 | working-directory: ./src 29 | steps: 30 | - uses: actions/checkout@v2 31 | - uses: actions/setup-node@v2 32 | with: 33 | node-version: 12 34 | registry-url: https://registry.npmjs.org/ 35 | scope: '@ngx-builders' 36 | - run: npm install 37 | - run: npm run build 38 | - run: npm publish 39 | env: 40 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 41 | 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | *.map 3 | node_modules 4 | *.js 5 | *.js.map 6 | .gitignore 7 | *.code-workspace 8 | **/package-lock.json -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 ngx-builders 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm downloads](https://img.shields.io/npm/dt/@netlify-builder/deploy?label=npm%20downloads)](https://www.npmjs.com/package/@netlify-builder/deploy) 2 | [![npm (scoped)](https://img.shields.io/npm/v/@netlify-builder/deploy)](https://www.npmjs.com/package/@netlify-builder/deploy) 3 | ![Build Status](https://github.com/ngx-builders/netlify-builder/workflows/Node.js%20CI/badge.svg) 4 | [![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat-square)](#contributors) 5 | 6 | ## **Deploy your Angular app to Netlify directly from the Angular CLI! 🚀** 7 | ### Pre-requisites 8 | - Angular project created via [Angular CLI](https://github.com/angular/angular-cli) v8.3.0 or greater. 9 | 10 | ### Steps: 11 | 1. run `ng add @netlify-builder/deploy` 12 | OR `ng add @netlify-builder/deploy --project={projectName}` to add necessary dependencies. Once, it get installed,you will be prompted to enter (a) Site Id and (b) Netlify Token 13 | ![Screenshot](screenshots/step-1.png) 14 | 2. run ```ng deploy``` assuming that you have [Angular CLI](https://github.com/angular/angular-cli) installed globally 15 | 16 | OR 17 | 18 | add below script to ```package.json``` 19 | ``` 20 | "deploy":"ng deploy" 21 | ``` 22 | 23 | ![Screenshot](screenshots/step-2.png) 24 | 25 | 26 | # Netlify Builder demo 27 | 28 | This repository contains an example of the Angular CLI Architect API. 29 | 30 | ## Builder 31 | 32 | You can find the Architect builder in the `src` directory. 33 | 34 | ## Sample application 35 | 36 | The sample application which uses the Architect builder is available under the `builder-test` directory. 37 | 38 | ## License 39 | 40 | MIT 41 | 42 | 43 | ## Setup 44 | 45 | 1. Move to src and run the below command 46 | 47 | ```sh 48 | npm i 49 | ``` 50 | 51 | 2. Run the below command to build the package 52 | 53 | ```sh 54 | npm run build 55 | ``` 56 | 57 | 3. run the below command to link the package 58 | 59 | ``` 60 | npm link 61 | ``` 62 | 63 | ## Link to [Step by Step Guide](https://www.netlify.com/blog/2019/09/17/using-the-angular-builder-for-netlify/) 64 | 65 | ## Contributors ✨ 66 | 67 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 |

Nitish Kumar Singh

💻

Shaikh-Ubaid

📖

Suraj Chandgude

💻

Santosh Yadav

💻

Alan Agius

💻

Imran Momin

💻

Michael Hladky

💻

Nilesh Patel

📖

Josh Morony

💻
87 | 88 | 89 | 90 | 91 | 92 | 93 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 94 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /screenshots/api-id.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngx-builders/netlify-builder/b915395041d61d460f3a312c1a9c7cc9a683cda2/screenshots/api-id.png -------------------------------------------------------------------------------- /screenshots/personal-access-token.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngx-builders/netlify-builder/b915395041d61d460f3a312c1a9c7cc9a683cda2/screenshots/personal-access-token.png -------------------------------------------------------------------------------- /screenshots/step-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngx-builders/netlify-builder/b915395041d61d460f3a312c1a9c7cc9a683cda2/screenshots/step-1.png -------------------------------------------------------------------------------- /screenshots/step-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ngx-builders/netlify-builder/b915395041d61d460f3a312c1a9c7cc9a683cda2/screenshots/step-2.png -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | charset = utf-8 7 | trim_trailing_whitespace = false 8 | insert_final_newline = false -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/ngx-builders/netlify-builder.svg?branch=master)](https://travis-ci.org/nitishk72/netlify-builder) 2 | [![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors) 3 | # Angular CLI Deployment to netlify 4 | 5 | Deploy your Angular app to Netlify directly from the Angular CLI! 🚀 6 | 7 | ## Prerequisite 8 | 9 | You will need two things in order to get started 10 | 11 | - API ID (Site ID) : Every Netlify application has an API ID that uniquely identify the respective app. You can find it inside your project's Setting/General section. 12 | ![alt text](https://raw.githubusercontent.com/ngx-builders/netlify-builder/master/screenshots/api-id.png) 13 | - [Personal access tokens](https://app.netlify.com/user/applications#personal-access-tokens) : Access token gives the ability to communicate with Netlify over API and helps to push the code on Netlify. 14 | ![alt text](https://raw.githubusercontent.com/ngx-builders/netlify-builder/master/screenshots/personal-access-token.png) 15 | 16 | ## Setting up this Builder 17 | 18 | ``` 19 | ng add @netlify-builder/deploy 20 | OR 21 | ng add @netlify-builder/deploy --project={projectName} 22 | ``` 23 | 24 | The above command will configure everything, you just need to provide API ID and Personal access tokens when it will ask you for that. 25 | 26 | ## That's it. Now, you are good to go 27 | 28 | Now, Whenever you want to deploy your angular project just run a command `ng run [YOUR_PROJECT_NAME]:deploy` and your project will be deployed with new updates. 29 | 30 | 31 | ## 📦 Options 32 | 33 | #### --configuration 34 | * __optional__ 35 | * Alias: `-c` 36 | * Default: `production` (string) 37 | * Example: 38 | * `ng deploy` – Angular project is build in production mode 39 | * `ng deploy --configuration=test` – Angular project is using the configuration `test` (this configuration must exist in the `angular.json` file) 40 | 41 | A named build target, as specified in the `configurations` section of `angular.json`. 42 | Each named target is accompanied by a configuration of option defaults for that target. 43 | Same as `ng build --configuration=XXX`. 44 | This command has no effect if the option `--no-build` option is active. 45 | 46 | 47 | #### --no-build 48 | - **optional** 49 | - Default: `false` (string) 50 | - Example: 51 | - `ng deploy` – Angular project is build in production mode before the deployment 52 | - `ng deploy --no-build` – Angular project is NOT build 53 | 54 | Skip build process during deployment. 55 | This can be used when you are sure that you haven't changed anything and want to deploy with the latest artifact. 56 | This command causes the `--configuration` setting to have no effect. 57 | 58 | #### --create 59 | - **optional** 60 | - Default: `false` (string) 61 | - Example: 62 | - `ng deploy --create` – The command will create a new site if there is no site id or the site id does not exists on netlify 63 | 64 | #### --base-href 65 | 66 | - **optional** 67 | - Default: `undefined` (string) 68 | - Example: 69 | - `ng deploy` – The tag `` remains unchanged in your `index.html` 70 | - `ng deploy --base-href=/the-repositoryname/` – The tag `` is added to your `index.html` 71 | 72 | Specifies the base URL for the application being built. 73 | Same as `ng build --base-href=/XXX/` 74 | 75 | #### --with-deps 76 | - **optional** 77 | - Default: `false` (string) 78 | - Example: 79 | - `ng deploy --with-deps` – Use this flag with Nx, to build your app withDeps. 80 | ## License 81 | 82 | MIT 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/builders.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "@angular-devkit/architect/src/builders-schema.json", 3 | "builders": { 4 | "deploy": { 5 | "implementation": "./deploy", 6 | "schema": "./deploy/schema.json", 7 | "description": "Runs any command line in the operating system." 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /src/collection.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "@angular-devkit/schematics/collection-schema.json", 3 | "schematics": { 4 | "ng-add": { 5 | "description": "A Netlify Deploy schematic.", 6 | "factory": "./ng-add/index", 7 | "schema": "./ng-add/schema.json", 8 | "aliases": [ 9 | "install" 10 | ] 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/deploy/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | BuilderContext, 3 | BuilderOutput, 4 | createBuilder, 5 | } from "@angular-devkit/architect"; 6 | import { json } from "@angular-devkit/core"; 7 | import { Schema } from "./schema"; 8 | const NetlifyAPI = require("netlify"); 9 | 10 | export default createBuilder( 11 | async ( 12 | builderConfig: Schema, 13 | context: BuilderContext 14 | ): Promise => { 15 | context.reportStatus(`Executing deploy...`); 16 | context.logger.info(`Executing netlify deploy command ...... `); 17 | 18 | if (builderConfig.noBuild) { 19 | context.logger.info(`📦 Skipping build`); 20 | } else { 21 | const configuration = builderConfig.configuration || "production"; 22 | 23 | const withDeps = { 24 | ...{ withDeps: builderConfig.withDeps }, 25 | }; 26 | 27 | let overrides: any = { 28 | // this is an example how to override the workspace set of options 29 | ...(builderConfig.baseHref && { 30 | baseHref: builderConfig.baseHref, 31 | }), 32 | }; 33 | 34 | if (builderConfig.withDeps) { 35 | overrides = { 36 | ...(builderConfig.baseHref && { 37 | baseHref: builderConfig.baseHref, 38 | }), 39 | withDeps: builderConfig.withDeps, 40 | }; 41 | } 42 | 43 | if (!context.target) { 44 | throw new Error( 45 | "Cannot build the application without a target" 46 | ); 47 | } 48 | 49 | const baseHref = builderConfig.baseHref 50 | ? `Your base-href: "${builderConfig.baseHref}` 51 | : ""; 52 | const buildTarget = builderConfig.buildTarget 53 | ? builderConfig.buildTarget 54 | : "build"; 55 | context.logger.info( 56 | `📦 Building "${context.target.project}". Configuration: "${configuration}". Build Command: ${buildTarget}. ${baseHref}` 57 | ); 58 | 59 | const build = await context.scheduleTarget( 60 | { 61 | target: buildTarget, 62 | project: context.target.project || "", 63 | configuration, 64 | }, 65 | overrides as json.JsonObject 66 | ); 67 | 68 | const buildResult = await build.result; 69 | 70 | if (buildResult.success !== true) { 71 | context.logger.error(`❌ Application build failed`); 72 | return { 73 | error: `❌ Application build failed`, 74 | success: false, 75 | }; 76 | } 77 | 78 | context.logger.info(`✔ Build Completed`); 79 | } 80 | 81 | const netlifyToken = 82 | process.env.NETLIFY_TOKEN || builderConfig.netlifyToken; 83 | if (netlifyToken === "" || netlifyToken === undefined) { 84 | context.logger.error("🚨 Netlify Token not found !"); 85 | return { success: false }; 86 | } 87 | 88 | let siteId = process.env.NETLIFY_API_ID || builderConfig.siteId; 89 | if (siteId === "" || siteId === undefined) { 90 | // site id is needed if the create option is false 91 | if (builderConfig.create === false) { 92 | context.logger.error("🚨 API ID (Site ID) not found !"); 93 | return { success: false }; 94 | } 95 | } 96 | 97 | const client = new NetlifyAPI(netlifyToken, { 98 | userAgent: "netlify/js-client", 99 | scheme: "https", 100 | host: "api.netlify.com", 101 | pathPrefix: "/api/v1", 102 | globalParams: {}, 103 | }); 104 | 105 | // let check if the site exists 106 | let site; 107 | try { 108 | // only when the site id is set 109 | if (siteId) { 110 | site = await client.getSite({ site_id: siteId }); 111 | } 112 | } catch (e) { 113 | switch (e.status) { 114 | case 404: 115 | context.logger.error(`❌ Site "${siteId}" : Not found`); 116 | // if the create is false - just return the error 117 | if (builderConfig.create !== true) { 118 | return { 119 | success: false, 120 | }; 121 | } 122 | break; 123 | case 401: 124 | context.logger.fatal("🚨 Netlify: Unauthorized Token"); 125 | return { 126 | success: false, 127 | }; 128 | default: 129 | // for all other errors 130 | return { 131 | error: e.message, 132 | success: false, 133 | }; 134 | } 135 | } 136 | 137 | // lets create the site 138 | if (!site && builderConfig.create) { 139 | try { 140 | context.logger.info(`Creating new site for the application`); 141 | site = await client.createSite(); 142 | siteId = site.id as string; 143 | context.logger.info( 144 | `✔ Site "${site.name}" (${siteId}) created. Please update the angular.json so on the next run we can re-deploy on the same site` 145 | ); 146 | } catch (e) { 147 | context.logger.error("🚨 Unable to create the site"); 148 | return { 149 | error: e.message, 150 | success: false, 151 | }; 152 | } 153 | } 154 | 155 | // if we still don't have the site return with error 156 | if (!site) { 157 | context.logger.error( 158 | "🚨 Unable to deploy as we don't have any context about the site" 159 | ); 160 | return { 161 | error: "🚨 Unable to deploy as we don't have any context about the site", 162 | success: false, 163 | }; 164 | } 165 | 166 | // lets deploy the application to the site 167 | try { 168 | context.logger.info( 169 | `Deploying project from 📂 ./${builderConfig.outputPath}` 170 | ); 171 | 172 | let config = {}; 173 | 174 | if (builderConfig.functionsPath) { 175 | console.log( 176 | `Deploying functions from 📂 ./${builderConfig.functionsPath}` 177 | ); 178 | config = { ...config, fnDir: builderConfig.functionsPath }; 179 | } 180 | 181 | const response = await client.deploy( 182 | siteId, 183 | builderConfig.outputPath, 184 | config 185 | ); 186 | context.logger.info( 187 | `✔ Your updated site 🕸 is running at ${response.deploy.ssl_url}` 188 | ); 189 | return { success: true }; 190 | } catch (e) { 191 | context.logger.error(`❌ Deployment failed: ${e.message}`); 192 | return { 193 | error: e.message, 194 | success: false, 195 | }; 196 | } 197 | } 198 | ); 199 | -------------------------------------------------------------------------------- /src/deploy/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface Schema { 2 | buildTarget?: string; 3 | configuration?: string; 4 | noBuild?: boolean; 5 | outputPath?: boolean; 6 | functionsPath?: boolean; 7 | netlifyToken?: string; 8 | siteId?: string; 9 | baseHref?: string; 10 | create?: boolean; 11 | withDeps?: boolean; 12 | } 13 | -------------------------------------------------------------------------------- /src/deploy/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$id": "Schema", 3 | "title": "schema", 4 | "description": "Deployment of Angular CLI applications to Netlify", 5 | "properties": { 6 | "buildTarget": { 7 | "type": "string", 8 | "default": "build", 9 | "description": "A build target command." 10 | }, 11 | "configuration": { 12 | "type": "string", 13 | "default": "production", 14 | "description": "A named build target, as specified in the `configurations` section of angular.json. Each named target is accompanied by a configuration of option defaults for that target. Same as `ng build --configuration=XXX`.", 15 | "alias": "c" 16 | }, 17 | "noBuild": { 18 | "type": "boolean", 19 | "default": false, 20 | "description": "Skip build process during deployment." 21 | }, 22 | "outputPath": { 23 | "type": "string", 24 | "description": "This is one of the options you can freely choose according to your needs. --- We will 'deploy' to this folder." 25 | }, 26 | "functionsPath": { 27 | "type": "string", 28 | "description": "Path to the functions folder you want to deploy" 29 | }, 30 | "netlifyToken": { 31 | "type": "string", 32 | "description": "Acess token give you the ability to communicate with netlify over API." 33 | }, 34 | "siteId": { 35 | "type": "string", 36 | "description": "Every netlify app have a API ID which uniquly identify that app." 37 | }, 38 | "baseHref": { 39 | "type": "string", 40 | "description": "This is an example how to override the workspace set of options. --- Base url for the application being built. Same as `ng build --base-href=/XXX/`." 41 | }, 42 | "create": { 43 | "type": "boolean", 44 | "default": false, 45 | "description": "Creates the site if it does not exists or no site id is set" 46 | }, 47 | "withDeps": { 48 | "type": "boolean", 49 | "default": false, 50 | "description": "To be used with Nx if app needs to be built with-deps" 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ng-add'; 2 | export * from './deploy'; -------------------------------------------------------------------------------- /src/interfaces.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface WorkspaceProject { 3 | projectType?: string; 4 | architect?: Record< 5 | string, 6 | { builder: string; options?: Record } 7 | >; 8 | } 9 | 10 | export interface Workspace { 11 | defaultProject?: string; 12 | projects: Record; 13 | } 14 | -------------------------------------------------------------------------------- /src/ng-add/index.ts: -------------------------------------------------------------------------------- 1 | import { Rule, SchematicContext, SchematicsException, Tree, chain } from '@angular-devkit/schematics'; 2 | import { JsonParseMode, parseJson } from '@angular-devkit/core'; 3 | import { Workspace } from '../interfaces'; 4 | 5 | function getWorkspace(host: Tree): { path: string; workspace: Workspace } { 6 | const possibleFiles = ['/angular.json', './angular.json']; 7 | const path = possibleFiles.find(path => host.exists(path)); 8 | const configBuffer = path ? host.read(path) : undefined; 9 | 10 | if (!path || !configBuffer) { 11 | throw new SchematicsException(`Could not find angular.json`); 12 | } 13 | 14 | const content = configBuffer.toString(); 15 | let workspace: Workspace; 16 | 17 | try { 18 | workspace = (parseJson(content, JsonParseMode.Loose) as {}) as Workspace; 19 | } catch (e) { 20 | throw new SchematicsException(`Could not parse angular.json: ${e.message}`); 21 | } 22 | 23 | return { path, workspace }; 24 | } 25 | 26 | interface NgAddOptions { 27 | project?: string; 28 | siteID: string; 29 | netlifyToken: string; 30 | } 31 | 32 | export function netlifyBuilder(options: NgAddOptions): Rule { 33 | return (tree: Tree, _context: SchematicContext) => { 34 | // get the workspace details 35 | const { path: workspacePath, workspace } = getWorkspace(tree); 36 | 37 | // getting project name 38 | if (!options.project) { 39 | if (workspace.defaultProject) { 40 | options.project = workspace.defaultProject; 41 | } else { 42 | throw new SchematicsException( 43 | 'No Angular project selected and no default project in the workspace' 44 | ); 45 | } 46 | } 47 | 48 | // Validating project name 49 | const project = workspace.projects[options.project]; 50 | if (!project) { 51 | throw new SchematicsException( 52 | 'The specified Angular project is not defined in this workspace' 53 | ); 54 | } 55 | 56 | // Checking if it is application 57 | if (project.projectType !== 'application') { 58 | throw new SchematicsException( 59 | `Deploy requires an Angular project type of "application" in angular.json` 60 | ); 61 | } 62 | 63 | // Getting output path from Angular.json 64 | if ( 65 | !project.architect || 66 | !project.architect.build || 67 | !project.architect.build.options || 68 | !project.architect.build.options.outputPath 69 | ) { 70 | throw new SchematicsException( 71 | `Cannot read the output path(architect.build.options.outputPath) of the Angular project "${options.project}" in angular.json` 72 | ); 73 | } 74 | 75 | // adding deploy statement for builder 76 | project.architect['deploy'] = { 77 | "builder": "@netlify-builder/deploy:deploy", 78 | "options": { 79 | "outputPath": project.architect.build.options.outputPath, 80 | "netlifyToken": options.netlifyToken, 81 | "siteId": options.siteID, 82 | } 83 | } 84 | 85 | tree.overwrite(workspacePath, JSON.stringify(workspace, null, 2)); 86 | return tree; 87 | }; 88 | } 89 | 90 | export default function (options: NgAddOptions): Rule { 91 | return chain([ 92 | netlifyBuilder(options), 93 | ]); 94 | } -------------------------------------------------------------------------------- /src/ng-add/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "netlify-builder-deploy-ng-add", 4 | "title": "Netlify Builder ng-add schematic", 5 | "type": "object", 6 | "properties": { 7 | "project": { 8 | "type": "string", 9 | "description": "The name of the project.", 10 | "$default": { 11 | "$source": "projectName" 12 | } 13 | }, 14 | "siteID": { 15 | "type": "string", 16 | "description": "You can find the Site ID on Netlify Settings/General", 17 | "x-prompt": "API ID( Site ID ) of Netlify project (optional)" 18 | }, 19 | "netlifyToken": { 20 | "type": "string", 21 | "description": "You can create a new API for free !", 22 | "x-prompt": "Personal Access Tokens of Netlify Account (required)" 23 | } 24 | }, 25 | "required": ["netlifyToken"] 26 | } 27 | -------------------------------------------------------------------------------- /src/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@netlify-builder/deploy", 3 | "version": "5.0.0", 4 | "description": "A Netlify builder schematics for deployment", 5 | "main": "index.js", 6 | "builders": "./builders.json", 7 | "schematics": "./collection.json", 8 | "ng-add": { 9 | "save": "devDependencies" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/santoshyadav198613/netlify-builder.git" 14 | }, 15 | "scripts": { 16 | "build": "tsc -p tsconfig.json", 17 | "test": "ts-node node_modules/jasmine/bin/jasmine command/index_spec.ts" 18 | }, 19 | "keywords": [ 20 | "angular", 21 | "schematics", 22 | "cli", 23 | "angular-cli", 24 | "netlify", 25 | "deploy", 26 | "ng deploy", 27 | "ng-deploy", 28 | "netlify deploy", 29 | "netlify-deploy" 30 | ], 31 | "author": "Santosh Yadav ", 32 | "contributors": [ 33 | "Nitish Kumar Singh (https://nitishk72.github.io)", 34 | "Imran Momin " 35 | ], 36 | "license": "MIT", 37 | "bugs": { 38 | "url": "https://github.com/santoshyadav198613/netlify-builder/issues" 39 | }, 40 | "homepage": "https://github.com/santoshyadav198613/netlify-builder#readme", 41 | "devDependencies": { 42 | "@types/jasmine": "3.7.6", 43 | "@types/node": "14.17.1", 44 | "jasmine": "3.7.0", 45 | "jasmine-node": "3.0.0", 46 | "ts-node": "10.0.0", 47 | "typescript": "4.3.2" 48 | }, 49 | "dependencies": { 50 | "@angular-devkit/architect": "^0.1200.0", 51 | "@angular-devkit/core": "^12.0.0", 52 | "@angular-devkit/schematics": "^12.0.0", 53 | "netlify": "^6.1.1" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "module": "commonjs", 5 | "target": "es2015", 6 | "lib": [ 7 | "es2015", 8 | "dom", 9 | "es2015.promise", 10 | "es2015.collection", 11 | "es2015.iterable" 12 | ], 13 | "strict": true, 14 | "allowSyntheticDefaultImports": true, 15 | "suppressImplicitAnyIndexErrors": true, 16 | "forceConsistentCasingInFileNames": true, 17 | "strictPropertyInitialization": false, 18 | "strictNullChecks": true, 19 | "sourceMap": true, 20 | "declaration": false, 21 | "inlineSources": true, 22 | "stripInternal": true, 23 | "skipLibCheck": true, 24 | "noImplicitAny": false, 25 | "esModuleInterop": true 26 | }, 27 | "exclude": [ 28 | "node_modules" 29 | ], 30 | "compileOnSave": false, 31 | "buildOnSave": false, 32 | "angularCompilerOptions": { 33 | "skipTemplateCodegen": true, 34 | "strictMetadataEmit": true, 35 | "enableSummariesForJit": false 36 | } 37 | } --------------------------------------------------------------------------------