├── .editorconfig ├── .gitignore ├── .prettierignore ├── .travis.yml ├── .yarnrc ├── LICENSE ├── README.md ├── index.js ├── lib ├── publish.js └── verify.js ├── package-lock.json └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | insert_final_newline = true 3 | trim_trailing_whitespace = true 4 | end_of_line = lf 5 | charset = utf-8 6 | indent_size = 2 7 | indent_style = space 8 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/macos,windows,linux,node 3 | 4 | ### Linux ### 5 | *~ 6 | 7 | # temporary files which can be created if a process still has a handle open of a deleted file 8 | .fuse_hidden* 9 | 10 | # KDE directory preferences 11 | .directory 12 | 13 | # Linux trash folder which might appear on any partition or disk 14 | .Trash-* 15 | 16 | # .nfs files are created when an open file is removed but is still being accessed 17 | .nfs* 18 | 19 | ### macOS ### 20 | *.DS_Store 21 | .AppleDouble 22 | .LSOverride 23 | 24 | # Icon must end with two \r 25 | Icon 26 | 27 | # Thumbnails 28 | ._* 29 | 30 | # Files that might appear in the root of a volume 31 | .DocumentRevisions-V100 32 | .fseventsd 33 | .Spotlight-V100 34 | .TemporaryItems 35 | .Trashes 36 | .VolumeIcon.icns 37 | .com.apple.timemachine.donotpresent 38 | 39 | # Directories potentially created on remote AFP share 40 | .AppleDB 41 | .AppleDesktop 42 | Network Trash Folder 43 | Temporary Items 44 | .apdisk 45 | 46 | ### Node ### 47 | # Logs 48 | logs 49 | *.log 50 | npm-debug.log* 51 | yarn-debug.log* 52 | yarn-error.log* 53 | 54 | # Runtime data 55 | pids 56 | *.pid 57 | *.seed 58 | *.pid.lock 59 | 60 | # Directory for instrumented libs generated by jscoverage/JSCover 61 | lib-cov 62 | 63 | # Coverage directory used by tools like istanbul 64 | coverage 65 | 66 | # nyc test coverage 67 | .nyc_output 68 | 69 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 70 | .grunt 71 | 72 | # Bower dependency directory (https://bower.io/) 73 | bower_components 74 | 75 | # node-waf configuration 76 | .lock-wscript 77 | 78 | # Compiled binary addons (http://nodejs.org/api/addons.html) 79 | build/Release 80 | 81 | # Dependency directories 82 | node_modules/ 83 | jspm_packages/ 84 | 85 | # Typescript v1 declaration files 86 | typings/ 87 | 88 | # Optional npm cache directory 89 | .npm 90 | 91 | # Optional eslint cache 92 | .eslintcache 93 | 94 | # Optional REPL history 95 | .node_repl_history 96 | 97 | # Output of 'npm pack' 98 | *.tgz 99 | 100 | # Yarn Integrity file 101 | .yarn-integrity 102 | 103 | # dotenv environment variables file 104 | .env 105 | 106 | 107 | ### Windows ### 108 | # Windows thumbnail cache files 109 | Thumbs.db 110 | ehthumbs.db 111 | ehthumbs_vista.db 112 | 113 | # Folder config file 114 | Desktop.ini 115 | 116 | # Recycle Bin used on file shares 117 | $RECYCLE.BIN/ 118 | 119 | # Windows Installer files 120 | *.cab 121 | *.msi 122 | *.msm 123 | *.msp 124 | 125 | # Windows shortcuts 126 | *.lnk 127 | 128 | # End of https://www.gitignore.io/api/macos,windows,linux,node 129 | 130 | yarn.lock 131 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | package.json 2 | package-lock.json 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: '8' 4 | 5 | cache: 6 | directories: 7 | - $HOME/.npm 8 | 9 | install: 10 | - npm install 11 | 12 | script: 13 | - npm run prettier 14 | - npm run lint 15 | 16 | jobs: 17 | include: 18 | - stage: test 19 | node_js: '8' 20 | - stage: release 21 | language: node_js 22 | node_js: '8' 23 | script: 24 | - npm run semantic-release 25 | 26 | stages: 27 | - test 28 | - name: release 29 | if: branch = master AND type = push AND fork = false 30 | 31 | branches: 32 | except: 33 | - /^v\d+\.\d+\.\d+$/ 34 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | --install.no-lockfile true 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Contributors 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 | # semantic-release-docker 2 | 3 | [![npm](https://img.shields.io/npm/v/semantic-release-docker.svg)](https://www.npmjs.com/package/felixfbecker/semantic-release-docker) 4 | [![build](https://img.shields.io/travis/felixfbecker/semantic-release-docker.svg)](https://travis-ci.org/felixfbecker/semantic-release-docker) 5 | [![downloads](https://img.shields.io/npm/dt/semantic-release-docker.svg)](https://www.npmjs.com/package/semantic-release-docker) 6 | [![dependencies](https://img.shields.io/david/felixfbecker/semantic-release-docker.svg)](https://david-dm.org/felixfbecker/semantic-release-docker) 7 | [![peerDependencies](https://david-dm.org/felixfbecker/semantic-release-docker/peer-status.svg)](https://david-dm.org/felixfbecker/semantic-release-docker?type=peer) 8 | [![Greenkeeper](https://badges.greenkeeper.io/felixfbecker/semantic-release-docker.svg)](https://greenkeeper.io/) 9 | [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) 10 | [![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release) 11 | [![license](https://img.shields.io/npm/l/semantic-release-docker.svg)](https://github.com/felixfbecker/semantic-release-docker/blob/master/LICENSE) 12 | 13 | Set of [semantic-release](https://github.com/semantic-release/semantic-release) plugins for publishing a docker image to 14 | [Docker Hub](https://hub.docker.com/). 15 | 16 | ```json 17 | { 18 | "release": { 19 | "verifyConditions": { 20 | "path": "semantic-release-docker", 21 | "registryUrl": "docker.io" 22 | }, 23 | "publish": { 24 | "path": "semantic-release-docker", 25 | "name": "username/imagename" 26 | } 27 | } 28 | } 29 | ``` 30 | 31 | ## Configuration 32 | 33 | Your credentials have to be configured with the environment variables `DOCKER_USERNAME` and `DOCKER_PASSWORD`. 34 | 35 | In addition, you need to specify the name of the image as the `name` setting in the publish step. If you need to specify a custom docker registry URL, add it as the `registryUrl` setting in the verifyConditions step. 36 | 37 | ## Plugins 38 | 39 | ### `verifyConditions` 40 | 41 | Verify that all needed configuration is present and login to the Docker registry. 42 | 43 | ### `publish` 44 | 45 | Tag the image specified by `name` with the new version, push it to Docker Hub and update the `latest` tag. 46 | 47 | ## Example .travis.yml 48 | 49 | ```yml 50 | jobs: 51 | include: 52 | - stage: release 53 | language: node_js 54 | node_js: '8' 55 | services: 56 | - docker 57 | script: 58 | - docker build -t username/imagename . 59 | - npm run semantic-release 60 | 61 | stages: 62 | - test 63 | - name: release 64 | if: branch = master AND type = push AND fork = false 65 | 66 | branches: 67 | except: 68 | - /^v\d+\.\d+\.\d+$/ 69 | ``` 70 | 71 | 72 | ## Circle CI Example .config.yml 73 | 74 | ```yml 75 | version: 2 76 | jobs: 77 | release: 78 | docker: 79 | - image: circleci/node:8 80 | steps: 81 | - setup_remote_docker: 82 | docker_layer_caching: true 83 | - run: 84 | name: release 85 | command: | 86 | docker build -t username/imagename . 87 | npm run semantic-release 88 | 89 | workflows: 90 | version: 2 91 | pipeline: 92 | jobs: 93 | - test 94 | - release: 95 | requires: 96 | - test 97 | filters: 98 | branches: 99 | only: master 100 | ``` 101 | 102 | > Note that `setup_remote_docker` step is required for this plugin to work in Circle CI environment 103 | 104 | ## How to keep new version in package.json inside docker image? 105 | In order to do that you need to run `docker build` command during semantic-release `prepareCmd` event. 106 | 107 | It can be done with help of [@semantic-release/exec](https://github.com/semantic-release/exec) for example. 108 | 109 | ```json 110 | { 111 | "plugins": [ 112 | ["@semantic-release/exec", { 113 | "prepareCmd": "docker build -t username/imagename ." 114 | }], 115 | ["semantic-release-docker", { 116 | "name": "username/imagename" 117 | }] 118 | ] 119 | } 120 | ``` 121 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const verifyConditions = require('./lib/verify') 2 | const publish = require('./lib/publish') 3 | 4 | module.exports = { 5 | verifyConditions, 6 | publish, 7 | } 8 | -------------------------------------------------------------------------------- /lib/publish.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa') 2 | 3 | module.exports = async (pluginConfig, { nextRelease: { version }, logger }) => { 4 | logger.log(`Pushing version ${pluginConfig.name}:${version} to docker hub`) 5 | 6 | // Push both new version and latest 7 | execa('docker', ['tag', `${pluginConfig.name}:latest`, `${pluginConfig.name}:${version}`], { stdio: 'inherit' }) 8 | execa('docker', ['push', `${pluginConfig.name}:${version}`], { stdio: 'inherit' }) 9 | execa('docker', ['push', `${pluginConfig.name}:latest`], { stdio: 'inherit' }) 10 | } 11 | -------------------------------------------------------------------------------- /lib/verify.js: -------------------------------------------------------------------------------- 1 | const execa = require('execa') 2 | 3 | module.exports = async (pluginConfig, { logger }) => { 4 | for (const envVar of ['DOCKER_USERNAME', 'DOCKER_PASSWORD']) { 5 | if (!process.env[envVar]) { 6 | throw new Error(`Environment variable ${envVar} is not set`) 7 | } 8 | } 9 | try { 10 | await execa( 11 | 'docker', 12 | [ 13 | 'login', 14 | pluginConfig.registryUrl || '', 15 | '-u=' + process.env.DOCKER_USERNAME, 16 | '-p=' + process.env.DOCKER_PASSWORD, 17 | ], 18 | { 19 | stdio: 'inherit', 20 | } 21 | ) 22 | } catch (err) { 23 | throw new Error('docker login failed') 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "semantic-release-docker", 3 | "description": "Set of semantic-release plugins to publish to docker hub", 4 | "version": "0.0.0-development", 5 | "engines": { 6 | "node": ">=8" 7 | }, 8 | "author": "Felix Becker", 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/felixfbecker/semantic-release-docker.git" 12 | }, 13 | "bugs": { 14 | "url": "https://github.com/felixfbecker/semantic-release-docker/issues" 15 | }, 16 | "homepage": "https://github.com/felixfbecker/semantic-release-docker#readme", 17 | "keywords": [ 18 | "docker", 19 | "hub", 20 | "publish", 21 | "push", 22 | "semantic-release", 23 | "version" 24 | ], 25 | "scripts": { 26 | "lint": "eslint lib index.js", 27 | "prettier": "prettier --write --list-different '**/*.js?(on)'", 28 | "semantic-release": "semantic-release" 29 | }, 30 | "config": { 31 | "commitizen": { 32 | "path": "cz-conventional-changelog" 33 | } 34 | }, 35 | "dependencies": { 36 | "@semantic-release/error": "^2.1.0", 37 | "execa": "^4.0.0" 38 | }, 39 | "devDependencies": { 40 | "cz-conventional-changelog": "^2.0.0", 41 | "eslint": "^4.11.0", 42 | "eslint-config-prettier": "^2.5.0", 43 | "eslint-config-standard": "^11.0.0", 44 | "eslint-plugin-import": "^2.7.0", 45 | "eslint-plugin-node": "^6.0.0", 46 | "eslint-plugin-prettier": "^2.3.0", 47 | "eslint-plugin-promise": "^3.5.0", 48 | "eslint-plugin-standard": "^3.0.1", 49 | "prettier": "1.12.1", 50 | "semantic-release": "^15.4.1", 51 | "validate-commit-msg": "^2.14.0" 52 | }, 53 | "peerDependencies": { 54 | "semantic-release": ">=11.0.0 <18.0.0" 55 | }, 56 | "eslintConfig": { 57 | "extends": [ 58 | "standard", 59 | "prettier" 60 | ], 61 | "plugins": [ 62 | "prettier" 63 | ], 64 | "rules": { 65 | "prettier/prettier": 2 66 | } 67 | }, 68 | "files": [ 69 | "lib", 70 | "index.js" 71 | ], 72 | "license": "MIT", 73 | "main": "index.js", 74 | "prettier": { 75 | "printWidth": 120, 76 | "singleQuote": true, 77 | "bracketSpacing": true, 78 | "trailingComma": "es5", 79 | "semi": false 80 | }, 81 | "publishConfig": { 82 | "access": "public" 83 | } 84 | } 85 | --------------------------------------------------------------------------------