├── .eslintrc.json
├── .github
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── build.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── .versionrc.json
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── commitlint.config.js
├── index.ts
├── package-lock.json
├── package.json
├── public_api.ts
├── renovate.json
├── schematics
├── collection.json
├── ng-add
│ ├── files
│ │ ├── .dockerignore
│ │ ├── Dockerfile
│ │ └── nginx.conf
│ ├── index.ts
│ ├── schema.d.ts
│ └── schema.json
└── utils.ts
├── src
├── builders.json
├── deploy
│ ├── actions.ts
│ ├── builder.ts
│ ├── schema.d.ts
│ └── schema.json
├── engine
│ └── engine.ts
└── interfaces.ts
└── tsconfig.json
/.eslintrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "node": true,
4 | "commonjs": true,
5 | "es6": true
6 | },
7 | "extends": [
8 | "eslint:recommended",
9 | "plugin:@typescript-eslint/eslint-recommended"
10 | ],
11 | "globals": {
12 | "Atomics": "readonly",
13 | "SharedArrayBuffer": "readonly"
14 | },
15 | "parser": "@typescript-eslint/parser",
16 | "parserOptions": {
17 | "ecmaVersion": 2018
18 | },
19 | "plugins": ["@typescript-eslint"],
20 | "rules": {}
21 | }
22 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
6 |
7 | ## I'm submitting a...
8 |
9 |
10 |
11 | [ ] Regression (a behavior that used to work and stopped working in a new release)
12 | [ ] Bug report
13 | [ ] Performance issue
14 | [ ] Feature request
15 | [ ] Documentation issue or request
16 | [ ] Support request
17 | [ ] Other... Please describe:
18 |
19 |
20 | ## Current behavior
21 |
22 |
23 |
24 | ## Expected behavior
25 |
26 |
27 |
28 | ## Minimal reproduction of the problem with instructions
29 |
30 | For bug reports please provide the _STEPS TO REPRODUCE_ and if possible a _MINIMAL DEMO_ of the problem.
31 |
32 | ## What is the motivation / use case for changing the behavior?
33 |
34 |
35 |
36 | ## Environment
37 |
38 |
39 | - Node version: XX
40 | - Git version
41 | - Platform:
42 |
43 | Others:
44 |
45 |
46 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ## PR Checklist
2 |
3 | Please check if your PR fulfills the following requirements:
4 |
5 | - [ ] The commit message follows our [guidelines](https://github.com/kauppfbi/ngx-deploy-docker/blob/master/CONTRIBUTING.md)
6 | - [ ] Tests for the changes have been added (for bug fixes / features)
7 | - [ ] Docs have been added / updated (for bug fixes / features)
8 |
9 | ## PR Type
10 |
11 | What kind of change does this PR introduce?
12 |
13 |
14 |
15 | ```
16 | [ ] Bugfix
17 | [ ] Feature
18 | [ ] Code style update (formatting, local variables)
19 | [ ] Refactoring (no functional changes, no api changes)
20 | [ ] Build related changes
21 | [ ] CI related changes
22 | [ ] Documentation content changes
23 | [ ] Other... Please describe:
24 | ```
25 |
26 | ## What is the current behavior?
27 |
28 |
29 |
30 | Issue Number: N/A
31 |
32 | ## What is the new behavior?
33 |
34 | ## Does this PR introduce a breaking change?
35 |
36 | ```
37 | [ ] Yes
38 | [ ] No
39 | ```
40 |
41 |
42 |
43 | ## Other information
44 |
--------------------------------------------------------------------------------
/.github/workflows/build.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: CI Pipeline
5 |
6 | # Trigger the workflow on push or pull request
7 | on: push
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | strategy:
14 | matrix:
15 | node-version: [14.x, 16.x]
16 |
17 | steps:
18 | - uses: actions/checkout@v2
19 | - name: Use Node.js ${{ matrix.node-version }}
20 | uses: actions/setup-node@v1
21 | with:
22 | node-version: ${{ matrix.node-version }}
23 | - name: Install Dependencies
24 | uses: bahmutov/npm-install@v1
25 | - name: Run Snyk to check for vulnerabilities
26 | uses: snyk/actions/node@master
27 | env:
28 | SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
29 | with:
30 | command: monitor
31 | - name: Check Format
32 | run: npm run format:test
33 | - name: Run Tests
34 | run: npm test
35 | - name: Build Package
36 | run: npm run build
37 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .tmp
3 | .sass-cache
4 | .DS_Store
5 | .bash_history
6 | *.swp
7 | *.swo
8 |
9 | *.classpath
10 | *.project
11 | *.settings/
12 |
13 | .vim/bundle
14 | nvim/autoload
15 | nvim/plugged
16 | nvim/doc
17 | nvim/swaps
18 | nvim/colors
19 | dist
20 |
21 | /src/mini-testdrive/404.html
22 | /src/mini-testdrive/CNAME
23 | .angulardoc.json
24 | .vscode/settings.json
25 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | package.json
2 | package-lock.json
3 | dist
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true
3 | }
4 |
--------------------------------------------------------------------------------
/.versionrc.json:
--------------------------------------------------------------------------------
1 | {
2 | "releaseCommitMessageFormat": "chore(release): 🚀 {{currentTag}}",
3 | "types": [
4 | { "type": "feat", "section": "🎸 Features" },
5 | { "type": "fix", "section": "🐛 Bug Fixes" },
6 | { "type": "docs", "section": "✏️ Documentation" },
7 | { "type": "chore", "hidden": true },
8 | { "type": "perf", "hidden": true },
9 | { "type": "style", "hidden": true },
10 | { "type": "refactor", "hidden": true },
11 | { "type": "test", "hidden": true }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4 |
5 | ## [0.1.0](https://github.com/kauppfbi/ngx-deploy-docker/compare/v0.0.5...v0.1.0) (2021-11-22)
6 |
7 | ### ⚠ BREAKING CHANGES
8 |
9 | - Drop Support for Angular versions <13
10 | - Drop Support for nodejs v10 and v12
11 | - option `build-target` replaces `configuration`
12 |
13 | ### ✏️ Documentation
14 |
15 | - add ci pipeline badge ([ae9bb2f](https://github.com/kauppfbi/ngx-deploy-docker/commit/ae9bb2faf13271bcf8f0874087ead778ab62e7f9))
16 |
17 | ### 🎸 Features
18 |
19 | - support angular v13 ([#104](https://github.com/kauppfbi/ngx-deploy-docker/issues/104)) ([abf319a](https://github.com/kauppfbi/ngx-deploy-docker/commit/abf319aec82bdf1646f16192e24d3d90e23a4d1c))
20 |
21 | ### 0.0.5 (2019-12-30)
22 |
23 | ### 🐛 Bug Fixes
24 |
25 | - update ng-add schematic ([caa6b6c](https://github.com/kauppfbi/ngx-deploy-docker/commit/caa6b6c798235b053917fc87391925f32cf6d129))
26 |
27 | ### ✏️ Documentation
28 |
29 | - update prerequisites ([5d9e116](https://github.com/kauppfbi/ngx-deploy-docker/commit/5d9e116648b7db781fcb590e9638f2874730141e))
30 |
31 | ### 0.0.4 (2019-10-04)
32 |
33 | ### 🐛 Bug Fixes
34 |
35 | - use correct path to read from package.json ([5b1b8a6](https://github.com/kauppfbi/ngx-deploy-docker/commit/5b1b8a6))
36 |
37 | ### 0.0.3 (2019-10-03)
38 |
39 | ### ✏️ Documentation
40 |
41 | - improve readme & project documentation ([36e45be](https://github.com/kauppfbi/ngx-deploy-docker/commit/36e45be))
42 |
43 | ### 0.0.2 (2019-10-02)
44 |
45 | ### 🎸 Features
46 |
47 | - 🎉 implement ng-add schematic for the package ([d45bf1f](https://github.com/kauppfbi/ngx-deploy-docker/commit/d45bf1f))
48 | - add docker build and push logic to builder ([2ac677b](https://github.com/kauppfbi/ngx-deploy-docker/commit/2ac677b))
49 | - add docker options in builder ([8da80cb](https://github.com/kauppfbi/ngx-deploy-docker/commit/8da80cb))
50 | - autogenerate dockerfile and nginx config if not present ([6edcd86](https://github.com/kauppfbi/ngx-deploy-docker/commit/6edcd86))
51 |
52 | ### 🐛 Bug Fixes
53 |
54 | - adjust copy command to also copy .dockerignore file ([1baf9bf](https://github.com/kauppfbi/ngx-deploy-docker/commit/1baf9bf))
55 | - set correct builder in ng add schematic ([55cd271](https://github.com/kauppfbi/ngx-deploy-docker/commit/55cd271))
56 | - use correct image name with account and tag ([dcb14b3](https://github.com/kauppfbi/ngx-deploy-docker/commit/dcb14b3))
57 |
58 | ### 0.0.1 (2019-09-30)
59 |
60 | ### ✏️ Documentation
61 |
62 | - add code of conduct ([187062e](https://github.com/kauppfbi/ngx-deploy-docker/commit/187062e))
63 | - add contributing guide ([c4db8b3](https://github.com/kauppfbi/ngx-deploy-docker/commit/c4db8b3))
64 | - add first draft for README ([cb490bd](https://github.com/kauppfbi/ngx-deploy-docker/commit/cb490bd))
65 | - add github templates for issues and prs ([7c771c1](https://github.com/kauppfbi/ngx-deploy-docker/commit/7c771c1))
66 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Our Pledge
2 |
3 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
4 |
5 | ## Our Standards
6 |
7 | ### Examples of behavior that contributes to creating a positive environment include:
8 |
9 | - Using welcoming and inclusive language
10 | - Being respectful of differing viewpoints and experiences
11 | - Gracefully accepting constructive criticism
12 | - Focusing on what is best for the community
13 | - Showing empathy towards other community members
14 | - Examples of unacceptable behavior by participants include:
15 |
16 | ### The use of sexualized language or imagery and unwelcome sexual attention or advances
17 |
18 | - Trolling, insulting/derogatory comments, and personal or political attacks
19 | - Public or private harassment
20 | - Publishing others’ private information, such as a physical or electronic address, without explicit permission
21 | - Other conduct which could reasonably be considered inappropriate in a professional setting
22 |
23 | ## Our Responsibilities
24 |
25 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
26 |
27 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
28 |
29 | ## Scope
30 |
31 | This Code of Conduct applies within all project spaces, and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
32 |
33 | ## Enforcement
34 |
35 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [INSERT EMAIL ADDRESS]. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
36 |
37 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project’s leadership.
38 |
39 | ## Attribution
40 |
41 | This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
42 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to ngx-deploy-docker
2 |
3 | 🙏 We would ❤️ for you to contribute to `ngx-deploy-docker` and help make it better!
4 |
5 | ## Getting started
6 |
7 | ### 1. Angular CLI
8 |
9 | 1. Install the next version of the Angular CLI.
10 |
11 | ```sh
12 | npm install -g @angular/cli
13 | ```
14 |
15 | 2. Run `ng version`, make sure you have installed Angular CLI v8.3.0 or greater.
16 |
17 | 3. Update your existing project using the command:
18 |
19 | ```sh
20 | ng update @angular/cli @angular/core
21 | ```
22 |
23 | ### 2. npm link
24 |
25 | Use the following instructions to make `ngx-deploy-docker` available locally via `npm link`.
26 |
27 | 1. Clone the project
28 |
29 | ```sh
30 | git clone https://github.com/kauppfbi/ngx-deploy-docker.git
31 | cd ngx-deploy-docker
32 | ```
33 |
34 | 2. Install the dependencies
35 |
36 | ```sh
37 | npm install
38 | ```
39 |
40 | 3. Build the project:
41 |
42 | ```sh
43 | npm run build
44 | ```
45 |
46 | 4. Create a local npm link:
47 |
48 | ```sh
49 | cd dist
50 | npm link
51 | ```
52 |
53 | Read more about the `link` feature in the [official NPM documentation](https://docs.npmjs.com/cli/link).
54 |
55 | ### 3. Adding to an Angular project -- ng add
56 |
57 | Once you have completed the previous steps to `npm link` the local copy of `ngx-deploy-docker`, follow these steps to use it in a local Angular project.
58 |
59 | 1. Enter the project directory
60 |
61 | ```sh
62 | cd your-angular-project
63 | ```
64 |
65 | 2. Add the local version of `ngx-deploy-docker`.
66 |
67 | ```sh
68 | npm link ngx-deploy-docker
69 | ```
70 |
71 | 3. Now execute the `ng-add` schematic.
72 |
73 | ```sh
74 | ng add ngx-deploy-docker
75 | ```
76 |
77 | 4. You can now deploy your angular app to a Docker Registry.
78 |
79 | ```sh
80 | ng deploy
81 | ```
82 |
83 | 5. You can remove the link later by running `npm unlink`
84 |
85 | ### 4. Testing
86 |
87 | Testing is done with [Jest](https://jestjs.io/).
88 | To run the tests:
89 |
90 | ```sh
91 | npm test
92 | ```
93 |
94 | ## Contribute
95 |
96 | ### Coding Rules
97 |
98 | To ensure consistency throughout the source code, keep these rules in mind as you are working:
99 |
100 | - All features or bug fixes **must be tested** by one or more specs (unit-tests).
101 | - All public API methods **must be documented**.
102 |
103 | ### Commit Message Guidelines
104 |
105 | We have very precise rules over how our git commit messages can be formatted. This leads to **more
106 | readable messages** that are easy to follow when looking through the **project history**. But also,
107 | we use the git commit messages to **generate the changelog**.
108 |
109 | #### Commit Message Format
110 |
111 | The format of commit messages must align with the rules provided by [@commitlint/config-conventional](https://www.npmjs.com/package/@commitlint/config-conventional)
112 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 - 2021 Fabian Kaupp
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 | # ngx-deploy-docker 🚀🐳
2 |
3 | **This Project is still work in progress.**
4 |
5 | 
6 | [![NPM version][npm-image]][npm-url]
7 | [](http://opensource.org/licenses/MIT)
8 |
9 | **Dockerize your Angular application with ease and deploy your image right from the Angular CLI to a registry 🚀**
10 |
11 | **Table of contents:**
12 |
13 | 1. [📖 Changelog](#changelog)
14 | 2. [🚀 Quick Start (local development)](#quickstart-local)
15 | 3. [🚀 Continuous Delivery](#continuous-delivery)
16 | 4. [📦 Options](#options)
17 | - [--base-href](#base-href)
18 | - [--build-target](#build-target)
19 | - [--no-build](#no-build)
20 | - [--image-name](#image-name)
21 | - [--account](#account)
22 | - [--tag](#tag)
23 | 5. [📁 Configuration File](#configuration-file)
24 | 6. [🏁 Next milestones](#milestones)
25 |
26 |
27 |
28 | ## 📖 Changelog
29 |
30 | A detailed changelog is available [here](https://github.com/kauppfbi/ngx-deploy-docker/blob/master/CHANGELOG.md).
31 |
32 | ## 🚀 Quick Start (local development)
33 |
34 | This quick start assumes that you are starting from scratch.
35 | If you already have an existing Angular project, skip step 1.
36 |
37 | 1. Install the latest version of the **`Angular CLI` (v13.0.0 or greater) globally**
38 | and create a new Angular project. Make sure you have a suitable version of `nodeJs` installed.
39 |
40 | ```sh
41 | npm install -g @angular/cli
42 | ng new your-angular-project --defaults
43 | cd your-angular-project
44 | ```
45 |
46 | 2. Add `ngx-deploy-docker` to your project.
47 |
48 | ```sh
49 | ng add ngx-deploy-docker
50 | ```
51 |
52 | 3. Make sure, Docker works properly on your client and you are authenticated at the repository of your choice.
53 |
54 | ```sh
55 | docker login
56 | ```
57 |
58 | 4. Deploy your newly built image to the registry with all default settings.
59 | Your project will be automatically built in production mode.
60 |
61 | ```sh
62 | ng deploy
63 | ```
64 |
65 | Which is the same as:
66 |
67 | ```sh
68 | ng deploy your-angular-project
69 | ```
70 |
71 | ## 🚀 Continuous Delivery
72 |
73 | ...more to come
74 |
75 | ## 📦 Options
76 |
77 | #### --base-href
78 |
79 | - **optional**
80 | - Default: `undefined` (string)
81 | - Example:
82 | - `ng deploy` – The tag `` remains unchanged in your `index.html`
83 | - `ng deploy --base-href=/XXX/` – The tag `` is added to your `index.html`
84 |
85 | Specifies the base URL for the application being built.
86 | Same as `ng build --base-href=/XXX/`
87 |
88 | #### --build-target
89 |
90 | - **optional**
91 | - Example:
92 | - `ng deploy` – Angular project is build in production mode
93 | - `ng deploy --build-target=:build:test` – Angular project is using the configuration `test` (this configuration must exist in the `angular.json` file)
94 |
95 | A named build target, as specified in the `configurations` section of `angular.json`.
96 | Each named target is accompanied by a configuration of option defaults for that target.
97 | Same as `ng run `.
98 | This command has no effect if the option `--no-build` option is active.
99 |
100 | #### --no-build
101 |
102 | - **optional**
103 | - Default: `false` (boolean)
104 | - Example:
105 | - `ng deploy` – Angular project is build in production mode before the deployment
106 | - `ng deploy --no-build` – Angular project is NOT build
107 |
108 | Skip build process during deployment.
109 | This can be used when you are sure that you haven't changed anything and want to deploy with the latest artifact.
110 | This command causes the `--build-target` setting to have no effect.
111 |
112 | #### --image-name
113 |
114 | - **optional**
115 | - Example:
116 | - `ng deploy` – Docker Image is build with the name of the project as image name
117 | - `ng deploy --image-name=your-special-name` – Docker Image is built with the name provided.
118 |
119 | #### --account
120 |
121 | - **optional**
122 | - Alias: `-a`
123 | - Default: `` (string)
124 | - Example:
125 | - `ng deploy` – Docker Image name is **not** prefixed.
126 | - `ng deploy --account=test` – Docker image name is prefixed with the provided account, like `account/image-name`.
127 |
128 | > This option may be necessary, depending on your write-rights within the repository, you want to push to.
129 |
130 | #### --tag
131 |
132 | - **optional**
133 | - Alias: `-t`
134 | - Default: `latest` (string)
135 | - Example:
136 | - `ng deploy` – Docker Image is build with the tag `latest`, e.g.`account/image-name:latest`
137 | - `ng deploy --tag=v1.0.0` – Docker Image is build with the tag `v1.0.0`
138 |
139 | ## 📁 Configuration File
140 |
141 | To avoid all these command-line cmd options, you can write down your configuration in the `angular.json` file in the `options` attribute of your deploy project's architect. Just change the kebab-case to lower camel case. This is the notation of all options in lower camel case:
142 |
143 | - baseHref
144 | - buildTarget
145 | - noBuild
146 | - imageName
147 | - account
148 | - tag
149 |
150 | A list of all available options is also available [here](https://github.com/kauppfbi/ngx-deploy-docker/blob/master/src/deploy/schema.json).
151 |
152 | Example:
153 |
154 | ```sh
155 | ng deploy --build-target=:build:production --tag=next
156 | ```
157 |
158 | becomes
159 |
160 | ```json
161 | "deploy": {
162 | "builder": "ngx-deploy-docker:deploy",
163 | "options": {
164 | "buildTarget": ":build:production",
165 | "tag": "next"
166 | }
167 | }
168 | ```
169 |
170 | And just run `ng deploy` 😄.
171 |
172 | ## 🏁 Next milestones
173 |
174 | - Setup of CI/CD Pipeline for the project
175 | - Code Restructuring:
176 | - Modularization of Schematics and Builders
177 | - Use what you need
178 | - Testing, Testing, Testing:
179 | - Manual tests on different clients with different OS
180 | - Unit and Integration Tests
181 | - Add more options to the deploy builder, what do you need?
182 | - Integration in NxWorkspace
183 | - 💅 Kubernetes deployment right from the CLI
184 | - preparing examples of `how to use the package in CI environment with different Providers for private registries`
185 | - your feature that's not on the list yet?
186 |
187 | We look forward to any help. PRs are welcome! 😃
188 |
189 | ## License
190 |
191 | Code released under the [MIT license](LICENSE).
192 |
193 |
194 |
195 | # Attribution
196 |
197 | ## 🚀 Powered By [ngx-deploy-starter](https://github.com/angular-schule/ngx-deploy-starter)
198 |
199 | ## 🔥 Many things have been taken over from [transloco](https://github.com/ngneat/transloco)
200 |
201 | [npm-url]: https://www.npmjs.com/package/ngx-deploy-docker
202 | [npm-image]: https://badge.fury.io/js/ngx-deploy-docker.svg
203 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: ['@commitlint/config-conventional']
3 | };
4 |
--------------------------------------------------------------------------------
/index.ts:
--------------------------------------------------------------------------------
1 | export * from 'public_api';
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ngx-deploy-docker",
3 | "version": "0.1.0",
4 | "description": "Publish your angular projects to a docker registry by just run `ng deploy your-app`",
5 | "scripts": {
6 | "format:write": "prettier **/*.{ts,json,md} --write",
7 | "format:test": "prettier **/*.{ts,json,md} --list-different",
8 | "test": "",
9 | "release": "standard-version",
10 | "build": "rimraf dist && npx tsc && copyfiles -a package.json README.md schematics/**/{collection.json,schema.json,files/**} src/**/{builders.json,schema.json} dist",
11 | "build:watch": "tsc --watch",
12 | "build:test": ""
13 | },
14 | "schematics": "./schematics/collection.json",
15 | "builders": "./src/builders.json",
16 | "repository": {
17 | "type": "git",
18 | "url": "git+https://github.com/kauppfbi/ngx-deploy-docker.git"
19 | },
20 | "keywords": [
21 | "angular",
22 | "cli",
23 | "angular-cli",
24 | "deploy",
25 | "ng-deploy",
26 | "ng deploy",
27 | "docker",
28 | "publish"
29 | ],
30 | "author": {
31 | "name": "Fabian Kaupp",
32 | "email": "kauppfbi@gmail.com"
33 | },
34 | "license": "MIT",
35 | "bugs": {
36 | "url": "https://github.com/kauppfbi/ngx-deploy-docker/issues"
37 | },
38 | "homepage": "https://github.com/kauppfbi/ngx-deploy-docker#readme",
39 | "devDependencies": {
40 | "@angular-devkit/architect": "0.1300.3",
41 | "@angular-devkit/core": "13.0.3",
42 | "@angular-devkit/schematics": "13.0.3",
43 | "@commitlint/cli": "8.3.5",
44 | "@commitlint/config-conventional": "8.3.4",
45 | "@types/node": "16.11.9",
46 | "@typescript-eslint/eslint-plugin": "2.26.0",
47 | "@typescript-eslint/parser": "2.26.0",
48 | "copyfiles": "^2.4.1",
49 | "eslint": "6.8.0",
50 | "eslint-config-airbnb-base": "14.1.0",
51 | "eslint-plugin-import": "2.20.1",
52 | "eslint-plugin-node": "11.1.0",
53 | "husky": "4.2.3",
54 | "prettier": "2.0.2",
55 | "pretty-quick": "2.0.1",
56 | "rimraf": "3.0.2",
57 | "standard-version": "7.1.0",
58 | "typescript": "4.4.4"
59 | },
60 | "peerDependencies": {
61 | "@angular-devkit/architect": ">=0.1300.0",
62 | "@angular-devkit/core": ">=13.0.0",
63 | "@angular-devkit/schematics": ">=13.0.0"
64 | },
65 | "husky": {
66 | "hooks": {
67 | "pre-commit": "pretty-quick --staged",
68 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/public_api.ts:
--------------------------------------------------------------------------------
1 | export * from './schematics/ng-add';
2 | export * from './src/deploy/actions';
3 | export * from './src/deploy/builder';
4 |
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": ["config:base"]
3 | }
4 |
--------------------------------------------------------------------------------
/schematics/collection.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../node_modules/@angular-devkit/schematics/collection-schema.json",
3 | "schematics": {
4 | "ng-add": {
5 | "description": "Add Docker Registry Publish schematic (ngx-deploy-docker)",
6 | "factory": "./ng-add/index#ngAdd",
7 | "schema": "./ng-add/schema.json",
8 | "aliases": ["install"]
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/schematics/ng-add/files/.dockerignore:
--------------------------------------------------------------------------------
1 | e2e
2 | node_modules
3 | src
--------------------------------------------------------------------------------
/schematics/ng-add/files/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM nginx:alpine
2 | LABEL version="<%= version %>"
3 |
4 | COPY nginx.conf /etc/nginx/nginx.conf
5 |
6 | WORKDIR /usr/share/nginx/html
7 | COPY <%= outputPath %> .
--------------------------------------------------------------------------------
/schematics/ng-add/files/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 |
3 | events {
4 | worker_connections 1024;
5 | }
6 |
7 | http {
8 | server {
9 | listen 80;
10 | server_name localhost;
11 |
12 | root /usr/share/nginx/html;
13 | index index.html index.htm;
14 | include /etc/nginx/mime.types;
15 |
16 | gzip on;
17 | gzip_min_length 1000;
18 | gzip_proxied expired no-cache no-store private auth;
19 | gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
20 |
21 | location / {
22 | try_files $uri $uri/ /index.html;
23 | }
24 | }
25 | }
--------------------------------------------------------------------------------
/schematics/ng-add/index.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Rule,
3 | SchematicContext,
4 | Tree,
5 | SchematicsException,
6 | url,
7 | chain,
8 | apply,
9 | mergeWith,
10 | template,
11 | } from '@angular-devkit/schematics';
12 | import { NodePackageInstallTask } from '@angular-devkit/schematics/tasks';
13 |
14 | import {
15 | addPackageToPackageJson,
16 | createHost,
17 | getLibraryVersion,
18 | getVersionFromPackageJson,
19 | } from '../utils';
20 |
21 | import { Schema as NgAddOptions } from './schema';
22 | import { workspaces } from '@angular-devkit/core';
23 | import {
24 | WorkspaceDefinition,
25 | WorkspaceHost,
26 | } from '@angular-devkit/core/src/workspace';
27 |
28 | function addDeployBuilderToProject(
29 | tree: Tree,
30 | host: WorkspaceHost,
31 | workspace: WorkspaceDefinition,
32 | options: NgAddOptions
33 | ) {
34 | if (!options.project) {
35 | if (workspace.extensions.defaultProject) {
36 | options.project = workspace.extensions.defaultProject as string;
37 | } else {
38 | throw new SchematicsException(
39 | 'No Angular project selected and no default project in the workspace'
40 | );
41 | }
42 | }
43 |
44 | const project = workspace.projects.get(options.project);
45 | if (!project) {
46 | throw new SchematicsException(
47 | 'The specified Angular project is not defined in this workspace'
48 | );
49 | }
50 |
51 | if (project.extensions.projectType !== 'application') {
52 | throw new SchematicsException(
53 | `Deploy requires an Angular project type of "application" in angular.json`
54 | );
55 | }
56 |
57 | if (!project.targets.get('build')?.options?.outputPath) {
58 | throw new SchematicsException(
59 | `Cannot read the output path (architect.build.options.outputPath) of the Angular project "${options.project}" in angular.json`
60 | );
61 | }
62 |
63 | project.targets.add({
64 | name: 'deploy',
65 | builder: 'ngx-deploy-docker:deploy',
66 | options: {
67 | account: options.account,
68 | },
69 | });
70 |
71 | workspaces.writeWorkspace(workspace, host);
72 | return tree;
73 | }
74 |
75 | function prepareDockerFiles(
76 | tree: Tree,
77 | workspace: WorkspaceDefinition,
78 | options: NgAddOptions
79 | ): Rule {
80 | const sourceTemplates = url('./files');
81 |
82 | const outputPath =
83 | workspace.projects.get(options.project)?.targets.get('build')?.options
84 | ?.outputPath || '';
85 | const version = getVersionFromPackageJson(tree);
86 | const sourceParametrizedTemplates = apply(sourceTemplates, [
87 | template({
88 | outputPath,
89 | version,
90 | }),
91 | ]);
92 |
93 | return mergeWith(sourceParametrizedTemplates);
94 | }
95 |
96 | export const ngAdd = (options: NgAddOptions) => async (
97 | tree: Tree,
98 | context: SchematicContext
99 | ) => {
100 | const host = createHost(tree);
101 | const { workspace } = await workspaces.readWorkspace('/', host);
102 |
103 | const version = getLibraryVersion();
104 | addPackageToPackageJson(tree, 'ngx-deploy-docker', `^${version}`);
105 | context.logger.log(
106 | 'info',
107 | `🐳 Added "ngx-deploy-docker@^${version}" into devDependencies`
108 | );
109 |
110 | if (options.skipInstall) {
111 | context.logger.log(
112 | 'warn',
113 | `❗️ The "--skip-install" flag was present, don't forget to install package manually`
114 | );
115 | } else {
116 | context.logger.log('info', `📦 Installing added packages...`);
117 | context.addTask(new NodePackageInstallTask());
118 | }
119 |
120 | addDeployBuilderToProject(tree, host, workspace, options);
121 | context.logger.log('info', `🚀 Deploy Builder added to your project`);
122 |
123 | context.logger.log('info', 'Preparing some 🐳 files...');
124 | return chain([prepareDockerFiles(tree, workspace, options)]);
125 | };
126 |
--------------------------------------------------------------------------------
/schematics/ng-add/schema.d.ts:
--------------------------------------------------------------------------------
1 | export interface Schema {
2 | account: string;
3 | project: string;
4 | skipInstall: boolean;
5 | }
6 |
--------------------------------------------------------------------------------
/schematics/ng-add/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "http://json-schema.org/schema",
3 | "$id": "NgxDeployDockerAddSchematic",
4 | "title": "Add ngx-deploy-docker to Your Project",
5 | "type": "object",
6 | "properties": {
7 | "account": {
8 | "type": "string",
9 | "description": "Your Docker account",
10 | "x-prompt": "What is your Docker account/username?",
11 | "alias": "a"
12 | },
13 | "project": {
14 | "type": "string",
15 | "description": "The name of the project",
16 | "alias": "p"
17 | },
18 | "skipInstall": {
19 | "type": "boolean",
20 | "description": "Skip installing after adding ngx-deploy-docker",
21 | "default": false
22 | }
23 | },
24 | "required": [],
25 | "additionalProperties": false
26 | }
27 |
--------------------------------------------------------------------------------
/schematics/utils.ts:
--------------------------------------------------------------------------------
1 | import fs from 'fs';
2 | import path from 'path';
3 |
4 | import { virtualFs, workspaces } from '@angular-devkit/core';
5 | import { SchematicsException, Tree } from '@angular-devkit/schematics';
6 |
7 | export function createHost(tree: Tree): workspaces.WorkspaceHost {
8 | return {
9 | async readFile(path: string): Promise {
10 | const data = tree.read(path);
11 | if (!data) {
12 | throw new SchematicsException('File not found.');
13 | }
14 | return virtualFs.fileBufferToString(data);
15 | },
16 | async writeFile(path: string, data: string): Promise {
17 | return tree.overwrite(path, data);
18 | },
19 | async isDirectory(path: string): Promise {
20 | return !tree.exists(path) && tree.getDir(path).subfiles.length > 0;
21 | },
22 | async isFile(path: string): Promise {
23 | return tree.exists(path);
24 | },
25 | };
26 | }
27 |
28 | export function getLibraryVersion() {
29 | return JSON.parse(
30 | fs.readFileSync(path.join(__dirname, '../package.json'), 'utf8')
31 | ).version;
32 | }
33 |
34 | export function getVersionFromPackageJson(host: Tree): string {
35 | const sourceText = host.read('package.json')!.toString('utf-8');
36 | const packageJson = JSON.parse(sourceText);
37 |
38 | return packageJson.version || '';
39 | }
40 |
41 | export function addPackageToPackageJson(
42 | tree: Tree,
43 | pkg: string,
44 | version: string
45 | ): Tree {
46 | if (tree.exists('package.json')) {
47 | const sourceText = tree.read('package.json')!.toString('utf-8');
48 | const json = JSON.parse(sourceText);
49 |
50 | if (!json.devDependencies) {
51 | json.devDependencies = {};
52 | }
53 |
54 | if (!json.devDependencies[pkg]) {
55 | json.devDependencies[pkg] = version;
56 | json.devDependencies = sortObjectByKeys(json.devDependencies);
57 | }
58 |
59 | tree.overwrite('package.json', JSON.stringify(json, null, 2));
60 | }
61 |
62 | return tree;
63 | }
64 |
65 | function sortObjectByKeys(obj: any) {
66 | return Object.keys(obj)
67 | .sort()
68 | .reduce((result: any, key) => {
69 | result[key] = obj[key];
70 | return result;
71 | }, {});
72 | }
73 |
--------------------------------------------------------------------------------
/src/builders.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "../node_modules/@angular-devkit/architect/src/builders-schema.json",
3 | "builders": {
4 | "deploy": {
5 | "implementation": "./deploy/builder",
6 | "schema": "./deploy/schema.json",
7 | "description": "Deploy builder"
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/deploy/actions.ts:
--------------------------------------------------------------------------------
1 | import { BuildTarget } from './../interfaces';
2 | import {
3 | BuilderContext,
4 | targetFromTargetString,
5 | } from '@angular-devkit/architect';
6 | import { json, logging } from '@angular-devkit/core';
7 |
8 | import { Schema } from './schema';
9 |
10 | export default async function deploy(
11 | engine: {
12 | run: (options: Schema, logger: logging.LoggerApi) => Promise;
13 | },
14 | context: BuilderContext,
15 | buildTarget: BuildTarget,
16 | options: Schema
17 | ) {
18 | // 1. BUILD
19 | if (options.noBuild) {
20 | context.logger.info(`📦 Skipping build`);
21 | } else {
22 | if (!context.target) {
23 | throw new Error('Cannot execute the build target');
24 | }
25 |
26 | const overrides = {
27 | ...(options.baseHref && { baseHref: options.baseHref }),
28 | };
29 |
30 | context.logger.info(`📦 Building "${context.target.project}"`);
31 | context.logger.info(`📦 Build target "${buildTarget.name}"`);
32 |
33 | const build = await context.scheduleTarget(
34 | targetFromTargetString(buildTarget.name),
35 | {
36 | ...buildTarget.options,
37 | ...overrides,
38 | }
39 | );
40 | const buildResult = await build.result;
41 |
42 | if (!buildResult.success) {
43 | throw new Error('Error while building the app.');
44 | }
45 | }
46 |
47 | // 2. DEPLOYMENT
48 |
49 | if (!options.imageName) {
50 | options.imageName = await context.target?.project;
51 | }
52 |
53 | await engine.run(options, (context.logger as unknown) as logging.LoggerApi);
54 | }
55 |
--------------------------------------------------------------------------------
/src/deploy/builder.ts:
--------------------------------------------------------------------------------
1 | import {
2 | BuilderContext,
3 | BuilderOutput,
4 | createBuilder,
5 | } from '@angular-devkit/architect';
6 | import { experimental, normalize } from '@angular-devkit/core';
7 | import { NodeJsSyncHost } from '@angular-devkit/core/node';
8 |
9 | import * as engine from '../engine/engine';
10 | import deploy from './actions';
11 | import { Schema } from './schema';
12 |
13 | // Call the createBuilder() function to create a builder. This mirrors
14 | // createJobHandler() but add typings specific to Architect Builders.
15 | export default createBuilder(
16 | async (options: Schema, context: BuilderContext): Promise => {
17 | if (!context.target) {
18 | throw new Error('Cannot deploy the application without a target');
19 | }
20 |
21 | const buildTarget = {
22 | name: options.buildTarget || `${context.target.project}:build:production`,
23 | };
24 |
25 | try {
26 | await deploy(engine, context, buildTarget, options);
27 | } catch (e) {
28 | context.logger.error('❌ An error occurred when trying to deploy:');
29 | context.logger.error(e.message);
30 | return { success: false };
31 | }
32 |
33 | return { success: true };
34 | }
35 | );
36 |
--------------------------------------------------------------------------------
/src/deploy/schema.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Deployment of Angular CLI applications to the file system
3 | */
4 | export interface Schema {
5 | /**
6 | * Base url for the application being built. Same as `ng build --base-href=/XXX/`.
7 | */
8 | baseHref?: string;
9 | /**
10 | * 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`.
11 | */
12 | buildTarget?: string;
13 | /**
14 | * Skip build process during deployment.
15 | */
16 | noBuild?: boolean;
17 |
18 | /**
19 | * The Name of the Docker Image you want to deploy. If not present, the project name will be taken.
20 | */
21 | imageName?: string;
22 |
23 | /**
24 | * The Account you want to publish the image too. Default is your docker username.
25 | */
26 | account?: string;
27 |
28 | /**
29 | * The Tag you want to publish the image with.
30 | */
31 | tag?: string;
32 | }
33 |
--------------------------------------------------------------------------------
/src/deploy/schema.json:
--------------------------------------------------------------------------------
1 | {
2 | "$id": "Schema",
3 | "title": "schema",
4 | "description": "Deployment of Angular CLI applications to the file system",
5 | "properties": {
6 | "baseHref": {
7 | "type": "string",
8 | "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/`."
9 | },
10 | "buildTarget": {
11 | "type": "string",
12 | "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 run :."
13 | },
14 | "noBuild": {
15 | "type": "boolean",
16 | "default": false,
17 | "description": "Skip build process during deployment."
18 | },
19 | "imageName": {
20 | "type": "string",
21 | "description": "The Name of the Docker Image you want to deploy. If not present, the project name will be taken."
22 | },
23 | "account": {
24 | "type": "string",
25 | "default": "",
26 | "description": "The Account you want to publish the image too. Default is your docker username.",
27 | "alias": "a"
28 | },
29 | "tag": {
30 | "type": "string",
31 | "description": "The Tag you want to publish the image with.",
32 | "default": "latest",
33 | "alias": "t"
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/engine/engine.ts:
--------------------------------------------------------------------------------
1 | import { logging } from '@angular-devkit/core';
2 |
3 | import { Schema } from '../deploy/schema';
4 |
5 | import * as child_process from 'child_process';
6 |
7 | function getImageNameWithTag(options: Schema): string {
8 | return options.account !== ''
9 | ? `${options.account}/${options.imageName}:${options.tag}`
10 | : `${options.imageName}:${options.tag}`;
11 | }
12 |
13 | async function buildDockerImage(
14 | imageNameWithTag: string,
15 | logger: logging.LoggerApi
16 | ): Promise {
17 | // context.reportStatus(`Executing "docker build"...`);
18 | const child = child_process.spawn(
19 | 'docker',
20 | ['build', '-t', imageNameWithTag, '.'],
21 | {
22 | stdio: 'pipe',
23 | }
24 | );
25 |
26 | child.stdout.on('data', (data) => {
27 | logger.info(data.toString());
28 | });
29 | child.stderr.on('data', (data) => {
30 | logger.error(data.toString());
31 | });
32 |
33 | return new Promise((resolve) => {
34 | // context.reportStatus(`Done.`);
35 | child.on('close', (code) => {
36 | resolve();
37 | });
38 | });
39 | }
40 |
41 | async function publishDockerImage(
42 | imageNameWithTag: string,
43 | logger: logging.LoggerApi
44 | ): Promise {
45 | const child = child_process.spawn('docker', ['push', imageNameWithTag], {
46 | stdio: 'pipe',
47 | });
48 |
49 | child.stdout.on('data', (data) => {
50 | logger.info(data.toString());
51 | });
52 | child.stderr.on('data', (data) => {
53 | logger.error(data.toString());
54 | });
55 |
56 | return new Promise((resolve) => {
57 | // context.reportStatus(`Done.`);
58 | child.on('close', (code) => {
59 | resolve();
60 | });
61 | });
62 | }
63 |
64 | export async function run(options: Schema, logger: logging.LoggerApi) {
65 | try {
66 | const imageNameWithTag = getImageNameWithTag(options);
67 |
68 | logger.info('🚧 Executing Docker Build...');
69 | await buildDockerImage(imageNameWithTag, logger);
70 | logger.info('✔️ Docker Build was successfully');
71 |
72 | logger.info('🚀 Publishing image to registry');
73 | await publishDockerImage(imageNameWithTag, logger);
74 | logger.info('🎊 Successfully published image. Have a nice day.');
75 | } catch (error) {
76 | logger.error('❌ An error occurred!');
77 | throw error;
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/src/interfaces.ts:
--------------------------------------------------------------------------------
1 | export interface WorkspaceProject {
2 | projectType?: string;
3 | architect?: Record<
4 | string,
5 | { builder: string; options?: Record }
6 | >;
7 | }
8 |
9 | export interface Workspace {
10 | defaultProject?: string;
11 | projects: Record;
12 | }
13 |
14 | export interface BuildTarget {
15 | name: string;
16 | options?: { [name: string]: any };
17 | }
18 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "experimentalDecorators": true,
5 | "emitDecoratorMetadata": true,
6 | "module": "CommonJS",
7 | "target": "es2015",
8 | "noImplicitAny": false,
9 | "outDir": "dist",
10 | "rootDir": ".",
11 | "sourceMap": true,
12 | "inlineSources": true,
13 | "declaration": false,
14 | "removeComments": true,
15 | "strictNullChecks": true,
16 | "lib": [
17 | "es2015",
18 | "dom",
19 | "es2015.promise",
20 | "es2015.collection",
21 | "es2015.iterable"
22 | ],
23 | "skipLibCheck": true,
24 | "moduleResolution": "Node",
25 | "esModuleInterop": true,
26 | "types": ["node"]
27 | },
28 | "files": ["index.ts"],
29 | "exclude": ["./**/*.spec.ts", "./schematics/**/files/**/*"],
30 | "angularCompilerOptions": {
31 | "skipTemplateCodegen": true,
32 | "strictMetadataEmit": true,
33 | "enableSummariesForJit": false
34 | }
35 | }
36 |
--------------------------------------------------------------------------------