├── .editorconfig ├── .ember-cli ├── .eslintrc.js ├── .github ├── PULL_REQUEST_TEMPLATE └── workflows │ └── ci.yaml ├── .gitignore ├── .npmignore ├── .watchmanconfig ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── RELEASE.md ├── config ├── ember-try.js └── environment.js ├── index.js ├── lib ├── legacy-table.js └── scm-table.js ├── package.json ├── tests ├── .eslintrc.js ├── index-test.js └── runner.js └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | 8 | [*] 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | indent_style = space 14 | indent_size = 2 15 | 16 | [*.hbs] 17 | insert_final_newline = false 18 | 19 | [*.{diff,md}] 20 | trim_trailing_whitespace = false 21 | -------------------------------------------------------------------------------- /.ember-cli: -------------------------------------------------------------------------------- 1 | { 2 | /** 3 | Ember CLI sends analytics information by default. The data is completely 4 | anonymous, but there are times when you might want to disable this behavior. 5 | 6 | Setting `disableAnalytics` to true will prevent any data from being sent. 7 | */ 8 | "disableAnalytics": false 9 | } 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | ecmaVersion: 10, 5 | sourceType: 'module' 6 | }, 7 | extends: 'eslint:recommended', 8 | env: { 9 | node: true 10 | }, 11 | rules: { 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE: -------------------------------------------------------------------------------- 1 | ## What Changed & Why 2 | Explain what changed and why. 3 | 4 | ## Related issues 5 | Link to related issues in this or other repositories (if any) 6 | 7 | ## PR Checklist 8 | - [ ] Add tests 9 | - [ ] Add documentation 10 | - [ ] Prefix documentation-only commits with [DOC] 11 | 12 | ## People 13 | Mention people who would be interested in the changeset (if any) 14 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Continuous Integration 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | jobs: 8 | test: 9 | name: Test 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | node-version: [14.x, 16.x, 18.x, 20.x] 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v2 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | cache: 'yarn' 21 | - run: yarn install 22 | - run: yarn test 23 | 24 | test-floating: 25 | name: Floating Dependencies 26 | runs-on: ubuntu-latest 27 | strategy: 28 | matrix: 29 | node-version: [14.x, 16.x, 18.x, 20.x] 30 | steps: 31 | - uses: actions/checkout@v2 32 | - name: Use Node.js ${{ matrix.node-version }} 33 | uses: actions/setup-node@v2 34 | with: 35 | node-version: ${{ matrix.node-version }} 36 | cache: 'yarn' 37 | - name: install dependencies 38 | run: yarn install --no-lockfile 39 | - name: test 40 | run: yarn test 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # misc 12 | /.sass-cache 13 | /connect.lock 14 | /coverage/* 15 | /libpeerconnection.log 16 | npm-debug.log* 17 | testem.log 18 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /bower_components 2 | /config/ember-try.js 3 | /dist 4 | /tests 5 | /tmp 6 | **/.gitkeep 7 | .bowerrc 8 | .editorconfig 9 | .ember-cli 10 | .gitignore 11 | .jshintrc 12 | .watchmanconfig 13 | .travis.yml 14 | bower.json 15 | ember-cli-build.js 16 | testem.js 17 | -------------------------------------------------------------------------------- /.watchmanconfig: -------------------------------------------------------------------------------- 1 | { 2 | "ignore_dirs": ["tmp", "dist"] 3 | } 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## v3.0.0 (2023-06-02) 2 | 3 | #### :boom: Breaking Change 4 | * [#71](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/71) [BREAKING] Update dependencies and node.js version requirements ([@lukemelia](https://github.com/lukemelia)) 5 | * [#57](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/57) [breaking] Switch to Github Actions for CI ([@jrjohnson](https://github.com/jrjohnson)) 6 | 7 | #### Committers: 3 8 | - Darin Doria ([@ddoria921](https://github.com/ddoria921)) 9 | - Jon Johnson ([@jrjohnson](https://github.com/jrjohnson)) 10 | - Luke Melia ([@lukemelia](https://github.com/lukemelia)) 11 | 12 | ## v2.1.2 (2020-10-27) 13 | 14 | #### :bug: Bug Fix 15 | * [#42](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/42) Luxon Take 3: Use fromJSDate instead of fromISO for ember-cli-deploy-revision-data ([@kpfefferle](https://github.com/kpfefferle)) 16 | 17 | #### Committers: 1 18 | - Kevin Pfefferle ([@kpfefferle](https://github.com/kpfefferle)) 19 | 20 | ## v2.1.1 (2020-10-23) 21 | 22 | #### :bug: Bug Fix 23 | * [#41](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/41) Fall back to ISO if timestamp is not milliseconds ([@kpfefferle](https://github.com/kpfefferle)) 24 | 25 | #### Committers: 1 26 | - Kevin Pfefferle ([@kpfefferle](https://github.com/kpfefferle)) 27 | 28 | ## v2.1.0 (2020-10-02) 29 | 30 | #### :house: Internal 31 | * [#39](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/39) Switch from Moment to Luxon ([@kpfefferle](https://github.com/kpfefferle)) 32 | 33 | #### Committers: 1 34 | - Kevin Pfefferle ([@kpfefferle](https://github.com/kpfefferle)) 35 | 36 | ## v2.0.0 (2020-05-16) 37 | 38 | #### :boom: Breaking Change 39 | * [#24](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/24) [BREAKING] Require node 10 or higher, and update ember-cli ([@lukemelia](https://github.com/lukemelia)) 40 | 41 | #### :house: Internal 42 | * [#34](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/34) Bump js-yaml from 3.8.2 to 3.13.1 ([@dependabot[bot]](https://github.com/apps/dependabot)) 43 | * [#31](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/31) Switch to release-it from ember-cli-release ([@lukemelia](https://github.com/lukemelia)) 44 | * [#28](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/28) Bump is-my-json-valid from 2.16.0 to 2.20.0 ([@dependabot[bot]](https://github.com/apps/dependabot)) 45 | * [#27](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/27) Bump js-yaml from 3.8.2 to 3.13.1 ([@dependabot[bot]](https://github.com/apps/dependabot)) 46 | * [#25](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/25) Bump stringstream from 0.0.5 to 0.0.6 ([@dependabot[bot]](https://github.com/apps/dependabot)) 47 | * [#30](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/30) Update JS to use more recent ECMAScript patterns ([@lukemelia](https://github.com/lukemelia)) 48 | * [#29](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/29) Update to dependencies to latest versions ([@lukemelia](https://github.com/lukemelia)) 49 | 50 | #### Committers: 1 51 | - Luke Melia ([@lukemelia](https://github.com/lukemelia)) 52 | 53 | # Change Log 54 | 55 | ## [1.0.1](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/1.0.1) (2018-12-12) 56 | [Full Changelog](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/compare/v1.0.0...1.0.1) 57 | 58 | **Merged pull requests:** 59 | 60 | - chore: migrate to cli-table3 [\#21](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/21) ([DanielRuf](https://github.com/DanielRuf)) 61 | 62 | ## [v1.0.0](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/v1.0.0) (2017-04-06) 63 | [Full Changelog](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/compare/v1.0.0-beta.0...v1.0.0) 64 | 65 | No changes from 1.0.0-beta.0 66 | 67 | ## [v1.0.0-beta.0](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/v1.0.0-beta.0) (2017-03-25) 68 | [Full Changelog](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/compare/v0.2.2...v1.0.0-beta.0) 69 | 70 | **Merged pull requests:** 71 | 72 | - Set environment for eslint [\#19](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/19) ([lukemelia](https://github.com/lukemelia)) 73 | - Update ember-cli and eliminate deprecation warning [\#18](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/18) ([lukemelia](https://github.com/lukemelia)) 74 | - Add yarn.lock and use yarn on CI [\#17](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/17) ([lukemelia](https://github.com/lukemelia)) 75 | - Update ember-cli to v2.11.1 [\#16](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/16) ([jrjohnson](https://github.com/jrjohnson)) 76 | - Fixing deprecation message. [\#15](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/15) ([lcpriest](https://github.com/lcpriest)) 77 | - Remove lodash dependency [\#14](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/14) ([zzarcon](https://github.com/zzarcon)) 78 | 79 | ## [v0.2.2](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/v0.2.2) (2016-06-15) 80 | [Full Changelog](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/compare/v0.2.1...v0.2.2) 81 | 82 | **Merged pull requests:** 83 | 84 | - Resolve core-object deprecation warnings. [\#12](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/12) ([blimmer](https://github.com/blimmer)) 85 | 86 | ## [v0.2.1](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/v0.2.1) (2016-04-01) 87 | [Full Changelog](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/compare/v0.2.0...v0.2.1) 88 | 89 | **Merged pull requests:** 90 | 91 | - Move lodash to be a dependency instead of a devDependency [\#10](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/10) ([lukemelia](https://github.com/lukemelia)) 92 | 93 | ## [v0.2.0](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/v0.2.0) (2016-04-01) 94 | [Full Changelog](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/compare/v0.1.2...v0.2.0) 95 | 96 | **Merged pull requests:** 97 | 98 | - display new scm revisionData [\#8](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/8) ([ghedamat](https://github.com/ghedamat)) 99 | 100 | ## [v0.1.2](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/v0.1.2) (2016-02-23) 101 | [Full Changelog](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/compare/v0.1.1...v0.1.2) 102 | 103 | **Merged pull requests:** 104 | 105 | - Removed unnecessary console.log [\#7](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/7) ([seawatts](https://github.com/seawatts)) 106 | 107 | ## [v0.1.1](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/v0.1.1) (2016-02-07) 108 | [Full Changelog](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/compare/v0.1.0...v0.1.1) 109 | 110 | **Merged pull requests:** 111 | 112 | - update ember-cli-deploy-plugin [\#5](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/5) ([ghedamat](https://github.com/ghedamat)) 113 | 114 | ## [v0.1.0](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/v0.1.0) (2015-10-25) 115 | [Full Changelog](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/compare/0.0.1...v0.1.0) 116 | 117 | **Merged pull requests:** 118 | 119 | - Update to use new verbose option for logging [\#4](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/4) ([lukemelia](https://github.com/lukemelia)) 120 | - Fix timestamp output [\#3](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/3) ([LevelbossMike](https://github.com/LevelbossMike)) 121 | - use ember install [\#1](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/pull/1) ([ghedamat](https://github.com/ghedamat)) 122 | 123 | ## [0.0.1](https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions/tree/0.0.1) (2015-07-31) 124 | 125 | 126 | \* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)* 127 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ember-cli-deploy-display-revisions 2 | 3 | [![](https://ember-cli-deploy.github.io/ember-cli-deploy-version-badges/plugins/ember-cli-deploy-display-revisions.svg)](http://ember-cli-deploy.github.io/ember-cli-deploy-version-badges/) 4 | 5 | Display a list of deployed revisions using [ember-cli-deploy](https://github.com/ember-cli/ember-cli-deploy). This plugin is for `ember-cli-deploy` >= 0.5.0. 6 | 7 | ## Installation 8 | 9 | * `ember install ember-cli-deploy-display-revisions` 10 | 11 | ## Configuration Options 12 | 13 | ### Defaults 14 | 15 | ``` 16 | ENV['display-revisions'] = { 17 | amount: 10, 18 | revisions: function(context) { 19 | return context.revisions; 20 | } 21 | } 22 | ``` 23 | 24 | ### amount 25 | 26 | Number of revisions displayed in the results table 27 | 28 | *Default:* `10` 29 | 30 | ### revisions 31 | 32 | The data to be displayed 33 | 34 | *Default:* `context.revisions`, usually received from `fetchRevisions` 35 | 36 | ## Usage 37 | 38 | * `ember deploy:list ` to list the latest 10 revisions 39 | * `ember deploy:list --amount ` to list the latest revisions 40 | 41 | ## Passing revisions 42 | 43 | `ember-cli-deploy-display-revisions` expects the `fetchRevisions` to be implemented by your index plugin, filling the `revisions` variable in context in the following format: 44 | 45 | ``` 46 | [ 47 | { 48 | revision: 'abc123', // mandatory 49 | version: 'v1', 50 | timestamp: 1438232435000, // milliseconds since epoch 51 | deployer: 'cats' 52 | }, 53 | { 54 | revision: 'def456', 55 | version: 'v2', 56 | timestamp: 1032123128000, 57 | deployer: 'dogs', 58 | active: true // indicate whether this revision is activated 59 | } 60 | ] 61 | ``` 62 | 63 | Omitted keys are not displayed in listing the results. 64 | 65 | ## Tests 66 | 67 | * yarn test 68 | 69 | ## Why `ember build` and `ember test` don't work 70 | 71 | Since this is a node-only ember-cli addon, this package does not include many files and dependencies which are part of ember-cli's typical `ember build` and `ember test` processes. 72 | -------------------------------------------------------------------------------- /RELEASE.md: -------------------------------------------------------------------------------- 1 | # Release 2 | 3 | Releases are mostly automated using 4 | [release-it](https://github.com/release-it/release-it/) and 5 | [lerna-changelog](https://github.com/lerna/lerna-changelog/). 6 | 7 | 8 | ## Preparation 9 | 10 | Since the majority of the actual release process is automated, the primary 11 | remaining task prior to releasing is confirming that all pull requests that 12 | have been merged since the last release have been labeled with the appropriate 13 | `lerna-changelog` labels and the titles have been updated to ensure they 14 | represent something that would make sense to our users. Some great information 15 | on why this is important can be found at 16 | [keepachangelog.com](https://keepachangelog.com/en/1.0.0/), but the overall 17 | guiding principle here is that changelogs are for humans, not machines. 18 | 19 | When reviewing merged PR's the labels to be used are: 20 | 21 | * breaking - Used when the PR is considered a breaking change. 22 | * enhancement - Used when the PR adds a new feature or enhancement. 23 | * bug - Used when the PR fixes a bug included in a previous release. 24 | * documentation - Used when the PR adds or updates documentation. 25 | * internal - Used for internal changes that still require a mention in the 26 | changelog/release notes. 27 | 28 | 29 | ## Release 30 | 31 | Once the prep work is completed, the actual release is straight forward: 32 | 33 | * First ensure that you have `release-it` installed globally, generally done by 34 | using one of the following commands: 35 | 36 | ``` 37 | # using https://volta.sh 38 | volta install release-it 39 | 40 | # using Yarn 41 | yarn global add release-it 42 | 43 | # using npm 44 | npm install --global release-it 45 | ``` 46 | 47 | * Second, ensure that you have installed your projects dependencies: 48 | 49 | ``` 50 | yarn install 51 | ``` 52 | 53 | * And last (but not least 😁) do your release. It requires a 54 | [GitHub personal access token](https://github.com/settings/tokens) as 55 | `$GITHUB_AUTH` environment variable. Only "repo" access is needed; no "admin" 56 | or other scopes are required. 57 | 58 | ``` 59 | export GITHUB_AUTH="f941e0..." 60 | release-it 61 | ``` 62 | 63 | [release-it](https://github.com/release-it/release-it/) manages the actual 64 | release process. It will prompt you to to choose the version number after which 65 | you will have the chance to hand tweak the changelog to be used (for the 66 | `CHANGELOG.md` and GitHub release), then `release-it` continues on to tagging, 67 | pushing the tag and commits, etc. 68 | -------------------------------------------------------------------------------- /config/ember-try.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | module.exports = { 3 | scenarios: [ 4 | { 5 | name: 'ember-lts-3.24', 6 | bower: { 7 | dependencies: { 8 | 'ember': 'components/ember#lts-3-24' 9 | }, 10 | resolutions: { 11 | 'ember': 'lts-3-24' 12 | } 13 | }, 14 | npm: { 15 | devDependencies: { 16 | 'ember-source': null 17 | } 18 | } 19 | }, 20 | { 21 | name: 'ember-lts-3.28', 22 | bower: { 23 | dependencies: { 24 | 'ember': 'components/ember#lts-3-28' 25 | }, 26 | resolutions: { 27 | 'ember': 'lts-3-28' 28 | } 29 | }, 30 | npm: { 31 | devDependencies: { 32 | 'ember-source': null 33 | } 34 | } 35 | }, 36 | { 37 | name: 'ember-release', 38 | bower: { 39 | dependencies: { 40 | 'ember': 'components/ember#release' 41 | }, 42 | resolutions: { 43 | 'ember': 'release' 44 | } 45 | }, 46 | npm: { 47 | devDependencies: { 48 | 'ember-source': null 49 | } 50 | } 51 | }, 52 | { 53 | name: 'ember-beta', 54 | bower: { 55 | dependencies: { 56 | 'ember': 'components/ember#beta' 57 | }, 58 | resolutions: { 59 | 'ember': 'beta' 60 | } 61 | }, 62 | npm: { 63 | devDependencies: { 64 | 'ember-source': null 65 | } 66 | } 67 | }, 68 | { 69 | name: 'ember-canary', 70 | bower: { 71 | dependencies: { 72 | 'ember': 'components/ember#canary' 73 | }, 74 | resolutions: { 75 | 'ember': 'canary' 76 | } 77 | }, 78 | npm: { 79 | devDependencies: { 80 | 'ember-source': null 81 | } 82 | } 83 | }, 84 | { 85 | name: 'ember-default', 86 | npm: { 87 | devDependencies: {} 88 | } 89 | } 90 | ] 91 | }; 92 | -------------------------------------------------------------------------------- /config/environment.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true*/ 2 | 'use strict'; 3 | 4 | module.exports = function(/* environment, appConfig */) { 5 | return { }; 6 | }; 7 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const DeployPluginBase = require('ember-cli-deploy-plugin'); 4 | const ScmTable = require('./lib/scm-table'); 5 | const LegacyTable = require('./lib/legacy-table'); 6 | 7 | module.exports = { 8 | name: 'ember-cli-deploy-display-revisions', 9 | 10 | createDeployPlugin(options) { 11 | let DeployPlugin = DeployPluginBase.extend({ 12 | name: options.name, 13 | 14 | defaultConfig: { 15 | amount(context) { 16 | return context.commandOptions.amount || 10; 17 | }, 18 | 19 | revisions(context) { 20 | return context.revisions; 21 | } 22 | }, 23 | 24 | displayRevisions(/* context */) { 25 | let table; 26 | let revisions = this.readConfig('revisions'); 27 | if(!revisions || revisions.length === 0) { 28 | this.log("Could not display latest revisions because no revisions were found in context.", {color: 'yellow'}); 29 | return; 30 | } 31 | 32 | revisions = revisions.slice(0, this.readConfig("amount")); 33 | 34 | let hasRevisionData = revisions.reduce(function(prev, current) { 35 | return !prev ? false : !!current.revisionData; 36 | }, true); 37 | 38 | if (hasRevisionData) { 39 | table = new ScmTable(this, revisions); 40 | } else { 41 | table = new LegacyTable(this, revisions); 42 | } 43 | 44 | table.display(); 45 | } 46 | }); 47 | 48 | return new DeployPlugin(); 49 | } 50 | }; 51 | -------------------------------------------------------------------------------- /lib/legacy-table.js: -------------------------------------------------------------------------------- 1 | let { DateTime } = require('luxon'); 2 | let CoreObject = require('core-object'); 3 | 4 | module.exports = CoreObject.extend({ 5 | init(plugin, revisions) { 6 | this._super(plugin, revisions); 7 | 8 | this._plugin = plugin; 9 | this.revisions = revisions; 10 | }, 11 | 12 | log() { 13 | this._plugin.log.apply(this._plugin, arguments); 14 | }, 15 | 16 | display() { 17 | let revisions = this.revisions; 18 | let keys = this._getKeys(revisions); 19 | 20 | this._displayHeader(keys, revisions); 21 | 22 | revisions.forEach(function(revision) { 23 | this._displayRow(keys, revision); 24 | }.bind(this)); 25 | }, 26 | 27 | _displayRow(keys, revision) { 28 | let row = ""; 29 | if(revision.active) { 30 | row += ">"; 31 | } else { 32 | row += " "; 33 | } 34 | 35 | let lastKey = keys[keys.length - 1]; 36 | 37 | keys.forEach(function(key) { 38 | let value = revision[key.name] ? revision[key.name] : ""; 39 | 40 | if(key.name === 'timestamp') { 41 | // ember-cli-deploy-revision-data provides a JS Date object, so fall back to that if not milliseconds 42 | let dt = typeof value === 'number' ? DateTime.fromMillis(value) : DateTime.fromJSDate(new Date(value)); 43 | value = dt.toFormat("yyyy/MM/dd HH:mm:ss"); 44 | } 45 | 46 | if(key.maxLength !== -1) { 47 | value = String(value).substr(0, key.maxLength); 48 | } 49 | 50 | row += " " + value + " "; 51 | 52 | let fillerLength = key.maxLength - value.length; 53 | for(let i = 0; i < fillerLength; i++) { 54 | row += " "; 55 | } 56 | if(key !== lastKey) { 57 | row += "|"; 58 | } 59 | }); 60 | 61 | this.log(row); 62 | }, 63 | 64 | _getKeys(revisions) { 65 | let keys = [ 66 | {name: 'version', maxLength: 7}, 67 | {name: 'timestamp', maxLength: 19}, 68 | {name: 'deployer', maxLength: 10}, 69 | {name: 'revision', maxLength: -1} 70 | ]; 71 | let presentKeys = []; 72 | keys.forEach(function(key) { 73 | if(this._hasKey(key.name, revisions)) { 74 | presentKeys.push(key); 75 | } 76 | }.bind(this)); 77 | return presentKeys; 78 | }, 79 | 80 | _displayHeader(keys) { 81 | let keyHeader = " "; 82 | let lastKey = keys[keys.length - 1]; 83 | 84 | keys.forEach(function(key) { 85 | let shortKey = key.maxLength === -1 ? key.name : key.name.substr(0, key.maxLength); 86 | keyHeader += " " + shortKey + " "; 87 | 88 | let fillerLength = key.maxLength === -1 ? 0 : key.maxLength - shortKey.length; 89 | for(let i = 0; i < fillerLength; i++) { 90 | keyHeader += " "; 91 | } 92 | 93 | // revision hash needs an unknown amount of space, don't display closing | 94 | if(key !== lastKey) { 95 | keyHeader += "|"; 96 | } 97 | }); 98 | this.log(keyHeader); 99 | 100 | let underline = ""; 101 | for(let i = 0; i < keyHeader.length; i++) { 102 | underline += "="; 103 | } 104 | this.log(underline); 105 | }, 106 | _hasKey(key, revisions) { 107 | return revisions.some(function(revision) { 108 | return Object.keys(revision).indexOf(key) !== -1; 109 | }); 110 | } 111 | }); 112 | -------------------------------------------------------------------------------- /lib/scm-table.js: -------------------------------------------------------------------------------- 1 | const Table = require('cli-table3'); 2 | const { DateTime } = require('luxon'); 3 | const CoreObject = require('core-object'); 4 | const RSVP = require('rsvp'); 5 | 6 | module.exports = CoreObject.extend({ 7 | init(plugin, revisions) { 8 | this._super(plugin, revisions); 9 | 10 | this._plugin = plugin; 11 | this.revisions = revisions; 12 | }, 13 | 14 | display(/* revisions */) { 15 | let table = this._createTable(); 16 | this._tableRows(table); 17 | 18 | this._plugin.logRaw(table.toString()); 19 | return RSVP.resolve(); 20 | }, 21 | 22 | _isWide() { 23 | return process.stdout.columns >= 98; 24 | }, 25 | 26 | _tableHeader() { 27 | let head = ['RevisionKey', 'Commit', 'User', 'Branch']; 28 | 29 | if (this._isWide()) { 30 | head.push('Deploy time'); 31 | } 32 | return head; 33 | }, 34 | 35 | _createTable() { 36 | let head = this._tableHeader(); 37 | 38 | return new Table({ 39 | head: head, 40 | wordWrap: true, 41 | chars: { 42 | 'top': '', 43 | 'top-mid': '', 44 | 'top-left': '', 45 | 'top-right': '', 46 | 'bottom': '', 47 | 'mid': '', 48 | 'middle': '', 49 | 'mid-mid': '', 50 | 'bottom-mid': '', 51 | 'bottom-left': '', 52 | 'bottom-right': '', 53 | 'left': '', 54 | 'left-mid': '', 55 | 'right': '', 56 | 'right-mid': '' 57 | } 58 | }); 59 | }, 60 | 61 | _tableRows(table) { 62 | this.revisions.forEach(function(revision) { 63 | let data = revision.revisionData; 64 | 65 | let row = [ 66 | ((revision.active) ? '> ' : ' ') + data.revisionKey, 67 | data.scm.sha.substr(0,8), 68 | data.scm.email, 69 | data.scm.branch, 70 | ]; 71 | 72 | if (this._isWide()) { 73 | let { timestamp } = data; 74 | // ember-cli-deploy-revision-data provides a JS Date object, so fall back to that if not milliseconds 75 | let dt = typeof timestamp === 'number' ? DateTime.fromMillis(timestamp) : DateTime.fromJSDate(new Date(timestamp)); 76 | let value = dt.toFormat('yyyy/MM/dd HH:mm:ss'); 77 | row.push(value); 78 | } 79 | 80 | table.push(row); 81 | 82 | }.bind(this)); 83 | }, 84 | 85 | }); 86 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ember-cli-deploy-display-revisions", 3 | "version": "3.0.0", 4 | "description": "Display a list of deployed revisions using ember-cli-deploy.", 5 | "keywords": [ 6 | "ember-addon", 7 | "ember-cli-deploy-plugin" 8 | ], 9 | "repository": "https://github.com/ember-cli-deploy/ember-cli-deploy-display-revisions", 10 | "license": "MIT", 11 | "author": "", 12 | "directories": { 13 | "doc": "doc", 14 | "test": "tests" 15 | }, 16 | "scripts": { 17 | "release": "release-it", 18 | "test": "node tests/runner.js && ./node_modules/.bin/eslint index.js lib/* tests/*" 19 | }, 20 | "dependencies": { 21 | "cli-table3": "^0.6.3", 22 | "core-object": "^3.1.5", 23 | "ember-cli-deploy-plugin": "^0.2.9", 24 | "luxon": "^3.3.0", 25 | "rsvp": "^4.8.5" 26 | }, 27 | "devDependencies": { 28 | "chai": "^4.3.7", 29 | "chai-as-promised": "^7.1.1", 30 | "ember-cli": "^3.28.6", 31 | "eslint": "^8.41.0", 32 | "glob": "^10.2.6", 33 | "mocha": "^10.2.0", 34 | "release-it": "14.4.1", 35 | "release-it-lerna-changelog": "^3.1.0" 36 | }, 37 | "engines": { 38 | "node": "14.* || 16.* || 18.* || >= 20" 39 | }, 40 | "publishConfig": { 41 | "registry": "https://registry.npmjs.org" 42 | }, 43 | "ember-addon": {}, 44 | "release-it": { 45 | "plugins": { 46 | "release-it-lerna-changelog": { 47 | "infile": "CHANGELOG.md", 48 | "launchEditor": false 49 | } 50 | }, 51 | "git": { 52 | "tagName": "v${version}" 53 | }, 54 | "github": { 55 | "release": true, 56 | "tokenRef": "GITHUB_AUTH" 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | globals: { 3 | "describe": true, 4 | "beforeEach": true, 5 | "it": true 6 | }, 7 | env: { 8 | mocha: true 9 | } 10 | }; 11 | -------------------------------------------------------------------------------- /tests/index-test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { DateTime } = require('luxon'); 4 | const chai = require('chai'); 5 | const chaiAsPromised = require("chai-as-promised"); 6 | chai.use(chaiAsPromised); 7 | 8 | const assert = chai.assert; 9 | 10 | describe('displayRevisions plugin', function() { 11 | let subject, mockUi, config; 12 | 13 | beforeEach(function() { 14 | subject = require('../index'); 15 | mockUi = { 16 | verbose: true, 17 | messages: [], 18 | write() { }, 19 | writeLine(message) { 20 | this.messages.push(message); 21 | } 22 | }; 23 | }); 24 | 25 | it('has a name', function() { 26 | let plugin = subject.createDeployPlugin({ 27 | name: 'test-plugin' 28 | }); 29 | 30 | assert.equal(plugin.name, 'test-plugin'); 31 | }); 32 | 33 | it('implements the correct hooks', function() { 34 | let plugin = subject.createDeployPlugin({ 35 | name: 'test-plugin' 36 | }); 37 | 38 | assert.equal(typeof plugin.displayRevisions, 'function'); 39 | }); 40 | 41 | describe('configure hook', function() { 42 | let plugin, context; 43 | describe('without providing config', function () { 44 | beforeEach(function() { 45 | config = { }; 46 | plugin = subject.createDeployPlugin({ 47 | name: 'displayRevisions' 48 | }); 49 | context = { 50 | ui: mockUi, 51 | config: config 52 | }; 53 | plugin.beforeHook(context); 54 | }); 55 | it('warns about missing optional config', function() { 56 | plugin.configure(context); 57 | let messages = mockUi.messages.reduce(function(previous, current) { 58 | if (/- Missing config:\s.*, using default:\s/.test(current)) { 59 | previous.push(current); 60 | } 61 | 62 | return previous; 63 | }, []); 64 | 65 | assert.equal(messages.length, 2); 66 | }); 67 | 68 | it('adds default config to the config object', function() { 69 | plugin.configure(context); 70 | assert.isDefined(config.displayRevisions.amount); 71 | }); 72 | }); 73 | 74 | describe('with an amount provided', function () { 75 | beforeEach(function() { 76 | config = { 77 | displayRevisions: { 78 | amount: 20 79 | } 80 | }; 81 | plugin = subject.createDeployPlugin({ 82 | name: 'displayRevisions' 83 | }); 84 | context = { 85 | ui: mockUi, 86 | config: config 87 | }; 88 | plugin.beforeHook(context); 89 | }); 90 | it('does not warn about missing optional config', function() { 91 | plugin.configure(context); 92 | let messages = mockUi.messages.reduce(function(previous, current) { 93 | if (/- Missing config:\s.*, using default:\s/.test(current)) { 94 | previous.push(current); 95 | } 96 | 97 | return previous; 98 | }, []); 99 | assert.equal(messages.length, 1); 100 | }); 101 | }); 102 | }); 103 | describe('displayRevisions hook with revisionData', function() { 104 | let plugin, context; 105 | 106 | beforeEach(function() { 107 | plugin = subject.createDeployPlugin({ 108 | name: 'display-revisions' 109 | }); 110 | 111 | context = { 112 | ui: mockUi, 113 | config: { }, 114 | commandOptions: { 115 | amount: 3 116 | }, 117 | revisions: [ 118 | { revision: "rev:first", revisionData: {revisionKey: 'rev:first', scm: {sha: '99ee96e7ee7d36717524bd6489d2eff966c83c3d', email: 'mattia@mail.com', branch: 'foo'}, timestamp: 1032123125000}}, 119 | { revision: "rev:second", revisionData: {revisionKey: 'rev:second', scm: {sha: 'eeee96e7ee7d36717524bd6489d2eff966c83c3d', email: 'aaron@mail.com', branch: 'bar'}, timestamp: 1032123127000}}, 120 | { revision: "rev:third", revisionData: {revisionKey: 'rev:third', scm: {sha: 'ffee96e7ee7d36717524bd6489d2eff966c83c3d', email: 'luke@mail.com', branch: 'foo'}, timestamp: 1032123128000}}, 121 | ] 122 | }; 123 | plugin.beforeHook(context); 124 | plugin.configure(context); 125 | }); 126 | 127 | it('lists revisions', function() { 128 | plugin.displayRevisions(context); 129 | let messages = mockUi.messages.reduce(function(previous, current) { 130 | if (current.indexOf("rev:") !== -1) { 131 | previous.push(current); 132 | } 133 | 134 | return previous; 135 | }, []); 136 | assert.equal(messages.length, 1); // logs a single message as table 137 | let message = messages[0]; 138 | assert.match(message, /RevisionKey/); 139 | assert.match(message, /Commit/); 140 | assert.match(message, /User/); 141 | assert.match(message, /Branch/); 142 | 143 | let lines = message.split("\n"); 144 | assert.equal(lines.length, 4); // logs headers and 3 revisions 145 | let revisionLine = lines[1]; 146 | assert.match(revisionLine, /rev:first/); 147 | assert.match(revisionLine, /mattia@mail.com/); 148 | }); 149 | }); 150 | 151 | describe('displayRevisions hook', function() { 152 | let plugin, context; 153 | 154 | beforeEach(function() { 155 | plugin = subject.createDeployPlugin({ 156 | name: 'display-revisions' 157 | }); 158 | 159 | context = { 160 | ui: mockUi, 161 | config: { }, 162 | commandOptions: { 163 | amount: 3 164 | }, 165 | revisions: [ 166 | { revision: "rev:abcdef", timestamp: 1438232435000, deployer: "My Hamster"}, 167 | { revision: "rev:defghi", timestamp: '2002-09-15T20:52:05.000Z', deployer: "My Hamster", active: true}, 168 | { revision: "rev:jklmno", timestamp: new Date(1032123128000), deployer: "My Hamster"}, 169 | { revision: "rev:qrstuv", timestamp: 1032123155000, deployer: "My Hamster"}, 170 | { revision: "rev:xyz123", timestamp: 1032123123000, deployer: "My Hamster"} 171 | ] 172 | }; 173 | plugin.beforeHook(context); 174 | plugin.configure(context); 175 | }); 176 | 177 | it('lists revisions limited by the amount specified', function() { 178 | plugin.displayRevisions(context); 179 | let messages = mockUi.messages.reduce(function(previous, current) { 180 | if (current.indexOf("rev:") !== -1) { 181 | previous.push(current); 182 | } 183 | 184 | return previous; 185 | }, []); 186 | assert.equal(messages.length, 3); 187 | }); 188 | 189 | it('skips unset keys', function() { 190 | plugin.displayRevisions(context); 191 | let messages = mockUi.messages.reduce(function(previous, current) { 192 | if (/ version /.test(current)) { 193 | previous.push(current); 194 | } 195 | 196 | return previous; 197 | }, []); 198 | assert.equal(messages.length, 0); 199 | }); 200 | 201 | it('transforms millisecond timestamps to human-readable dates (yyyy/MM/dd HH:mm:ss)', function() { 202 | plugin.displayRevisions(context); 203 | let expectedFormat = ('yyyy/MM/dd HH:mm:ss'); 204 | let expectedDate = DateTime.fromMillis(1438232435000).toFormat(expectedFormat); 205 | 206 | let messages = mockUi.messages.reduce(function(previous, current) { 207 | if (current.indexOf(expectedDate) !== -1) { 208 | previous.push(current); 209 | } 210 | 211 | return previous; 212 | }, []); 213 | assert.equal(messages.length, 1); 214 | }); 215 | 216 | it('transforms ISO string timestamps to human-readable dates (yyyy/MM/dd HH:mm:ss)', function() { 217 | plugin.displayRevisions(context); 218 | let expectedFormat = ('yyyy/MM/dd HH:mm:ss'); 219 | let expectedDate = DateTime.fromISO('2002-09-15T20:52:05.000Z').toFormat(expectedFormat); 220 | 221 | let messages = mockUi.messages.reduce(function(previous, current) { 222 | if (current.indexOf(expectedDate) !== -1) { 223 | previous.push(current); 224 | } 225 | 226 | return previous; 227 | }, []); 228 | assert.equal(messages.length, 1); 229 | }); 230 | 231 | it('transforms JS Date object timestamps to human-readable dates (yyyy/MM/dd HH:mm:ss)', function() { 232 | plugin.displayRevisions(context); 233 | let expectedFormat = ('yyyy/MM/dd HH:mm:ss'); 234 | let expectedDate = DateTime.fromJSDate(new Date(1032123128000)).toFormat(expectedFormat); 235 | 236 | let messages = mockUi.messages.reduce(function(previous, current) { 237 | if (current.indexOf(expectedDate) !== -1) { 238 | previous.push(current); 239 | } 240 | 241 | return previous; 242 | }, []); 243 | assert.equal(messages.length, 1); 244 | }); 245 | 246 | it('highlights the active revision', function() { 247 | plugin.displayRevisions(context); 248 | let messages = mockUi.messages.reduce(function(previous, current) { 249 | if (current.indexOf(">") !== -1) { 250 | previous.push(current); 251 | } 252 | 253 | return previous; 254 | }, []); 255 | assert.equal(messages.length, 1); 256 | }); 257 | }); 258 | }); 259 | -------------------------------------------------------------------------------- /tests/runner.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var glob = require('glob'); 4 | var Mocha = require('mocha'); 5 | 6 | var mocha = new Mocha({ 7 | reporter: 'spec' 8 | }); 9 | 10 | var arg = process.argv[2]; 11 | var root = 'tests/'; 12 | 13 | function addFiles(mocha, files) { 14 | glob.sync(root + files).forEach(mocha.addFile.bind(mocha)); 15 | } 16 | 17 | addFiles(mocha, '/**/*-test.js'); 18 | 19 | if (arg === 'all') { 20 | addFiles(mocha, '/**/*-test-slow.js'); 21 | } 22 | 23 | mocha.run(function(failures) { 24 | process.on('exit', function() { 25 | process.exit(failures); 26 | }); 27 | }); 28 | --------------------------------------------------------------------------------