├── .all-contributorsrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ ├── ci.yml │ └── release.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── .verdaccio └── config.yml ├── .vscode ├── extensions.json └── settings.json ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── apps └── .gitkeep ├── jest.config.ts ├── jest.preset.js ├── libs ├── .gitkeep └── nx-release │ ├── .all-contributorsrc │ ├── .eslintrc.json │ ├── README.md │ ├── assets │ └── nx-release-logo.svg │ ├── executors.json │ ├── generators.json │ ├── jest.config.ts │ ├── package.json │ ├── project.json │ ├── src │ ├── executors │ │ ├── build-update-publish │ │ │ ├── executor.spec.ts │ │ │ ├── executor.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ ├── helpers │ │ │ ├── projects.helpers.spec.ts │ │ │ └── projects.helpers.ts │ │ ├── npm-publish │ │ │ ├── executor.spec.ts │ │ │ ├── executor.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ └── update-version │ │ │ ├── executor.spec.ts │ │ │ ├── executor.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ ├── generators │ │ ├── configure-libraries │ │ │ ├── generator.spec.ts │ │ │ ├── generator.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ ├── configure-library │ │ │ ├── generator.spec.ts │ │ │ ├── generator.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ ├── configure-workspace │ │ │ ├── generator.spec.ts │ │ │ ├── generator.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ ├── configure │ │ │ ├── generator.spec.ts │ │ │ ├── generator.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ ├── generate-gh-actions │ │ │ ├── files │ │ │ │ └── .github │ │ │ │ │ └── workflows │ │ │ │ │ ├── ci.yml │ │ │ │ │ └── release.yml │ │ │ ├── generator.spec.ts │ │ │ ├── generator.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ ├── generate-release-config │ │ │ ├── files │ │ │ │ └── release.config.js.template │ │ │ ├── generator.spec.ts │ │ │ ├── generator.ts │ │ │ ├── schema.d.ts │ │ │ └── schema.json │ │ └── helpers │ │ │ ├── projects.helpers.spec.ts │ │ │ ├── projects.helpers.ts │ │ │ └── spinner.helper.ts │ └── index.ts │ ├── tsconfig.json │ ├── tsconfig.lib.json │ └── tsconfig.spec.json ├── nx.json ├── package-lock.json ├── package.json ├── project.json ├── release.config.js ├── tools ├── scripts │ └── publish.mjs └── tsconfig.tools.json └── tsconfig.base.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "files": [ 3 | "README.md" 4 | ], 5 | "imageSize": 100, 6 | "commit": false, 7 | "commitType": "docs", 8 | "commitConvention": "angular", 9 | "contributors": [ 10 | { 11 | "login": "ajitzero", 12 | "name": "Ajit Panigrahi", 13 | "avatar_url": "https://avatars.githubusercontent.com/u/19947758?v=4", 14 | "profile": "https://beta.ajitpanigrahi.com", 15 | "contributions": [ 16 | "doc" 17 | ] 18 | }, 19 | { 20 | "login": "canserkanuren", 21 | "name": "Can Serkan UREN", 22 | "avatar_url": "https://avatars.githubusercontent.com/u/22659909?v=4", 23 | "profile": "https://github.com/canserkanuren", 24 | "contributions": [ 25 | "code", 26 | "ideas", 27 | "test" 28 | ] 29 | }, 30 | { 31 | "login": "markuczy", 32 | "name": "markuczy", 33 | "avatar_url": "https://avatars.githubusercontent.com/u/129275100?v=4", 34 | "profile": "https://github.com/markuczy", 35 | "contributions": [ 36 | "code" 37 | ] 38 | } 39 | ], 40 | "contributorsPerLine": 7, 41 | "skipCi": true, 42 | "repoType": "github", 43 | "repoHost": "https://github.com", 44 | "projectName": "nx-release", 45 | "projectOwner": "nivekcode" 46 | } 47 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "ignorePatterns": ["**/*"], 4 | "plugins": ["@nx"], 5 | "overrides": [ 6 | { 7 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 8 | "rules": { 9 | "@nx/enforce-module-boundaries": [ 10 | "error", 11 | { 12 | "enforceBuildableLibDependency": true, 13 | "allow": [], 14 | "depConstraints": [ 15 | { 16 | "sourceTag": "*", 17 | "onlyDependOnLibsWithTags": ["*"] 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | }, 24 | { 25 | "files": ["*.ts", "*.tsx"], 26 | "extends": ["plugin:@nx/typescript"], 27 | "rules": {} 28 | }, 29 | { 30 | "files": ["*.js", "*.jsx"], 31 | "extends": ["plugin:@nx/javascript"], 32 | "rules": {} 33 | }, 34 | { 35 | "files": ["*.spec.ts", "*.spec.tsx", "*.spec.js", "*.spec.jsx"], 36 | "env": { 37 | "jest": true 38 | }, 39 | "rules": {} 40 | }, 41 | { 42 | "files": "*.json", 43 | "parser": "jsonc-eslint-parser", 44 | "rules": {} 45 | } 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - '*' 6 | - '*/*' 7 | - '**' 8 | - '!main' 9 | jobs: 10 | main: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | - uses: nrwl/nx-set-shas@v3 17 | - name: Install deps 18 | run: npm ci 19 | - name: Lint affected 20 | run: npx nx affected -t lint 21 | - name: Test affected 22 | run: npm run test:coverage 23 | - name: Report coverage 24 | uses: coverallsapp/github-action@v2 25 | - name: Build affected 26 | run: npx nx affected -t build 27 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: RELEASE 2 | on: [workflow_dispatch] 3 | jobs: 4 | main: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | with: 9 | fetch-depth: 0 10 | - uses: nrwl/nx-set-shas@v3 11 | - name: Install deps 12 | run: npm ci 13 | - name: Lint 14 | run: npx nx run-many -t lint 15 | - name: Test 16 | run: npm run test:coverage 17 | - name: Report coverage 18 | uses: coverallsapp/github-action@v2 19 | - name: Release 20 | run: npx semantic-release 21 | env: 22 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} 23 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | dist 5 | tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | yarn-error.log 34 | testem.log 35 | /typings 36 | 37 | # System Files 38 | .DS_Store 39 | Thumbs.db 40 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | # Add files here to ignore them from prettier formatting 2 | /dist 3 | /coverage -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /.verdaccio/config.yml: -------------------------------------------------------------------------------- 1 | # path to a directory with all packages 2 | storage: ../tmp/local-registry/storage 3 | 4 | # a list of other known repositories we can talk to 5 | uplinks: 6 | npmjs: 7 | url: https://registry.npmjs.org/ 8 | maxage: 60m 9 | 10 | packages: 11 | '**': 12 | # give all users (including non-authenticated users) full access 13 | # because it is a local registry 14 | access: $all 15 | publish: $all 16 | unpublish: $all 17 | 18 | # if package is not available locally, proxy requests to npm registry 19 | proxy: npmjs 20 | 21 | # log settings 22 | logs: 23 | type: stdout 24 | format: pretty 25 | level: warn 26 | 27 | publish: 28 | allow_offline: true # set offline to true to allow publish offline 29 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "nrwl.angular-console", 4 | "esbenp.prettier-vscode", 5 | "dbaeumer.vscode-eslint", 6 | "firsttris.vscode-jest-runner" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "eslint.validate": ["json"] 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [3.4.0](https://github.com/kreuzerk/nx-release/compare/v3.3.0...v3.4.0) (2025-01-08) 2 | 3 | 4 | ### Features 5 | 6 | * npm publish uses distribution tags ([8715172](https://github.com/kreuzerk/nx-release/commit/8715172a939c524d2fcef37d8090b000891a096a)) 7 | 8 | 9 | ### Refactoring 10 | 11 | * remove trailing semicolon ([ed04275](https://github.com/kreuzerk/nx-release/commit/ed042756c90dc84587f18eb2ff3d99e280916679)) 12 | * revert formatting ([4b3005d](https://github.com/kreuzerk/nx-release/commit/4b3005d239fb4836ec290404002a80875d586a07)) 13 | * revert further format changes ([a04186d](https://github.com/kreuzerk/nx-release/commit/a04186d853bd5feb36b96abc7e8471bb354dde4c)) 14 | 15 | ## [3.3.0](https://github.com/kreuzerk/nx-release/compare/v3.2.0...v3.3.0) (2024-01-20) 16 | 17 | 18 | ### Features 19 | 20 | * **npm-publish:** do not override current .npmrc file ([c71f7dd](https://github.com/kreuzerk/nx-release/commit/c71f7dd000593d4ffb869a5d26db4850690adc76)) 21 | 22 | ## [3.2.0](https://github.com/kreuzerk/nx-release/compare/v3.1.6...v3.2.0) (2024-01-18) 23 | 24 | 25 | ### Features 26 | 27 | * **npm-publish:** add option to specify npm registry ([f576088](https://github.com/kreuzerk/nx-release/commit/f5760886cb332702a7fb3e025ec3e2148f50bc16)) 28 | 29 | ## [3.1.6](https://github.com/kreuzerk/nx-release/compare/v3.1.5...v3.1.6) (2023-09-27) 30 | 31 | 32 | ### Bug Fixes 33 | 34 | * 🐛 add missing inquirer dependency ([c05a44b](https://github.com/kreuzerk/nx-release/commit/c05a44bef872c0acce6c2d1f609dcb5db45c4782)) 35 | 36 | ## [3.1.5](https://github.com/kreuzerk/nx-release/compare/v3.1.4...v3.1.5) (2023-07-13) 37 | 38 | 39 | ### Bug Fixes 40 | 41 | * 🐛 trigger release ([d5b78a3](https://github.com/kreuzerk/nx-release/commit/d5b78a3f1139147dc1374e7a1ffc4b25c1028f7b)) 42 | 43 | ## [3.1.4](https://github.com/kreuzerk/nx-release/compare/v3.1.3...v3.1.4) (2023-07-12) 44 | 45 | 46 | ### Bug Fixes 47 | 48 | * 🐛 install missing conventional commits dep ([4671b5e](https://github.com/kreuzerk/nx-release/commit/4671b5e04d46edadba2221e510edd2e3fdb29b0b)) 49 | 50 | ## [3.1.3](https://github.com/kreuzerk/nx-release/compare/v3.1.2...v3.1.3) (2023-07-11) 51 | 52 | 53 | ### Bug Fixes 54 | 55 | * 🐛 remove the all selection option ([2fc13d0](https://github.com/kreuzerk/nx-release/commit/2fc13d00bb43ec5f7378a002af6c6bc3f3965f6f)) 56 | 57 | ## [3.1.2](https://github.com/kreuzerk/nx-release/compare/v3.1.1...v3.1.2) (2023-07-11) 58 | 59 | 60 | ### Bug Fixes 61 | 62 | * 🐛 generate files before installing ([928237f](https://github.com/kreuzerk/nx-release/commit/928237fab4d8b2771dc0918fbb351cccb5209641)) 63 | 64 | ## [3.1.1](https://github.com/kreuzerk/nx-release/compare/v3.1.0...v3.1.1) (2023-07-11) 65 | 66 | 67 | ### Bug Fixes 68 | 69 | * 🐛 update tslib dep ([8464424](https://github.com/kreuzerk/nx-release/commit/84644240b9a34cf5babb0cb0bc7fdd3e1941ae1f)) 70 | 71 | ## [3.1.0](https://github.com/kreuzerk/nx-release/compare/v3.0.0...v3.1.0) (2023-07-11) 72 | 73 | 74 | ### Features 75 | 76 | * 🎸 select all option on libraries configurator ([22a3208](https://github.com/kreuzerk/nx-release/commit/22a320857e423a95ec361dbf793cb2a6c4391f16)) 77 | 78 | 79 | ### Chores 80 | 81 | * 🤖 add test libs ([0e29dd2](https://github.com/kreuzerk/nx-release/commit/0e29dd2abde2a32763fbb94cc1f53dc40b123d4b)) 82 | * 🤖 remove release target from nx-release project.json ([c68b49e](https://github.com/kreuzerk/nx-release/commit/c68b49eb2d909305162bd1f736a57faf84d84fdb)) 83 | 84 | ## [3.0.0](https://github.com/kreuzerk/nx-release/compare/v2.1.0...v3.0.0) (2023-07-11) 85 | 86 | 87 | ### ⚠ BREAKING CHANGES 88 | 89 | * 🧨 libName option input is removed 90 | 91 | ### Features 92 | 93 | * 🎸 add configure libraries generator ([ec61506](https://github.com/kreuzerk/nx-release/commit/ec61506593306bf56fe29c71600a5094a78db300)) 94 | * 🎸 add configure libraries generator ([e445d24](https://github.com/kreuzerk/nx-release/commit/e445d24ee72ed70555c48179a029da8f390df4b1)) 95 | * 🎸 add configure library generator ([e615fcf](https://github.com/kreuzerk/nx-release/commit/e615fcf82075199ffcdfbd3f684a45239b17aa0b)) 96 | * 🎸 add configure-libraries generator ([ed1ba0b](https://github.com/kreuzerk/nx-release/commit/ed1ba0bb55d0033a76264cc1a68d3b6741e0d8e5)) 97 | * 🎸 add required prompts ([f6d1a67](https://github.com/kreuzerk/nx-release/commit/f6d1a67410e558f7f39d49d7d3965116a6248276)) 98 | * 🎸 add workspace configuration generator ([dbe072f](https://github.com/kreuzerk/nx-release/commit/dbe072f69a4c87e432c466142a97c1a892baac45)) 99 | * 🎸 add workspace configurator generator ([92cca1c](https://github.com/kreuzerk/nx-release/commit/92cca1c710180b366e5342eac1d192b71a643e52)) 100 | * 🎸 extract gh-action and release config into generators ([7dfd196](https://github.com/kreuzerk/nx-release/commit/7dfd196882032559708eae9c543a7611a9452115)) 101 | * 🎸 improve executors ([b1410d7](https://github.com/kreuzerk/nx-release/commit/b1410d7097cc39cada83d46d8a5b609c0c0f818d)) 102 | 103 | 104 | ### Bug Fixes 105 | 106 | * 🐛 remove lib path ([ad8d811](https://github.com/kreuzerk/nx-release/commit/ad8d811ddf0c91653122642892bcf10dd2da5628)) 107 | * 🐛 remove required options ([94e8ee9](https://github.com/kreuzerk/nx-release/commit/94e8ee926d6a45a41dd30e3e6b9c1267858a7875)) 108 | * 🐛 update generate GitHub actions workflow generator ([556fbc8](https://github.com/kreuzerk/nx-release/commit/556fbc8a30a1b0f8d2a1fb81a57f7d7fb00708a6)) 109 | * 🐛 use correct source root ([c0f6933](https://github.com/kreuzerk/nx-release/commit/c0f693381948cda70ab35ddabb6791a55199faab)) 110 | * 🐛 use root instead of src root ([0296ab9](https://github.com/kreuzerk/nx-release/commit/0296ab9ef9f887ccf3ad60220951f4ba9a6bbcb2)) 111 | 112 | 113 | ### Chores 114 | 115 | * 🤖 add all-contributors as dep ([d64a92a](https://github.com/kreuzerk/nx-release/commit/d64a92a531633977ded5e7956137f7d7ef8221d2)) 116 | * 🤖 adjust build scripts ([09b16e5](https://github.com/kreuzerk/nx-release/commit/09b16e5d2757ab82df1eb7dbe5ef68648e28127e)) 117 | * 🤖 generate coverage report ([8f6dec1](https://github.com/kreuzerk/nx-release/commit/8f6dec1125f47086cd9aa1e9e2947f5f630dfdd0)) 118 | * 🤖 remove test libraries ([bba255e](https://github.com/kreuzerk/nx-release/commit/bba255e96c1734f9055415db9066bd36a4801b86)) 119 | * 🤖 run tests with release ([a12438d](https://github.com/kreuzerk/nx-release/commit/a12438dbadeca96aa72152d6e20652af5afd3820)) 120 | 121 | 122 | ### Refactoring 123 | 124 | * 💡 generators and update docs ([f3b0d3d](https://github.com/kreuzerk/nx-release/commit/f3b0d3db0bf361e851eb4c11bb7f493fa66349f1)) 125 | 126 | ## [2.1.0](https://github.com/kreuzerk/nx-release/compare/v2.0.0...v2.1.0) (2023-07-07) 127 | 128 | 129 | ### Features 130 | 131 | * 🎸 add build, update & publish executor ([80357c1](https://github.com/kreuzerk/nx-release/commit/80357c16c4a0b2484b754e34061e4ae080cb7a48)) 132 | 133 | ## [2.0.0](https://github.com/kreuzerk/nx-release/compare/v1.0.1...v2.0.0) (2023-07-07) 134 | 135 | 136 | ### ⚠ BREAKING CHANGES 137 | 138 | * 🧨 version input is no longer supported 139 | 140 | ### Features 141 | 142 | * 🎸 access version from node env ([cc684d3](https://github.com/kreuzerk/nx-release/commit/cc684d348d8430eec09d6450df4b5285973f39f4)) 143 | 144 | ## [1.0.1](https://github.com/kreuzerk/nx-release/compare/v1.0.0...v1.0.1) (2023-07-07) 145 | 146 | 147 | ### Bug Fixes 148 | 149 | * 🐛 use exec sync ([cae8041](https://github.com/kreuzerk/nx-release/commit/cae80410db9dde03d1ce13d96ef8fccee31bc46f)) 150 | 151 | ## 1.0.0 (2023-07-07) 152 | 153 | 154 | ### Features 155 | 156 | * 🎸 implement executors ([f4bc2a7](https://github.com/kreuzerk/nx-release/commit/f4bc2a73860e2815da4ddbdee877edc52eef3f9f)) 157 | 158 | 159 | ### Chores 160 | 161 | * 🤖 add dedicated release script ([4cb00ff](https://github.com/kreuzerk/nx-release/commit/4cb00ff0d32419a5d9e672378068a070984ad51a)) 162 | * 🤖 add npm publish script ([9ec7052](https://github.com/kreuzerk/nx-release/commit/9ec705267e06def9a316bc690677a80124da8b05)) 163 | * 🤖 prepare for release ([c19dc1f](https://github.com/kreuzerk/nx-release/commit/c19dc1fe47ea5343da9d32f7a502914d51cb3f9d)) 164 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | Contributor Covenant Code of Conduct Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 2 | 3 | Our Standards Examples of behavior that contributes to creating a positive environment include: 4 | 5 | Using welcoming and inclusive language Being respectful of differing viewpoints and experiences Gracefully accepting constructive criticism Focusing on what is best for the community Showing empathy towards other community members Examples of unacceptable behavior by participants include: 6 | 7 | The use of sexualized language or imagery and unwelcome sexual attention or advances Trolling, insulting/derogatory comments, and personal or political attacks Public or private harassment Publishing others' private information, such as a physical or electronic address, without explicit permission Other conduct which could reasonably be considered inappropriate in a professional setting Our Responsibilities 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. 8 | 9 | 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. 10 | 11 | Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. 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. 12 | 13 | Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at kevin.kreuzer90@icloud.com. The project team will review and investigate all complaints, and will respond in a way that it deems 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. 14 | 15 | 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. 16 | 17 | Attribution This Code of Conduct is adapted from the Contributor Covenant, version 1.4, available at http://contributor-covenant.org/version/1/4 18 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | Contributing 2 | A big welcome and thank you for considering contributing to the project. 3 | 4 | Reading and following these guidelines will help us make the contribution process easy and effective for everyone involved. It also communicates that you agree to respect the time of the developers managing and developing these open source projects. In return, we will reciprocate that respect by addressing your issue, assessing changes, and helping you finalize your pull requests. 5 | 6 | Quicklinks 7 | Code of Conduct 8 | Commit Convention 9 | Code of Conduct 10 | We take our open source community seriously and hold ourselves and other contributors to high standards of communication. By participating and contributing to this project, you agree to uphold our Code of Conduct. 11 | 12 | Commit Convention 13 | This project uses the conventional commit format and is commitizen friendly, using npm run commit instead of git commit will run you through a step by step command line process to generate a valid commit message. 14 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 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 | ![](https://github.com/kreuzerk/nx-release/blob/main/libs/nx-release/assets/nx-release-logo.svg) 2 | 3 | 4 | [![All Contributors](https://img.shields.io/badge/all_contributors-3-orange.svg?style=flat-square)](#contributors-) 5 | 6 | 7 | This library contains executors and generators. 8 | 9 | Your go-to open-source library for effortless semantic releases of NPM libraries within a monorepo. This repository provides generators and executors for a fully automated release setup that contains commit analysis, automated versioning, changelog generation, and publishing. 10 | 11 | The library provides generators and executors: 12 | 13 | - Generators 14 | - Executors 15 | 16 | 17 | 18 | **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* 19 | 20 | - [Getting started](#getting-started) 21 | - [Installation](#installation) 22 | - [Configuring the workspace](#configuring-the-workspace) 23 | - [GitHub repository setup](#github-repository-setup) 24 | - [1. Provide access tokens](#1-provide-access-tokens) 25 | - [2. Actions write permissions](#2-actions-write-permissions) 26 | - [Generators](#generators) 27 | - [configure](#configure) 28 | - [configure-workspace](#configure-workspace) 29 | - [configure-library](#configure-library) 30 | - [configure-libraries](#configure-libraries) 31 | - [generate-gh-actions](#generate-gh-actions) 32 | - [generate-release-config](#generate-release-config) 33 | - [Executors](#executors) 34 | - [npm-publish](#npm-publish) 35 | - [update-version](#update-version) 36 | - [build-update-publish](#build-update-publish) 37 | - [Contributors ✨](#contributors-) 38 | 39 | 40 | 41 | # Getting started 42 | 43 | ## Installation 44 | 45 | ```npm i -D nx-release``` 46 | 47 | ## Configuring the workspace 48 | 49 | To configure your Nx workspace for releasing, you can invoke the main generator provided by `nx-release`. 50 | 51 | ```npx nx g nx-release:configure``` 52 | 53 | This command will prompt all the required options. 54 | 55 | ## GitHub repository setup 56 | 57 | To enable full automated releases, you have to configure your GitHub repository in two steps: 58 | 59 | ### 1. Provide access tokens 60 | 61 | To enable a fully automated release, we need access rights to publish the artifact to npm and commit back to your repository. Therefore you have to provide the following tokens as action secrets. 62 | 63 | > To create an action secret navigate to your GitHub repository / Settings / Secrets and Variables / Actions / New Repository secret 64 | 65 | Here you have to provide the following two secrets: 66 | 67 | - **GH_TOKEN**: repo scope 68 | - **NPM_TOKEN**: scope CI automation 69 | 70 | Those tokens will then be picked up and provided as environment variables by the `release.yml` generated by `nx-release`. 71 | 72 | ### 2. Actions write permissions 73 | 74 | Since our workflow will commit back release artifacts such as `CHANGELOG`, tags, and update versions inside the `package.json`, our actions need write permissions. To give GitHub Actions write permissions, navigate again to your repository, then go to `Settings / Actions / General / Workflow Permissions / Read and write permissions / Save`. 75 | 76 | # Generators 77 | 78 | The provided generators help you set up an automated library-releasing process in an existing NX workspace. This process works for all kinds of libraries since it's framework-agnostic. The following generators are provided: 79 | 80 | ## configure 81 | 82 | The `configure` workspace generator allows you to set up the workspace plus the libraries of your choice. Internally this generator calls the `configure-workspace` as well as the `configure-libraries` generator. The generator can be invoked with the following command: 83 | 84 | ```npx nx g nx-release:configure``` 85 | 86 | The generators provide the following options: 87 | 88 | | option | description | default | prompted | 89 | | --------------------- | ------------------------------------------------------------ | ------- | -------- | 90 | | installDeps | Should we install semantic-release and all the required plugins | true | yes | 91 | | generateReleaseConfig | Should we generate a semantic-release configuration at the root of your workspace | true | yes | 92 | | generateGhActions | Should we generate GitHub actions for feature branches and releases | true | yes | 93 | | publicPublishConfig | Should we add public publish config for your library | true | Yes | 94 | 95 | ## configure-workspace 96 | 97 | ```npx nx g nx-release:configure-workspace``` 98 | 99 | The `configure-workspace` generator allows you to set up automated releases on a **workspace level only**. The generator will then prompt the following options: 100 | 101 | | option | description | default | prompted | 102 | | --------------------- | ------------------------------------------------------------ | ------- | -------- | 103 | | installDeps | Should we install semantic-release and all the required plugins | true | yes | 104 | | generateReleaseConfig | Should we generate a semantic-release configuration at the root of your workspace | true | yes | 105 | | generateGhActions | Should we generate GitHub actions for feature branches and releases | True | yes | 106 | 107 | ## configure-library 108 | 109 | ```npx nx g nx-release:configure-library``` 110 | 111 | The `configure-library` generator sets up a library for semantic release. When setting up the library, it will use some of the executors provided by `nx-release`. 112 | 113 | | option | description | default | prompted | 114 | | ------------------- | ---------------------------------------------------- | ------- | ----------------------------------- | 115 | | publicPublishConfig | Should we add public publish config for your library | true | yes | 116 | | libName | The name of the library that should be configured | | only if nothing is passed initially | 117 | 118 | ## configure-libraries 119 | 120 | ```npx nx g nx-release:configure-libraries``` 121 | 122 | The `configure-libraries` generator sets up multiple libraries for semantic release. When setting up the libraries, it will use some of the executors provided by `nx-release`. 123 | 124 | | option | description | default | prompted | 125 | | ------------------- | ---------------------------------------------------- | ------- | --------------------------------- | 126 | | publicPublishConfig | Should we add public publish config for your library | true | yes | 127 | | libName | The name of the library that should be configured | | will be prompted during execution | 128 | 129 | ## generate-gh-actions 130 | 131 | ```npx nx g nx-release:generate-gh-actions``` 132 | 133 | This generator can be used to generate two workflow files for automated releases. This generator will generate the following two files: 134 | 135 | - ci.yml (this file configures a pipeline that is run on Pull request) 136 | - release.yml (file that releases the library / by default; it has to be triggered manually) 137 | 138 | ## generate-release-config 139 | 140 | ```npx nx g nx-release:generate-release-config``` 141 | 142 | This generator generates a `release.config.js` file at the root of your project. 143 | 144 | # Executors 145 | 146 | ## npm-publish 147 | 148 | As the name indicates, the `npm-publish` generator can be used to publish a library to NPM. To 149 | do so, **the executor requires a `NPM_TOKEN` to be present as a Node environment variable**. 150 | 151 | 152 | ## update-version 153 | This executor updates the `package.json` version in the specified library. The executor **requires** the following config options.**The update-version executor expects a VERSION env variable to be present**. 154 | 155 | ## build-update-publish 156 | This executor combines the previous two executors and additionally performs a release. 157 | 158 | **This command expects a valid NPM token to be present as an `NPM_TOKEN` environment variable and the new release version to be present as a `VERSION` variable**. 159 | 160 | ## Contributors ✨ 161 | 162 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 |
Ajit Panigrahi
Ajit Panigrahi

📖
Can Serkan UREN
Can Serkan UREN

💻 🤔 ⚠️
markuczy
markuczy

💻
175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 197 | 198 | 199 |
Nivek
Nivek

💻
193 | 194 | Add your contributions 195 | 196 |
200 | 201 | 202 | 203 | 204 | 205 | 206 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind are welcome! 207 | -------------------------------------------------------------------------------- /apps/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nivekcode/nx-release/dec67fb7ff59167308c0161109874ce2a9b61da7/apps/.gitkeep -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import { getJestProjects } from '@nx/jest'; 2 | 3 | export default { 4 | projects: getJestProjects(), 5 | }; 6 | -------------------------------------------------------------------------------- /jest.preset.js: -------------------------------------------------------------------------------- 1 | const nxPreset = require('@nx/jest/preset').default; 2 | 3 | module.exports = { ...nxPreset }; 4 | -------------------------------------------------------------------------------- /libs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nivekcode/nx-release/dec67fb7ff59167308c0161109874ce2a9b61da7/libs/.gitkeep -------------------------------------------------------------------------------- /libs/nx-release/.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "nx-release", 3 | "projectOwner": "kreuzerk", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": ["README.md"], 7 | "imageSize": 100, 8 | "commit": true, 9 | "commitConvention": "angular", 10 | "contributors": [ 11 | { 12 | "login": "kreuzerk", 13 | "name": "Nivek", 14 | "avatar_url": "https://avatars.githubusercontent.com/u/5468954?v=4", 15 | "profile": "https://medium.com/@kevinkreuzer", 16 | "contributions": ["code"] 17 | } 18 | ], 19 | "contributorsPerLine": 7, 20 | "linkToUsage": true 21 | } 22 | 23 | -------------------------------------------------------------------------------- /libs/nx-release/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["../../.eslintrc.json"], 3 | "ignorePatterns": ["!**/*"], 4 | "overrides": [ 5 | { 6 | "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], 7 | "rules": {} 8 | }, 9 | { 10 | "files": ["*.d.ts"], 11 | "rules": { 12 | "@typescript-eslint/no-empty-interface": "off" 13 | } 14 | }, 15 | { 16 | "files": ["*.ts", "*.tsx"], 17 | "rules": {} 18 | }, 19 | { 20 | "files": ["*.spec.ts"], 21 | "rules": { 22 | "@typescript-eslint/no-empty-function": "off", 23 | "@typescript-eslint/no-explicit-any": "off" 24 | } 25 | }, 26 | { 27 | "files": ["*.js", "*.jsx"], 28 | "rules": {} 29 | }, 30 | { 31 | "files": ["./package.json", "./executors.json", "./generators.json"], 32 | "parser": "jsonc-eslint-parser", 33 | "rules": { 34 | "@nx/nx-plugin-checks": "error" 35 | } 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /libs/nx-release/README.md: -------------------------------------------------------------------------------- 1 | ![](https://github.com/kreuzerk/nx-release/blob/main/libs/nx-release/assets/nx-release-logo.svg) 2 | 3 | [![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors-) [![Coverage Status](https://coveralls.io/repos/github/kreuzerk/nx-release/badge.svg?branch=feature/generators)](https://coveralls.io/github/kreuzerk/nx-release?branch=feature/generators) 4 | 5 | 6 | 7 | This library contains executors and generators 8 | 9 | Your go-to open-source library for effortless semantic releases of NPM libraries within a monorepo. This repository provides generators and executors for a fully automated release setup that contains commit analyzation, automated versioning, changelog generation and publishing. 10 | 11 | The library provides generators and executors: 12 | 13 | - Generators 14 | - Executors 15 | 16 | 17 | 18 | **Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* 19 | 20 | - [Getting started](#getting-started) 21 | - [Installation](#installation) 22 | - [Configuring the workspace](#configuring-the-workspace) 23 | - [GitHub repository setup](#github-repository-setup) 24 | - [1. Provide access tokens](#1-provide-access-tokens) 25 | - [2. Actions write permissions](#2-actions-write-permissions) 26 | - [Generators](#generators) 27 | - [configure](#configure) 28 | - [configure-workspace](#configure-workspace) 29 | - [configure-library](#configure-library) 30 | - [configure-libraries](#configure-libraries) 31 | - [generate-gh-actions](#generate-gh-actions) 32 | - [generate-release-config](#generate-release-config) 33 | - [Executors](#executors) 34 | - [npm-publish](#npm-publish) 35 | - [update-version](#update-version) 36 | - [build-update-publish](#build-update-publish) 37 | - [Contributors ✨](#contributors-) 38 | 39 | 40 | 41 | # Getting started 42 | 43 | ## Installation 44 | 45 | ```npm i -D nx-release``` 46 | 47 | ## Configuring the workspace 48 | 49 | To configure your Nx workspace for releasing you can invoke the main generator provided by `nx-release`. 50 | 51 | ```npx nx g nx-release:configure``` 52 | 53 | This comman will prompt all the required options. 54 | 55 | ## GitHub repository setup 56 | 57 | To enable full automated releases you have to configure your GitHub repository in two steps: 58 | 59 | ### 1. Provide access tokens 60 | 61 | To enable fully automated release we need access rights to publish the artifact to npm and to commit back to your repository. Therefore you have to provide the following tokens as action secrets. 62 | 63 | > To create a action secret navigate to your GitHub repoistory / Settings / Secrets and Variables / Actions / New Repository secret 64 | 65 | Here you have to provide the following two secrets: 66 | 67 | - **GH_TOKEN**: repo scope 68 | - **NPM_TOKEN**: scope CI automation 69 | 70 | Those tokens will then be picked up and provided as environment variables by the `release.yml` generated by `nx-release`. 71 | 72 | ### 2. Actions write permissions 73 | 74 | Since our workflow will commit back release artifacts such as `CHANGELOG`, tags and update versions inside the `package.json` our actions need write permissions. To give GitHub actions write permissions navigate again to your repository then go to `Settings / Actions / General / Workflow Permissions / Read and write permissions / Save`. 75 | 76 | # Generators 77 | 78 | The provided generators help you setup automated library releasing in an existing NX workspace. This process works for all kind of libraries since its framework agnostic. The following generators are provided: 79 | 80 | ## configure 81 | 82 | The `configure` workspace generator allows you to setup the workspace plus the libraries of you choice. Internally this generator calls the `configure-workspace` as well as the `configure-libraries` generator. The generator can be invoked with the following command: 83 | 84 | ```npx nx g nx-release:configure``` 85 | 86 | The generators provides the follwing options: 87 | 88 | | option | description | default | prompted | 89 | | --------------------- | ------------------------------------------------------------ | ------- | -------- | 90 | | installDeps | Should we install semantic-release and all the required plugins | true | yes | 91 | | generateReleaseConfig | Should we generate a semantic-release configuration at the root of your workspace | true | yes | 92 | | generateGhActions | Should we generate GitHub actions for feature branches and releases | true | yes | 93 | | publicPublishConfig | Should we add public publish config for your library | true | Yes | 94 | 95 | ## configure-workspace 96 | 97 | ```npx nx g nx-release:configure-workspace``` 98 | 99 | The `configure-workspace` generator allows you to setup automated releases on a **workspace level only**. The generator will then prompt the following options: 100 | 101 | | option | description | default | prompted | 102 | | --------------------- | ------------------------------------------------------------ | ------- | -------- | 103 | | installDeps | Should we install semantic-release and all the required plugins | true | yes | 104 | | generateReleaseConfig | Should we generate a semantic-release configuration at the root of your workspace | true | yes | 105 | | generateGhActions | Should we generate GitHub actions for feature branches and releases | True | yes | 106 | 107 | ## configure-library 108 | 109 | ```npx nx g nx-release:configure-library``` 110 | 111 | The `configure-library`generator sets up a library for semantic release. When setting up the library it will use some of the executors provided by `nx-release`. 112 | 113 | | option | description | default | prompted | 114 | | ------------------- | ---------------------------------------------------- | ------- | ----------------------------------- | 115 | | publicPublishConfig | Should we add public publish config for your library | true | yes | 116 | | libName | The name of the library that should be configured | | only if nothing is passed initially | 117 | 118 | ## configure-libraries 119 | 120 | ```npx nx g nx-release:configure-libraries``` 121 | 122 | The `configure-libraries`generator sets up a multiple libraries for semantic release. When setting up the libraries it will use some of the executors provided by `nx-release`. 123 | 124 | | option | description | default | prompted | 125 | | ------------------- | ---------------------------------------------------- | ------- | --------------------------------- | 126 | | publicPublishConfig | Should we add public publish config for your library | true | yes | 127 | | libName | The name of the library that should be configured | | will be prompted during execution | 128 | 129 | ## generate-gh-actions 130 | 131 | ```npx nx g nx-release:generate-gh-actions``` 132 | 133 | This generator can be used to generate two workflow files for automated releasing. This generator will generate the following two files: 134 | 135 | - ci.yml (this file configures a pipeline that is run on Pull request) 136 | - release.yml (file that releases the library / by default it has to be triggered manually) 137 | 138 | ## generate-release-config 139 | 140 | ```npx nx g nx-release:generate-release-config``` 141 | 142 | This generator generates a `release.config.js` file at the root of your project. 143 | 144 | # Executors 145 | 146 | ## npm-publish 147 | 148 | As the name indicates the `npm-publish` generator can be used to publish a library to NPM. To 149 | do so **the executor requires a `NPM_TOKEN` to be present as a Node environment variable**. 150 | 151 | 152 | ## update-version 153 | This executor updates the `package.json` version in the specified library. The executor **requires** the following config options.**The update-version executor expects a VERSION env variable to be present**. 154 | 155 | ## build-update-publish 156 | This executor combines the previous two executors and additionally performs a release. 157 | 158 | **This command expects a valid NPM token to be present as a `NPM_TOKEN` environment variable and the new release version to be present as a `VERSION` variable**. 159 | 160 | ## Contributors ✨ 161 | 162 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 180 | 181 | 182 |
Nivek
Nivek

💻
176 | 177 | Add your contributions 178 | 179 |
183 | 184 | 185 | 186 | 187 | 188 | 189 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! 190 | -------------------------------------------------------------------------------- /libs/nx-release/assets/nx-release-logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /libs/nx-release/executors.json: -------------------------------------------------------------------------------- 1 | { 2 | "executors": { 3 | "npm-publish": { 4 | "implementation": "./src/executors/npm-publish/executor", 5 | "schema": "./src/executors/npm-publish/schema.json", 6 | "description": "npm-publish executor" 7 | }, 8 | "update-version": { 9 | "implementation": "./src/executors/update-version/executor", 10 | "schema": "./src/executors/update-version/schema.json", 11 | "description": "update-version executor" 12 | }, 13 | "build-update-publish": { 14 | "implementation": "./src/executors/build-update-publish/executor", 15 | "schema": "./src/executors/build-update-publish/schema.json", 16 | "description": "build-update-publish executor" 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /libs/nx-release/generators.json: -------------------------------------------------------------------------------- 1 | { 2 | "generators": { 3 | "configure-workspace": { 4 | "factory": "./src/generators/configure-workspace/generator", 5 | "schema": "./src/generators/configure-workspace/schema.json", 6 | "description": "configure-workspace generator" 7 | }, 8 | "configure-library": { 9 | "factory": "./src/generators/configure-library/generator", 10 | "schema": "./src/generators/configure-library/schema.json", 11 | "description": "configure-library generator" 12 | }, 13 | "configure-libraries": { 14 | "factory": "./src/generators/configure-libraries/generator", 15 | "schema": "./src/generators/configure-libraries/schema.json", 16 | "description": "configure-libraries generator" 17 | }, 18 | "configure": { 19 | "factory": "./src/generators/configure/generator", 20 | "schema": "./src/generators/configure/schema.json", 21 | "description": "configure generator" 22 | }, 23 | "generate-release-config": { 24 | "factory": "./src/generators/generate-release-config/generator", 25 | "schema": "./src/generators/generate-release-config/schema.json", 26 | "description": "generate-release-config generator" 27 | }, 28 | "generate-gh-actions": { 29 | "factory": "./src/generators/generate-gh-actions/generator", 30 | "schema": "./src/generators/generate-gh-actions/schema.json", 31 | "description": "generate-gh-actions generator" 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /libs/nx-release/jest.config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | export default { 3 | displayName: 'nx-release', 4 | preset: '../../jest.preset.js', 5 | transform: { 6 | '^.+\\.[tj]s$': ['ts-jest', { tsconfig: '/tsconfig.spec.json' }], 7 | }, 8 | moduleFileExtensions: ['ts', 'js', 'html'], 9 | coverageDirectory: '../../coverage/libs/nx-release', 10 | }; 11 | -------------------------------------------------------------------------------- /libs/nx-release/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nx-release", 3 | "version": "0.0.1", 4 | "type": "commonjs", 5 | "executors": "./executors.json", 6 | "generators": "./generators.json", 7 | "peerDependencies": { 8 | "tslib": "^2.6.0" 9 | }, 10 | "license": "MIT", 11 | "repository": "https://github.com/kreuzerk/nx-release", 12 | "readme": "https://github.com/kreuzerk/nx-release/blob/main/README.md", 13 | "bugs": "https://github.com/kreuzerk/nx-release/issues", 14 | "author": "kreuzerk" 15 | } 16 | -------------------------------------------------------------------------------- /libs/nx-release/project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "nx-release", 3 | "$schema": "../../node_modules/nx/schemas/project-schema.json", 4 | "sourceRoot": "libs/nx-release/src", 5 | "projectType": "library", 6 | "targets": { 7 | "build": { 8 | "executor": "@nx/js:tsc", 9 | "outputs": ["{options.outputPath}"], 10 | "options": { 11 | "outputPath": "dist/libs/nx-release", 12 | "main": "libs/nx-release/src/index.ts", 13 | "tsConfig": "libs/nx-release/tsconfig.lib.json", 14 | "assets": [ 15 | "libs/nx-release/*.md", 16 | { 17 | "input": "./libs/nx-release/src", 18 | "glob": "**/!(*.ts)", 19 | "output": "./src" 20 | }, 21 | { 22 | "input": "./libs/nx-release/src", 23 | "glob": "**/*.d.ts", 24 | "output": "./src" 25 | }, 26 | { 27 | "input": "./libs/nx-release", 28 | "glob": "generators.json", 29 | "output": "." 30 | }, 31 | { 32 | "input": "./libs/nx-release", 33 | "glob": "executors.json", 34 | "output": "." 35 | } 36 | ] 37 | } 38 | }, 39 | "lint": { 40 | "executor": "@nx/linter:eslint", 41 | "outputs": ["{options.outputFile}"], 42 | "options": { 43 | "lintFilePatterns": [ 44 | "libs/nx-release/**/*.ts", 45 | "libs/nx-release/package.json", 46 | "libs/nx-release/executors.json", 47 | "libs/nx-release/generators.json" 48 | ] 49 | } 50 | }, 51 | "test": { 52 | "executor": "@nx/jest:jest", 53 | "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], 54 | "options": { 55 | "jestConfig": "libs/nx-release/jest.config.ts", 56 | "passWithNoTests": true 57 | }, 58 | "configurations": { 59 | "ci": { 60 | "ci": true, 61 | "codeCoverage": true 62 | } 63 | } 64 | }, 65 | "publish": { 66 | "executor": "nx:run-commands", 67 | "options": { 68 | "command": "cd ./dist/libs/nx-release && echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc && npm publish" 69 | } 70 | } 71 | }, 72 | "tags": [] 73 | } 74 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/build-update-publish/executor.spec.ts: -------------------------------------------------------------------------------- 1 | import * as childProcess from 'child_process'; 2 | 3 | import * as updateVersion from '../update-version/executor'; 4 | import * as projectHelper from '../helpers/projects.helpers'; 5 | import * as npmPublish from '../npm-publish/executor'; 6 | 7 | import executor from './executor'; 8 | 9 | describe('BuildUpdatePublish Executor', () => { 10 | it('should call update-version executor and npm publish executor with the options and context', async () => { 11 | const libName = 'foo'; 12 | const mockContext = {bar: 'bar'} as any; 13 | 14 | /* eslint-disable */ 15 | jest.spyOn(projectHelper, 'getProjectName').mockReturnValue(libName); 16 | /* eslint-disable */ 17 | jest.spyOn(updateVersion, 'default').mockImplementation((() => {}) as any) 18 | /* eslint-disable */ 19 | jest.spyOn(npmPublish, 'default').mockImplementation((() => {}) as any) 20 | /* eslint-disable */ 21 | jest.spyOn(childProcess, 'execSync').mockImplementation((() => {}) as any) 22 | 23 | 24 | const output = await executor({}, mockContext as any); 25 | 26 | expect(updateVersion.default).toHaveBeenCalledWith({}, mockContext); 27 | expect(npmPublish.default).toHaveBeenCalledWith({}, mockContext); 28 | expect(childProcess.execSync).toHaveBeenCalledWith(`nx build --project ${libName}`); 29 | expect(output.success).toBe(true); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/build-update-publish/executor.ts: -------------------------------------------------------------------------------- 1 | import {ExecutorContext} from "@nx/devkit"; 2 | import {execSync} from "child_process"; 3 | 4 | import {getProjectName} from '../helpers/projects.helpers'; 5 | import updateVersion from '../update-version/executor'; 6 | import npmPublish from '../npm-publish/executor'; 7 | 8 | import {BuildUpdatePublishExecutorSchema} from './schema'; 9 | 10 | export default async function runExecutor( 11 | options: BuildUpdatePublishExecutorSchema, 12 | context: ExecutorContext 13 | ) { 14 | 15 | await updateVersion({}, context); 16 | execSync(`nx build --project ${getProjectName(context)}`); 17 | await npmPublish({}, context); 18 | 19 | return { 20 | success: true, 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/build-update-publish/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface BuildUpdatePublishExecutorSchema {} 2 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/build-update-publish/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "version": 2, 4 | "title": "BuildUpdatePublish executor", 5 | "description": "", 6 | "type": "object", 7 | "properties": {} 8 | } 9 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/helpers/projects.helpers.spec.ts: -------------------------------------------------------------------------------- 1 | import * as nxDevKit from '@nx/devkit'; 2 | 3 | import { getProjectName, getRoot } from './projects.helpers'; 4 | 5 | describe('executor project helper', () => { 6 | it('should return the project name', () => { 7 | const projectName = 'foo'; 8 | expect(getProjectName({projectName} as any)).toBe(projectName); 9 | }); 10 | 11 | it('should get the root of the project', () => { 12 | const expectedRoot = 'libs/foo'; 13 | const context = { 14 | projectName: 'foo', 15 | projectsConfigurations: { 16 | projects: { 17 | foo: { 18 | root: expectedRoot 19 | } 20 | } 21 | } 22 | } as any; 23 | 24 | expect(getRoot(context)).toBe(expectedRoot); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/helpers/projects.helpers.ts: -------------------------------------------------------------------------------- 1 | import {ExecutorContext} from "@nx/devkit"; 2 | 3 | export function getProjectName(context: ExecutorContext): string { 4 | return context.projectName; 5 | } 6 | 7 | export function getRoot(context: ExecutorContext): string { 8 | const projectsConfiguration = context.projectsConfigurations.projects; 9 | const projectName = getProjectName(context); 10 | return projectsConfiguration[projectName].root; 11 | } 12 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/npm-publish/executor.spec.ts: -------------------------------------------------------------------------------- 1 | import * as child_process from "child_process"; 2 | 3 | import * as projectHelpers from "../helpers/projects.helpers"; 4 | 5 | import executor from './executor'; 6 | 7 | describe('NpmPublish Executor', () => { 8 | const OLD_ENV = process.env; 9 | 10 | beforeEach(() => { 11 | jest.resetModules(); 12 | }); 13 | 14 | afterEach(() => { 15 | process.env = { ...OLD_ENV }; 16 | }); 17 | 18 | it('should execSync with a default libPath if no libPath was provided', async () => { 19 | const mockRoot = 'libs/my-domain/foo'; 20 | const context = { 21 | } as any; 22 | 23 | /* eslint-disable */ 24 | jest.spyOn(child_process, 'execSync').mockImplementation((() => {}) as any); 25 | /* eslint-disable */ 26 | jest.spyOn(projectHelpers, 'getRoot').mockReturnValue(mockRoot); 27 | 28 | const expectedCommand = `cd ./dist/${mockRoot} && echo '//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}' >> .npmrc && npm publish --tag=latest` 29 | const output = await executor({}, context); 30 | 31 | expect(child_process.execSync).toHaveBeenCalledWith(expectedCommand); 32 | expect(output.success).toBe(true); 33 | }); 34 | 35 | it('should execSync with a specific npm registry if provided with one', async () => { 36 | const mockRoot = 'libs/my-domain/foo'; 37 | const context = { 38 | } as any; 39 | const registry = 'specific-npm-registry.org'; 40 | process.env = Object.assign(process.env, { NPM_REGISTRY: registry }); 41 | 42 | /* eslint-disable */ 43 | jest.spyOn(child_process, 'execSync').mockImplementation((() => {}) as any); 44 | /* eslint-disable */ 45 | jest.spyOn(projectHelpers, 'getRoot').mockReturnValue(mockRoot); 46 | 47 | const expectedCommand = `cd ./dist/${mockRoot} && echo '//${registry}/:_authToken=${process.env.NPM_TOKEN}' >> .npmrc && npm publish --tag=latest` 48 | const output = await executor({}, context); 49 | 50 | expect(child_process.execSync).toHaveBeenCalledWith(expectedCommand); 51 | expect(output.success).toBe(true); 52 | }); 53 | 54 | it('should execSync with a specific npm channel if provided with one', async () => { 55 | const mockRoot = 'libs/my-domain/foo'; 56 | const context = { 57 | } as any; 58 | const channel = 'beta'; 59 | process.env = Object.assign(process.env, { CHANNEL: channel }); 60 | 61 | /* eslint-disable */ 62 | jest.spyOn(child_process, 'execSync').mockImplementation((() => {}) as any); 63 | /* eslint-disable */ 64 | jest.spyOn(projectHelpers, 'getRoot').mockReturnValue(mockRoot); 65 | 66 | const expectedCommand = `cd ./dist/${mockRoot} && echo '//registry.npmjs.org/:_authToken=${process.env.NPM_TOKEN}' >> .npmrc && npm publish --tag=${channel}` 67 | const output = await executor({}, context); 68 | 69 | expect(child_process.execSync).toHaveBeenCalledWith(expectedCommand); 70 | expect(output.success).toBe(true); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/npm-publish/executor.ts: -------------------------------------------------------------------------------- 1 | import {execSync} from 'child_process'; 2 | import {ExecutorContext} from "@nx/devkit"; 3 | 4 | import {getRoot} from "../helpers/projects.helpers"; 5 | 6 | import {NpmPublishExecutorSchema} from './schema'; 7 | 8 | export default async function runExecutor(options: NpmPublishExecutorSchema, 9 | context: ExecutorContext 10 | ) { 11 | const sourceRoot = `./dist/${getRoot(context)}`; 12 | const registry: string = process.env.NPM_REGISTRY || 'registry.npmjs.org' 13 | const channel: string = process.env.CHANNEL || 'latest' 14 | execSync( 15 | `cd ${sourceRoot} && echo '//${registry}/:_authToken=${process.env.NPM_TOKEN}' >> .npmrc && npm publish --tag=${channel}` 16 | ); 17 | return { 18 | success: true, 19 | }; 20 | } -------------------------------------------------------------------------------- /libs/nx-release/src/executors/npm-publish/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface NpmPublishExecutorSchema {} 2 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/npm-publish/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "version": 2, 4 | "title": "NPM publish executor", 5 | "description": "", 6 | "type": "object", 7 | "properties": {} 8 | } 9 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/update-version/executor.spec.ts: -------------------------------------------------------------------------------- 1 | import * as replaceJsonProp from 'replace-json-property'; 2 | import * as process from "process"; 3 | 4 | import * as projectHelpers from '../helpers/projects.helpers'; 5 | 6 | import executor from './executor'; 7 | 8 | describe('ReplaceVersion Executor', () => { 9 | 10 | it('should replace the version with in the default path if no path was provided', async () => { 11 | const version = '2.0.0'; 12 | const libName = 'foo'; 13 | const mockContext = {} as any; 14 | 15 | process.env.VERSION = version; 16 | 17 | const root = `libs/${libName}`; 18 | 19 | // eslint-disable-next-line @typescript-eslint/no-empty-function 20 | jest.spyOn(replaceJsonProp, 'replace').mockImplementation(() => {}); 21 | jest.spyOn(projectHelpers, 'getRoot').mockReturnValue(root); 22 | 23 | const output = await executor({}, mockContext); 24 | 25 | expect(replaceJsonProp.replace).toHaveBeenCalledWith(`${root}/package.json`, 'version', version); 26 | expect(output.success).toBe(true); 27 | }); 28 | 29 | }); 30 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/update-version/executor.ts: -------------------------------------------------------------------------------- 1 | import type {ExecutorContext} from '@nx/devkit'; 2 | import {replace} from 'replace-json-property'; 3 | import * as process from "process"; 4 | 5 | import {getRoot} from "../helpers/projects.helpers"; 6 | 7 | import {ReplaceVersionExecutorSchema} from './schema'; 8 | 9 | export default async function runExecutor( 10 | options: ReplaceVersionExecutorSchema, 11 | context: ExecutorContext 12 | ) { 13 | const sourceRoot = getRoot(context); 14 | replace(`${sourceRoot}/package.json`, 'version', process.env.VERSION); 15 | return { 16 | success: true, 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/update-version/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface ReplaceVersionExecutorSchema {} 2 | -------------------------------------------------------------------------------- /libs/nx-release/src/executors/update-version/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "version": 2, 4 | "title": "Update version executor", 5 | "description": "", 6 | "type": "object", 7 | "properties": {} 8 | } 9 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-libraries/generator.spec.ts: -------------------------------------------------------------------------------- 1 | import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing'; 2 | import * as inquirer from 'inquirer' 3 | import { Tree } from '@nx/devkit'; 4 | 5 | import * as libraryGenerator from '../configure-library/generator'; 6 | import * as projectHelpers from '../helpers/projects.helpers'; 7 | import * as spinnerHelper from '../helpers/spinner.helper'; 8 | 9 | import { configureLibrariesGenerator } from './generator'; 10 | import * as process from "process"; 11 | 12 | describe('configure-libraries generator', () => { 13 | let tree: Tree; 14 | 15 | beforeEach(() => { 16 | tree = createTreeWithEmptyWorkspace(); 17 | jest.spyOn(spinnerHelper, 'getSpinner').mockReturnValue(({ 18 | start: jest.fn(), 19 | succeed: jest.fn(), 20 | fail: jest.fn(), 21 | }) as any 22 | ); 23 | }); 24 | 25 | it('should log an error message if no library projects are found', done => { 26 | jest.spyOn(console, 'error').mockImplementation(() => {}); 27 | jest.spyOn(projectHelpers, 'getLibraryProjectNames').mockReturnValue([]); 28 | jest.spyOn(inquirer, 'prompt').mockImplementation(() => Promise.resolve({ 29 | selectedProjects: [] 30 | })); 31 | jest.spyOn(process, 'exit').mockImplementation((() => { 32 | done(); 33 | }) as any); 34 | 35 | configureLibrariesGenerator(tree, {} as any); 36 | }); 37 | 38 | it('should call the configureLibraryGenerator for each selected project', async () => { 39 | const selectedProjects = ['foo', 'bar']; 40 | 41 | jest.spyOn(libraryGenerator, 'configureLibraryGenerator').mockImplementation(() => Promise.resolve()); 42 | jest.spyOn(inquirer, 'prompt').mockImplementation(() => Promise.resolve({ 43 | selectedProjects 44 | })); 45 | 46 | await configureLibrariesGenerator(tree, { 47 | publicPublishConfig: true 48 | }); 49 | 50 | expect(libraryGenerator.configureLibraryGenerator).toHaveBeenCalledTimes(2); 51 | expect(libraryGenerator.configureLibraryGenerator).toHaveBeenCalledWith(tree, { 52 | libName: selectedProjects[0], 53 | publicPublishConfig: true 54 | }); 55 | expect(libraryGenerator.configureLibraryGenerator).toHaveBeenCalledWith(tree, { 56 | libName: selectedProjects[1], 57 | publicPublishConfig: true 58 | }); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-libraries/generator.ts: -------------------------------------------------------------------------------- 1 | import {formatFiles, Tree,} from '@nx/devkit'; 2 | import * as inquirer from 'inquirer'; 3 | 4 | import {getLibraryProjectNames} from "../helpers/projects.helpers"; 5 | import {configureLibraryGenerator} from "../configure-library/generator"; 6 | 7 | import {ConfigureLibrariesGeneratorSchema} from './schema'; 8 | import * as chalk from "chalk"; 9 | 10 | export async function configureLibrariesGenerator( 11 | tree: Tree, 12 | options: ConfigureLibrariesGeneratorSchema 13 | ) { 14 | const {publicPublishConfig} = options; 15 | const libraryProjects = getLibraryProjectNames(tree); 16 | 17 | if (libraryProjects.length === 0) { 18 | console.error(chalk.red(`🐋 nx-release: no library projects found in your workspace -> aborting`)); 19 | process.exit(0); 20 | } 21 | 22 | const projectsPrompt = await inquirer.prompt({ 23 | type: 'checkbox', 24 | name: 'selectedProjects', 25 | choices: libraryProjects 26 | }); 27 | const selectedProjects = projectsPrompt.selectedProjects; 28 | 29 | for (const libName of selectedProjects) { 30 | await configureLibraryGenerator(tree, {libName, publicPublishConfig}); 31 | } 32 | 33 | await formatFiles(tree); 34 | } 35 | 36 | export default configureLibrariesGenerator; 37 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-libraries/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface ConfigureLibrariesGeneratorSchema { 2 | publicPublishConfig: boolean; 3 | } 4 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-libraries/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "ConfigureLibraries", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "publicPublishConfig": { 8 | "type": "boolean", 9 | "description": "Should we update the config for public publishing of a library", 10 | "x-prompt": { 11 | "type": "boolean", 12 | "message": "\uD83D\uDC0B nx-release: is your library publicly publishable" 13 | }, 14 | "default": true 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-library/generator.spec.ts: -------------------------------------------------------------------------------- 1 | import {createTreeWithEmptyWorkspace} from '@nx/devkit/testing'; 2 | import {readJson, Tree} from '@nx/devkit'; 3 | import * as inquirer from 'inquirer'; 4 | 5 | import * as projectHelpers from '../helpers/projects.helpers'; 6 | import * as spinnerHelper from "../helpers/spinner.helper"; 7 | 8 | import {configureLibraryGenerator} from './generator'; 9 | import {libraryGenerator} from "@nx/js"; 10 | 11 | describe('configure-library generator', () => { 12 | let tree: Tree; 13 | 14 | beforeEach(() => { 15 | tree = createTreeWithEmptyWorkspace(); 16 | jest.spyOn(spinnerHelper, 'getSpinner').mockReturnValue(({ 17 | start: jest.fn(), 18 | succeed: jest.fn(), 19 | fail: jest.fn() 20 | }) as any 21 | ); 22 | }); 23 | 24 | it('should prompt for project if no library name was provided', async () => { 25 | const mockProjectNames = ['foo', 'bar']; 26 | 27 | jest.spyOn(inquirer, 'prompt').mockImplementation(() => Promise.resolve({name: 'test'})); 28 | jest.spyOn(projectHelpers, 'getLibraryProjectNames').mockReturnValue(mockProjectNames); 29 | 30 | await configureLibraryGenerator(tree, {}); 31 | 32 | expect(inquirer.prompt).toHaveBeenCalledWith({ 33 | type: 'list', 34 | name: 'selectedProject', 35 | choices: mockProjectNames 36 | }); 37 | }); 38 | 39 | it('should add the executor to the project.json', async () => { 40 | const libName = 'foo'; 41 | const expectedExecutorConfig = { 42 | executor: 'nx-release:build-update-publish', 43 | options: { 44 | libName 45 | } 46 | }; 47 | 48 | jest.spyOn(inquirer, 'prompt').mockImplementation(() => Promise.resolve({selectedProject: libName})); 49 | jest.spyOn(projectHelpers, 'getLibraryProjectNames').mockReturnValue([libName]); 50 | jest.spyOn(projectHelpers, 'getLibraryRoot').mockReturnValue(`${libName}`); 51 | 52 | await libraryGenerator(tree, {name: libName}); 53 | await configureLibraryGenerator(tree, {libName}); 54 | 55 | const projectJson = readJson(tree, `${libName}/project.json`) 56 | expect(projectJson.targets['release']).toEqual(expectedExecutorConfig); 57 | }); 58 | 59 | it('should not add a public publish config if the "publicPublishConfig" was not set', async () => { 60 | const libName = 'foo'; 61 | 62 | jest.spyOn(inquirer, 'prompt').mockImplementation(() => Promise.resolve({selectedProject: libName})); 63 | jest.spyOn(projectHelpers, 'getLibraryProjectNames').mockReturnValue([libName]); 64 | jest.spyOn(projectHelpers, 'getLibraryRoot').mockReturnValue(`${libName}`); 65 | 66 | await libraryGenerator(tree, {name: libName}); 67 | await configureLibraryGenerator(tree, {libName}); 68 | 69 | const packageJson = readJson(tree, `${libName}/package.json`) 70 | expect(packageJson.publishConfig).not.toBeDefined(); 71 | }); 72 | 73 | it('should add a public publish config if the "publicPublishConfig" was set to true', async () => { 74 | const libName = 'foo'; 75 | const expectedPublishConfig = {access: 'public'} 76 | 77 | jest.spyOn(inquirer, 'prompt').mockImplementation(() => Promise.resolve({selectedProject: libName})); 78 | jest.spyOn(projectHelpers, 'getLibraryProjectNames').mockReturnValue([libName]); 79 | jest.spyOn(projectHelpers, 'getLibraryRoot').mockReturnValue(`${libName}`); 80 | 81 | await libraryGenerator(tree, {name: libName}); 82 | await configureLibraryGenerator(tree, {libName, publicPublishConfig: true}); 83 | 84 | const packageJson = readJson(tree, `${libName}/package.json`) 85 | expect(packageJson.publishConfig).toEqual(expectedPublishConfig); 86 | }); 87 | 88 | it('should log an error message if no library projects are found', done => { 89 | jest.spyOn(console, 'error').mockImplementation(() => {}); 90 | jest.spyOn(projectHelpers, 'getLibraryProjectNames').mockReturnValue([]); 91 | jest.spyOn(inquirer, 'prompt').mockImplementation(() => Promise.resolve({ 92 | selectedProjects: [] 93 | })); 94 | jest.spyOn(process, 'exit').mockImplementation((() => { 95 | done(); 96 | }) as any); 97 | 98 | configureLibraryGenerator(tree, {} as any); 99 | }); 100 | }); 101 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-library/generator.ts: -------------------------------------------------------------------------------- 1 | import {formatFiles, Tree, updateJson} from '@nx/devkit'; 2 | import * as inquirer from 'inquirer'; 3 | import * as process from "process"; 4 | import * as chalk from "chalk"; 5 | 6 | import {getLibraryProjectNames, getLibraryRoot} from "../helpers/projects.helpers"; 7 | import {getSpinner} from "../helpers/spinner.helper"; 8 | 9 | import {ConfigureLibraryGeneratorSchema} from './schema'; 10 | 11 | export async function configureLibraryGenerator( 12 | tree: Tree, 13 | options: ConfigureLibraryGeneratorSchema 14 | ) { 15 | let {libName} = options; 16 | const { publicPublishConfig } = options; 17 | const spinner = getSpinner(); 18 | 19 | try { 20 | if (!libName) { 21 | const libraryProjects = getLibraryProjectNames(tree); 22 | 23 | if (libraryProjects.length === 0) { 24 | console.error(chalk.red(`🐋 nx-release: no library projects found in your workspace -> aborting`)); 25 | process.exit(0); 26 | } 27 | 28 | const projectPrompt = await inquirer.prompt({ 29 | type: 'list', 30 | name: 'selectedProject', 31 | choices: libraryProjects 32 | }); 33 | libName = projectPrompt.selectedProject; 34 | } 35 | 36 | spinner.text = `🐋 nx-release: configuring executor for library ${libName}`; 37 | spinner.start(); 38 | 39 | const libraryRoot = getLibraryRoot(tree, libName); 40 | 41 | updateJson(tree, `${libraryRoot}/project.json`, (packageJson: any) => { 42 | packageJson.targets.release = { 43 | executor: 'nx-release:build-update-publish', 44 | options: { 45 | libName 46 | } 47 | }; 48 | return packageJson; 49 | }); 50 | 51 | spinner.succeed(); 52 | 53 | if (publicPublishConfig) { 54 | spinner.text = `🐋 nx-release: add public publish config for library ${libName}`; 55 | spinner.start(); 56 | 57 | updateJson(tree, `${libraryRoot}/package.json`, (packageJson: any) => { 58 | packageJson.publishConfig = { 59 | access: 'public' 60 | }; 61 | return packageJson; 62 | }); 63 | spinner.succeed(); 64 | } 65 | await formatFiles(tree); 66 | } catch (e) { 67 | spinner.fail(`🐋 nx-release: something went wrong: ${e.toString()}`) 68 | } 69 | } 70 | 71 | export default configureLibraryGenerator; 72 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-library/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface ConfigureLibraryGeneratorSchema { 2 | libName?: string; 3 | publicPublishConfig?: boolean; 4 | } 5 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-library/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "ConfigureLibrary", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "publicPublishConfig": { 8 | "type": "boolean", 9 | "description": "Should we update the config for public publishing of a library", 10 | "x-prompt": { 11 | "type": "boolean", 12 | "message": "\uD83D\uDC0B nx-release: is your library publicly publishable" 13 | }, 14 | "default": true 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-workspace/generator.spec.ts: -------------------------------------------------------------------------------- 1 | import {createTreeWithEmptyWorkspace} from '@nx/devkit/testing'; 2 | import * as childProcess from 'child_process'; 3 | import * as nXdevKit from '@nx/devkit'; 4 | import {Tree} from '@nx/devkit'; 5 | 6 | import * as spinnerHelper from '../helpers/spinner.helper'; 7 | 8 | import {configureWorkspaceGenerator} from './generator'; 9 | 10 | describe('configure-workspace generator', () => { 11 | let tree: Tree; 12 | 13 | beforeEach(() => { 14 | tree = createTreeWithEmptyWorkspace(); 15 | jest.spyOn(spinnerHelper, 'getSpinner').mockReturnValue(({ 16 | start: jest.fn(), 17 | succeed: jest.fn(), 18 | }) as any 19 | ); 20 | }); 21 | 22 | it('should install the dependencies if the "installDeps" flag is set', async () => { 23 | const options = { 24 | installDeps: true 25 | }; 26 | 27 | jest.spyOn(childProcess, 'execSync').mockImplementation((() => { 28 | }) as any); 29 | 30 | await configureWorkspaceGenerator(tree, options); 31 | expect(childProcess.execSync).toHaveBeenCalledWith(`npm i -D @semantic-release/changelog @semantic-release/commit-analyzer @semantic-release/exec @semantic-release/git @semantic-release/release-notes-generator nx-release replace-json-property conventional-changelog-conventionalcommits --force`); 32 | }); 33 | 34 | it('should generate the release config if the "generateReleaseConfig" flag is set', async () => { 35 | const options = { 36 | generateReleaseConfig: true 37 | }; 38 | 39 | jest.spyOn(childProcess, 'execSync').mockImplementation((() => { 40 | }) as any); 41 | jest.spyOn(nXdevKit, 'generateFiles').mockImplementation((() => { 42 | }) as any); 43 | 44 | await configureWorkspaceGenerator(tree, options); 45 | expect(nXdevKit.generateFiles).toHaveBeenCalled(); 46 | }); 47 | }); 48 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-workspace/generator.ts: -------------------------------------------------------------------------------- 1 | import {execSync} from "child_process"; 2 | import {formatFiles, Tree,} from '@nx/devkit'; 3 | 4 | import {getSpinner} from "../helpers/spinner.helper"; 5 | import generateReleaseConfigGenerator from "../generate-release-config/generator"; 6 | import generateGhActionsGenerator from "../generate-gh-actions/generator"; 7 | 8 | import {ConfigureWorkspaceGeneratorSchema} from './schema'; 9 | 10 | export async function configureWorkspaceGenerator( 11 | tree: Tree, 12 | options: ConfigureWorkspaceGeneratorSchema 13 | ) { 14 | const {installDeps, generateReleaseConfig, generateGhActions} = options; 15 | const spinner = getSpinner(); 16 | try { 17 | if (generateReleaseConfig) { 18 | await generateReleaseConfigGenerator(tree, {}); 19 | } 20 | 21 | if (generateGhActions) { 22 | await generateGhActionsGenerator(tree, {}); 23 | } 24 | 25 | if (installDeps) { 26 | spinner.text = '🐋 nx-release: Installing dependencies'; 27 | spinner.start(); 28 | execSync(`npm i -D @semantic-release/changelog @semantic-release/commit-analyzer @semantic-release/exec @semantic-release/git @semantic-release/release-notes-generator nx-release replace-json-property conventional-changelog-conventionalcommits --force`); 29 | spinner.succeed(); 30 | } 31 | 32 | await formatFiles(tree); 33 | } catch (e) { 34 | spinner.fail(`🐋 nx-release: something went wrong: ${e.toString()}`) 35 | } 36 | } 37 | 38 | function getArtifacts(generateReleaseConfig: boolean, generateWorkflows: boolean) { 39 | let artifacts = ''; 40 | if (generateReleaseConfig) { 41 | artifacts += 'release config'; 42 | } 43 | if(generateWorkflows){ 44 | artifacts += artifacts.length > 0 ? '& GitHub actions': 'GitHub actions' 45 | } 46 | return artifacts; 47 | } 48 | 49 | export default configureWorkspaceGenerator; 50 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-workspace/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface ConfigureWorkspaceGeneratorSchema { 2 | installDeps?: boolean; 3 | generateReleaseConfig?: boolean; 4 | generateGhActions?: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure-workspace/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "ConfigureWorkspace", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "installDeps": { 8 | "type": "boolean", 9 | "description": "Install semantic-release and dependencies", 10 | "x-prompt": { 11 | "type": "boolean", 12 | "message": "\uD83D\uDC0B nx-release: would you like to install semantic-release and the required plugins?" 13 | }, 14 | "default": true 15 | }, 16 | "generateReleaseConfig": { 17 | "type": "boolean", 18 | "description": "Generate release.config.js file", 19 | "x-prompt": { 20 | "type": "boolean", 21 | "message": "\uD83D\uDC0B nx-release: would you like to generate a release config" 22 | }, 23 | "default": true 24 | }, 25 | "generateGhActions": { 26 | "type": "boolean", 27 | "description": "Generate GitHub workflow files (ci.yml & release.yml)", 28 | "x-prompt": { 29 | "type": "boolean", 30 | "message": "\uD83D\uDC0B nx-release: would you like to generate GitHub workflows?" 31 | }, 32 | "default": true 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure/generator.spec.ts: -------------------------------------------------------------------------------- 1 | import {createTreeWithEmptyWorkspace} from '@nx/devkit/testing'; 2 | import {Tree} from '@nx/devkit'; 3 | 4 | import * as workspaceGenerator from "../configure-workspace/generator"; 5 | import * as libraryGenerator from "../configure-libraries/generator"; 6 | 7 | import {configureGenerator} from './generator'; 8 | 9 | describe('configure generator', () => { 10 | let tree: Tree; 11 | 12 | beforeEach(() => { 13 | tree = createTreeWithEmptyWorkspace(); 14 | }); 15 | 16 | it('should call the workspace and the library generator', async () => { 17 | 18 | const options = { 19 | installDeps: true, 20 | generateGhActions: true, 21 | generateReleaseConfig: true, 22 | publicPublishConfig: true 23 | } 24 | 25 | jest.spyOn(workspaceGenerator, 'configureWorkspaceGenerator').mockImplementation(() => Promise.resolve()); 26 | jest.spyOn(libraryGenerator, 'configureLibrariesGenerator').mockImplementation(() => Promise.resolve()); 27 | 28 | await configureGenerator(tree, options); 29 | 30 | expect(workspaceGenerator.configureWorkspaceGenerator).toHaveBeenCalledWith(tree, { 31 | installDeps: options.installDeps, 32 | generateGhActions: options.generateGhActions, 33 | generateReleaseConfig: options.generateReleaseConfig 34 | }); 35 | 36 | expect(libraryGenerator.configureLibrariesGenerator).toHaveBeenCalledWith(tree, { 37 | publicPublishConfig: options.publicPublishConfig 38 | }); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure/generator.ts: -------------------------------------------------------------------------------- 1 | import {formatFiles, Tree,} from '@nx/devkit'; 2 | 3 | import {configureWorkspaceGenerator} from "../configure-workspace/generator"; 4 | import {configureLibrariesGenerator} from "../configure-libraries/generator"; 5 | 6 | import {ConfigureGeneratorSchema} from './schema'; 7 | 8 | export async function configureGenerator( 9 | tree: Tree, 10 | options: ConfigureGeneratorSchema 11 | ) { 12 | const {publicPublishConfig, installDeps, generateGhActions, generateReleaseConfig} = options; 13 | await configureWorkspaceGenerator(tree, {installDeps, generateGhActions, generateReleaseConfig}); 14 | await configureLibrariesGenerator(tree, {publicPublishConfig}); 15 | 16 | await formatFiles(tree); 17 | } 18 | 19 | export default configureGenerator; 20 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface ConfigureGeneratorSchema { 2 | installDeps: boolean; 3 | generateReleaseConfig: boolean; 4 | generateGhActions 5 | publicPublishConfig: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/configure/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "Configure", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | "installDeps": { 8 | "type": "boolean", 9 | "description": "Install semantic-release and dependencies", 10 | "x-prompt": { 11 | "type": "boolean", 12 | "message": "\uD83D\uDC0B nx-release: would you like to install semantic-release and the required plugins?" 13 | }, 14 | "default": true 15 | }, 16 | "generateReleaseConfig": { 17 | "type": "boolean", 18 | "description": "Generate release.config.js file", 19 | "x-prompt": { 20 | "type": "boolean", 21 | "message": "\uD83D\uDC0B nx-release: would you like to generate a release config" 22 | }, 23 | "default": true 24 | }, 25 | "generateGhActions": { 26 | "type": "boolean", 27 | "description": "Generate GitHub workflow files (ci.yml & release.yml)", 28 | "x-prompt": { 29 | "type": "boolean", 30 | "message": "\uD83D\uDC0B nx-release: would you like to generate GitHub workflows?" 31 | }, 32 | "default": true 33 | }, 34 | "publicPublishConfig": { 35 | "type": "boolean", 36 | "description": "Should we update the config for public publishing of a library", 37 | "x-prompt": { 38 | "type": "boolean", 39 | "message": "\uD83D\uDC0B nx-release: is your library publicly publishable" 40 | }, 41 | "default": true 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-gh-actions/files/.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | on: 3 | push: 4 | branches: 5 | - '*' 6 | - '*/*' 7 | - '**' 8 | - '!main' 9 | jobs: 10 | main: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | - uses: nrwl/nx-set-shas@v3 17 | - name: Install deps 18 | run: npm ci 19 | - name: Lint affected 20 | run: npx nx affected -t lint 21 | - name: Test affected 22 | run: npx nx affected -t test --configuration=ci 23 | - name: Build affected 24 | run: npx nx affected -t build 25 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-gh-actions/files/.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: RELEASE 2 | on: [workflow_dispatch] 3 | jobs: 4 | main: 5 | runs-on: ubuntu-latest 6 | steps: 7 | - uses: actions/checkout@v2 8 | with: 9 | fetch-depth: 0 10 | - uses: nrwl/nx-set-shas@v3 11 | - name: Install deps 12 | run: npm ci 13 | - name: Lint 14 | run: npx nx run-many -t lint 15 | - name: Test 16 | run: npx nx run-many -t test --configuration=ci 17 | - name: Release 18 | run: npx semantic-release 19 | env: 20 | GITHUB_TOKEN: ${{ secrets.GH_TOKEN }} 21 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 22 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-gh-actions/generator.spec.ts: -------------------------------------------------------------------------------- 1 | import {createTreeWithEmptyWorkspace} from '@nx/devkit/testing'; 2 | import * as nxDevkit from '@nx/devkit'; 3 | import {Tree} from '@nx/devkit'; 4 | 5 | import * as spinnerHelper from "../helpers/spinner.helper"; 6 | 7 | import {GenerateGhActionsGeneratorSchema} from './schema'; 8 | import generateGhActionsGenerator from "./generator"; 9 | 10 | describe('generate-gh-actions generator', () => { 11 | let tree: Tree; 12 | const options: GenerateGhActionsGeneratorSchema = { name: 'test' }; 13 | 14 | beforeEach(() => { 15 | tree = createTreeWithEmptyWorkspace(); 16 | jest.spyOn(spinnerHelper, 'getSpinner').mockReturnValue(({ 17 | start: jest.fn(), 18 | succeed: jest.fn(), 19 | fail: jest.fn(), 20 | }) as any 21 | ); 22 | }); 23 | 24 | it('should generate the GitHub actions', async () => { 25 | jest.spyOn(nxDevkit, 'generateFiles').mockImplementation(() => {}); 26 | 27 | await generateGhActionsGenerator(tree, options); 28 | expect(nxDevkit.generateFiles).toHaveBeenCalled(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-gh-actions/generator.ts: -------------------------------------------------------------------------------- 1 | import {formatFiles, generateFiles, Tree,} from '@nx/devkit'; 2 | import * as path from 'path'; 3 | 4 | import {getSpinner} from '../helpers/spinner.helper'; 5 | 6 | import {GenerateGhActionsGeneratorSchema} from './schema'; 7 | 8 | export async function generateGhActionsGenerator( 9 | tree: Tree, 10 | options: GenerateGhActionsGeneratorSchema 11 | ) { 12 | const spinner = getSpinner(); 13 | try { 14 | spinner.text = `🐋 nx-release: generating GitHub actions workflow files`; 15 | spinner.start(); 16 | generateFiles(tree, path.join(__dirname, 'files'), '.', options); 17 | spinner.succeed(); 18 | 19 | await formatFiles(tree); 20 | } catch (e) { 21 | spinner.fail(`🐋 nx-release: something went wrong: ${e.toString()}`); 22 | } 23 | } 24 | 25 | export default generateGhActionsGenerator; 26 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-gh-actions/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface GenerateGhActionsGeneratorSchema {} 2 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-gh-actions/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "GenerateGhActions", 4 | "title": "", 5 | "type": "object", 6 | "properties": { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-release-config/files/release.config.js.template: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | branches: ['main'], 3 | preset: 'conventionalcommits', 4 | presetConfig: { 5 | types: [ 6 | { type: 'feat', section: 'Features' }, 7 | { type: 'fix', section: 'Bug Fixes' }, 8 | { type: 'chore', section: 'Chores' }, 9 | { type: 'docs', hidden: true }, 10 | { type: 'style', hidden: true }, 11 | { type: 'refactor', section: 'Refactoring' }, 12 | { type: 'perf', hidden: true }, 13 | { type: 'test', hidden: true }, 14 | ], 15 | }, 16 | releaseRules: [{ type: 'refactor', release: 'patch' }], 17 | plugins: [ 18 | '@semantic-release/commit-analyzer', 19 | '@semantic-release/release-notes-generator', 20 | [ 21 | '@semantic-release/changelog', 22 | { 23 | changelogFile: `./CHANGELOG.md`, 24 | }, 25 | ], 26 | ["@semantic-release/exec", { 27 | prepareCmd: `VERSION=\${nextRelease.version} npx nx run-many -t release && VERSION=\${nextRelease.version} npx -p replace-json-property rjp ./package.json version \${nextRelease.version}`, 28 | }], 29 | [ 30 | '@semantic-release/git', 31 | { 32 | assets: [ 33 | `libs/**/package.json`, 34 | `package.json`, 35 | `CHANGELOG.md` 36 | ], 37 | message: 38 | 'chore(release): -v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}', 39 | }, 40 | ], 41 | ], 42 | }; 43 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-release-config/generator.spec.ts: -------------------------------------------------------------------------------- 1 | import {createTreeWithEmptyWorkspace} from '@nx/devkit/testing'; 2 | import * as nxDevkit from '@nx/devkit'; 3 | import {Tree} from '@nx/devkit'; 4 | 5 | import * as spinnerHelper from "../helpers/spinner.helper"; 6 | 7 | import {generateReleaseConfigGenerator} from './generator'; 8 | import {GenerateReleaseConfigGeneratorSchema} from './schema'; 9 | 10 | describe('generate-release-config generator', () => { 11 | let tree: Tree; 12 | const options: GenerateReleaseConfigGeneratorSchema = { name: 'test' }; 13 | 14 | beforeEach(() => { 15 | tree = createTreeWithEmptyWorkspace(); 16 | jest.spyOn(spinnerHelper, 'getSpinner').mockReturnValue(({ 17 | start: jest.fn(), 18 | succeed: jest.fn(), 19 | fail: jest.fn(), 20 | }) as any 21 | ); 22 | }); 23 | 24 | it('should generate the release config', async () => { 25 | jest.spyOn(nxDevkit, 'generateFiles').mockImplementation(() => {}); 26 | 27 | await generateReleaseConfigGenerator(tree, options); 28 | expect(nxDevkit.generateFiles).toHaveBeenCalled(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-release-config/generator.ts: -------------------------------------------------------------------------------- 1 | import { 2 | addProjectConfiguration, 3 | formatFiles, 4 | generateFiles, 5 | Tree, 6 | } from '@nx/devkit'; 7 | import * as path from 'path'; 8 | import { GenerateReleaseConfigGeneratorSchema } from './schema'; 9 | import { getSpinner } from '../helpers/spinner.helper'; 10 | 11 | export async function generateReleaseConfigGenerator( 12 | tree: Tree, 13 | options: GenerateReleaseConfigGeneratorSchema 14 | ) { 15 | const spinner = getSpinner(); 16 | try { 17 | spinner.text = `🐋 nx-release: generating a release config`; 18 | spinner.start(); 19 | generateFiles(tree, path.join(__dirname, 'files'), '.', options); 20 | spinner.succeed(); 21 | 22 | await formatFiles(tree); 23 | } catch (e) { 24 | spinner.fail(`🐋 nx-release: something went wrong: ${e.toString()}`); 25 | } 26 | } 27 | 28 | export default generateReleaseConfigGenerator; 29 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-release-config/schema.d.ts: -------------------------------------------------------------------------------- 1 | export interface GenerateReleaseConfigGeneratorSchema {} 2 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/generate-release-config/schema.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/schema", 3 | "$id": "GenerateReleaseConfig", 4 | "title": "", 5 | "type": "object", 6 | "properties": {} 7 | } 8 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/helpers/projects.helpers.spec.ts: -------------------------------------------------------------------------------- 1 | import * as nxDevKit from '@nx/devkit'; 2 | 3 | import { getLibraryProjectNames, getLibraryRoot } from './projects.helpers'; 4 | 5 | describe('generator project helper', () => { 6 | it('should return the library project names', () => { 7 | const expectedLibraryNames = ['foo', 'bar']; 8 | 9 | const mockProjectConfigs = new Map(); 10 | mockProjectConfigs.set('foo', { 11 | projectType: 'library', 12 | }); 13 | mockProjectConfigs.set('bar', { 14 | projectType: 'library', 15 | }); 16 | mockProjectConfigs.set('baz', { 17 | projectType: 'application', 18 | }); 19 | 20 | jest.spyOn(nxDevKit, 'getProjects').mockReturnValue(mockProjectConfigs); 21 | 22 | expect(getLibraryProjectNames({} as any)).toEqual(expectedLibraryNames); 23 | }); 24 | 25 | it('should get the library root', () => { 26 | const mockProjectConfigs = new Map(); 27 | mockProjectConfigs.set('foo', { 28 | projectType: 'library', 29 | root: 'libs/foo', 30 | }); 31 | mockProjectConfigs.set('bar', { 32 | projectType: 'library', 33 | root: 'libs/bar', 34 | }); 35 | 36 | jest.spyOn(nxDevKit, 'getProjects').mockReturnValue(mockProjectConfigs); 37 | 38 | expect(getLibraryRoot({} as any, 'foo')).toEqual('libs/foo'); 39 | }); 40 | }); 41 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/helpers/projects.helpers.ts: -------------------------------------------------------------------------------- 1 | import {getProjects, Tree} from "@nx/devkit"; 2 | 3 | export function getLibraryProjectNames(tree: Tree): string[]{ 4 | const projectNames = []; 5 | getProjects(tree).forEach((projectConfiguration, projectName) => { 6 | if(projectConfiguration.projectType === 'library'){ 7 | projectNames.push(projectName); 8 | } 9 | }); 10 | return projectNames; 11 | } 12 | 13 | export function getLibraryRoot(tree: Tree, libraryName: string): string{ 14 | return getProjects(tree).get(libraryName).root; 15 | } 16 | -------------------------------------------------------------------------------- /libs/nx-release/src/generators/helpers/spinner.helper.ts: -------------------------------------------------------------------------------- 1 | import * as ora from "ora"; 2 | 3 | export function getSpinner(): ora.Ora { 4 | return ora(); 5 | } 6 | -------------------------------------------------------------------------------- /libs/nx-release/src/index.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nivekcode/nx-release/dec67fb7ff59167308c0161109874ce2a9b61da7/libs/nx-release/src/index.ts -------------------------------------------------------------------------------- /libs/nx-release/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | }, 6 | "files": [], 7 | "include": [], 8 | "references": [ 9 | { 10 | "path": "./tsconfig.lib.json" 11 | }, 12 | { 13 | "path": "./tsconfig.spec.json" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /libs/nx-release/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "declaration": true, 6 | "types": ["node"] 7 | }, 8 | "include": ["src/**/*.ts"], 9 | "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"] 10 | } 11 | -------------------------------------------------------------------------------- /libs/nx-release/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../dist/out-tsc", 5 | "module": "commonjs", 6 | "types": ["jest", "node"] 7 | }, 8 | "include": [ 9 | "jest.config.ts", 10 | "src/**/*.test.ts", 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /nx.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/nx/schemas/nx-schema.json", 3 | "tasksRunnerOptions": { 4 | "default": { 5 | "runner": "nx-cloud", 6 | "options": { 7 | "cacheableOperations": ["build", "lint", "test", "e2e"], 8 | "accessToken": "NDI4ZGRjZmUtYjQ1NC00ODkxLWE2NTctNjA0MWQ4Y2VlY2NlfHJlYWQtd3JpdGU=" 9 | } 10 | } 11 | }, 12 | "targetDefaults": { 13 | "build": { 14 | "dependsOn": ["^build"], 15 | "inputs": ["production", "^production"] 16 | }, 17 | "lint": { 18 | "inputs": [ 19 | "default", 20 | "{workspaceRoot}/.eslintrc.json", 21 | "{workspaceRoot}/.eslintignore" 22 | ] 23 | }, 24 | "test": { 25 | "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"] 26 | } 27 | }, 28 | "namedInputs": { 29 | "default": ["{projectRoot}/**/*", "sharedGlobals"], 30 | "production": [ 31 | "default", 32 | "!{projectRoot}/.eslintrc.json", 33 | "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)", 34 | "!{projectRoot}/tsconfig.spec.json", 35 | "!{projectRoot}/jest.config.[jt]s", 36 | "!{projectRoot}/src/test-setup.[jt]s" 37 | ], 38 | "sharedGlobals": [] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nx-release/source", 3 | "version": "3.4.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "g:configure": "nx generate @nx-release/nx-release:configure", 7 | "g:configure-workspace": "nx generate @nx-release/nx-release:configure-workspace", 8 | "g:configure-library": "nx generate @nx-release/nx-release:configure-library", 9 | "g:configure-libraries": "nx generate @nx-release/nx-release:configure-libraries", 10 | "lint": "nx lint -p nx-release", 11 | "test": "nx test -p nx-release", 12 | "test:coverage": "nx test --coverage --coverageReporters=lcov -p nx-release", 13 | "build": "nx build -p nx-release", 14 | "bump-versions": "rjp package.json version $VERSION && rjp libs/nx-release/package.json version $VERSION", 15 | "release": "VERSION=$VERSION npm run bump-versions && npm run build && nx run-many -t publish" 16 | }, 17 | "private": true, 18 | "dependencies": { 19 | "@nx/devkit": "16.5.0", 20 | "@nx/plugin": "^16.5.0", 21 | "@swc/helpers": "~0.5.0", 22 | "chalk": "^4.1.2", 23 | "inquirer": "^8.2.5", 24 | "ora": "^5.4.1", 25 | "tslib": "^2.6.0" 26 | }, 27 | "devDependencies": { 28 | "@nx/eslint-plugin": "16.5.0", 29 | "@nx/jest": "16.5.0", 30 | "@nx/js": "16.5.0", 31 | "@nx/linter": "16.5.0", 32 | "@nx/workspace": "16.5.0", 33 | "@semantic-release/changelog": "^6.0.3", 34 | "@semantic-release/commit-analyzer": "^10.0.1", 35 | "@semantic-release/exec": "^6.0.3", 36 | "@semantic-release/git": "^10.0.1", 37 | "@semantic-release/release-notes-generator": "^11.0.4", 38 | "@swc-node/register": "~1.4.2", 39 | "@swc/cli": "~0.1.62", 40 | "@swc/core": "~1.3.51", 41 | "@types/jest": "^29.4.0", 42 | "@types/node": "18.7.1", 43 | "@typescript-eslint/eslint-plugin": "^5.60.1", 44 | "@typescript-eslint/parser": "^5.60.1", 45 | "all-contributors-cli": "^6.26.1", 46 | "conventional-changelog-conventionalcommits": "^6.1.0", 47 | "eslint": "~8.15.0", 48 | "eslint-config-prettier": "8.1.0", 49 | "jest": "^29.4.1", 50 | "jest-environment-jsdom": "^29.4.1", 51 | "jest-environment-node": "^29.4.1", 52 | "nx": "16.5.0", 53 | "nx-cloud": "latest", 54 | "nx-release": "^2.1.0", 55 | "prettier": "^2.6.2", 56 | "replace-json-property": "^1.9.0", 57 | "ts-jest": "^29.1.0", 58 | "ts-node": "10.9.1", 59 | "typescript": "~5.1.3", 60 | "verdaccio": "^5.0.4" 61 | }, 62 | "repository": "https://github.com/kreuzerk/nx-release", 63 | "nx": { 64 | "includedScripts": [] 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /project.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nx-release/source", 3 | "$schema": "node_modules/nx/schemas/project-schema.json", 4 | "targets": { 5 | "local-registry": { 6 | "executor": "@nx/js:verdaccio", 7 | "options": { 8 | "port": 4873, 9 | "config": ".verdaccio/config.yml", 10 | "storage": "tmp/local-registry/storage" 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | branches: ['main'], 3 | preset: 'conventionalcommits', 4 | presetConfig: { 5 | types: [ 6 | { type: 'feat', section: 'Features' }, 7 | { type: 'fix', section: 'Bug Fixes' }, 8 | { type: 'chore', section: 'Chores' }, 9 | { type: 'docs', hidden: true }, 10 | { type: 'style', hidden: true }, 11 | { type: 'refactor', section: 'Refactoring' }, 12 | { type: 'perf', hidden: true }, 13 | { type: 'test', hidden: true }, 14 | ], 15 | }, 16 | releaseRules: [{ type: 'refactor', release: 'patch' }], 17 | plugins: [ 18 | '@semantic-release/commit-analyzer', 19 | '@semantic-release/release-notes-generator', 20 | [ 21 | '@semantic-release/changelog', 22 | { 23 | changelogFile: `./CHANGELOG.md`, 24 | }, 25 | ], 26 | ["@semantic-release/exec", { 27 | prepareCmd: `VERSION=\${nextRelease.version} npm run release`, 28 | }], 29 | [ 30 | '@semantic-release/git', 31 | { 32 | assets: [ 33 | `libs/foo/package.json`, 34 | `libs/bar/package.json`, 35 | `libs/baz/package.json`, 36 | `package.json`, 37 | `CHANGELOG.md` 38 | ], 39 | message: 40 | 'chore(release): -v${nextRelease.version} [skip ci]\n\n${nextRelease.notes}', 41 | }, 42 | ], 43 | ], 44 | }; 45 | -------------------------------------------------------------------------------- /tools/scripts/publish.mjs: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a minimal script to publish your package to "npm". 3 | * This is meant to be used as-is or customize as you see fit. 4 | * 5 | * This script is executed on "dist/path/to/library" as "cwd" by default. 6 | * 7 | * You might need to authenticate with NPM before running this script. 8 | */ 9 | 10 | import { execSync } from 'child_process'; 11 | import { readFileSync, writeFileSync } from 'fs'; 12 | 13 | import devkit from '@nx/devkit'; 14 | const { readCachedProjectGraph } = devkit; 15 | 16 | function invariant(condition, message) { 17 | if (!condition) { 18 | console.error(message); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | // Executing publish script: node path/to/publish.mjs {name} --version {version} --tag {tag} 24 | // Default "tag" to "next" so we won't publish the "latest" tag by accident. 25 | const [, , name, version, tag = 'next'] = process.argv; 26 | 27 | // A simple SemVer validation to validate the version 28 | const validVersion = /^\d+\.\d+\.\d+(-\w+\.\d+)?/; 29 | invariant( 30 | version && validVersion.test(version), 31 | `No version provided or version did not match Semantic Versioning, expected: #.#.#-tag.# or #.#.#, got ${version}.` 32 | ); 33 | 34 | const graph = readCachedProjectGraph(); 35 | const project = graph.nodes[name]; 36 | 37 | invariant( 38 | project, 39 | `Could not find project "${name}" in the workspace. Is the project.json configured correctly?` 40 | ); 41 | 42 | const outputPath = project.data?.targets?.build?.options?.outputPath; 43 | invariant( 44 | outputPath, 45 | `Could not find "build.options.outputPath" of project "${name}". Is project.json configured correctly?` 46 | ); 47 | 48 | process.chdir(outputPath); 49 | 50 | // Updating the version in "package.json" before publishing 51 | try { 52 | const json = JSON.parse(readFileSync(`package.json`).toString()); 53 | json.version = version; 54 | writeFileSync(`package.json`, JSON.stringify(json, null, 2)); 55 | } catch (e) { 56 | console.error(`Error reading package.json file from library build output.`); 57 | } 58 | 59 | // Execute "npm publish" to publish 60 | execSync(`npm publish --access public --tag ${tag}`); 61 | -------------------------------------------------------------------------------- /tools/tsconfig.tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "../dist/out-tsc/tools", 5 | "rootDir": ".", 6 | "module": "commonjs", 7 | "target": "es5", 8 | "types": ["node"], 9 | "importHelpers": false 10 | }, 11 | "include": ["**/*.ts"] 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "moduleResolution": "node", 8 | "emitDecoratorMetadata": true, 9 | "experimentalDecorators": true, 10 | "importHelpers": true, 11 | "target": "es2015", 12 | "module": "esnext", 13 | "lib": ["es2020", "dom"], 14 | "skipLibCheck": true, 15 | "skipDefaultLibCheck": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "@nx-release/nx-release": ["libs/nx-release/src/index.ts"] 19 | } 20 | }, 21 | "exclude": ["node_modules", "tmp"] 22 | } 23 | --------------------------------------------------------------------------------