diff --git a/.travis.yml b/.travis.yml index b2e8d24..751475a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,5 +13,6 @@ install: export DISPLAY=':99.0' /usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & fi + - npm install script: - npm test diff --git a/.vscodeignore b/.vscodeignore index 3b76c81..1001b20 100644 --- a/.vscodeignore +++ b/.vscodeignore @@ -11,4 +11,4 @@ vsc-extension-quickstart.md temp/** test-temp/** .idea/** -images/examles \ No newline at end of file +images/examples \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index ff76fdb..1e6905e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,29 @@ # Change Log -All notable changes to the "git-semantic-commit" extension will be documented in this file. +All notable changes to this project will be documented in this file. -Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased] +## [2.0.0] - 2020-02-06 -- Initial release +### Added + +- Add new types with helpful descriptions

Improving default types

+- Add new option to show description for types ([#de88ff6](https://github.com/nitayneeman/vscode-git-semantic-commit/commit/de88ff66cab1bc3788915aafc7b3756209f08dc2)) - thanks to [@balazsorban44](https://github.com/balazsorban44)

Showing Descriptions for Types

+ +## [1.1.0] - 2019-10-25 + +### Added + +- Add new option to change the scope template through a placeholder ([#610a3fc](https://github.com/nitayneeman/vscode-git-semantic-commit/commit/610a3fc9550b4a88fcea06741c3cd6602a2051d3)) - thanks to [@axelprox](https://github.com/axelprox)

Changing the Scope Template

+ +## [1.0.1] - 2019-10-22 + +### Changed + +- Change to use `git diff` for checking the staging area + +## [1.0.0] - 2019-10-21 + +- 🎉 Initial release diff --git a/README.md b/README.md index d658a60..b548524 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ This Visual Studio Code extension enables to commit simply by the semantic messa Preview

+Notice that the default types are aligned with the Angular commit message [conventions](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#type). +
## 👨🏻‍🏫 How to Use @@ -39,7 +41,7 @@ Well, there are two ways to trigger the "Semantic Commit" command: Open the Command Palette and start typing `Git: Semantic Commit`:

- Preview + Triggering using the Command Palette

Then, choose the appropriate command and follow the steps. @@ -49,7 +51,7 @@ Then, choose the appropriate command and follow the steps. Alternatively, you can use the primary and secondary actions within the Source Control view:

- Preview + Triggering using the View Actions


@@ -62,9 +64,26 @@ The extension allows you to customize the following configuration settings: | --------------------------------- | ------------------------------------------------------------------------------------------------------------------ | | `gitSemanticCommit.commitOptions` | Specifies which [arguments](https://git-scm.com/docs/git-commit#_options) to be passed when the commit is executed | | `gitSemanticCommit.preserveScope` | Determines whether to preserve the last message scope that was inserted | +| `gitSemanticCommit.scopeTemplate` | Specifies scope template (`$scope` placeholder will be replaced with the passed scope) | | `gitSemanticCommit.stageAll` | Determines whether to stage all changes before the commit, in case the staging area (index) is empty | | `gitSemanticCommit.types` | Specifies the supported message types | +### Customize Your Types + +Besides the fact you can add new message types, it's also possible to modify the existing values and their descriptions: + +

+ Enriching types with Emojis +

+ +### Customize Your Scope + +You can modify the scope template through a placeholder: + +

+ Changing the Scope Template +

+
## 💁🏻 Contributing diff --git a/images/examples/settings/scope-template.gif b/images/examples/settings/scope-template.gif new file mode 100644 index 0000000..b4188de Binary files /dev/null and b/images/examples/settings/scope-template.gif differ diff --git a/images/examples/settings/types-with-emojis.png b/images/examples/settings/types-with-emojis.png new file mode 100644 index 0000000..47a7826 Binary files /dev/null and b/images/examples/settings/types-with-emojis.png differ diff --git a/images/examples/usage/types-with-descriptions.png b/images/examples/usage/types-with-descriptions.png new file mode 100644 index 0000000..e72e742 Binary files /dev/null and b/images/examples/usage/types-with-descriptions.png differ diff --git a/package-lock.json b/package-lock.json index d2556a1..f994d49 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "git-semantic-commit", - "version": "1.0.0", + "version": "2.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -452,9 +452,9 @@ } }, "https-proxy-agent": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", - "integrity": "sha512-c8Ndjc9Bkpfx/vCJueCPy0jlP4ccCCSNDp8xwCZzPjKJUm+B+u9WX2x98Qx4n1PiMNTWo3D7KK5ifNV/yJyRzg==", + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, "requires": { "agent-base": "^4.3.0", @@ -561,9 +561,9 @@ } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==", "dev": true }, "log-symbols": { @@ -986,9 +986,9 @@ "dev": true }, "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", "dev": true }, "yargs": { diff --git a/package.json b/package.json index 0507765..2df1e2b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "git-semantic-commit", - "version": "1.0.0", + "version": "2.0.0", "license": "MIT", "author": "Nitay Neeman", "description": "💬 A Visual Studio Code extension which enables to commit simply by the semantic message conventions", @@ -21,7 +21,7 @@ "icon": "images/logo.png", "galleryBanner": { "color": "#eae9e1", - "theme": "dark" + "theme": "light" }, "engines": { "vscode": "^1.39.0" @@ -29,6 +29,13 @@ "categories": [ "Other" ], + "badges": [ + { + "description": "Build", + "url": "https://travis-ci.com/nitayneeman/vscode-git-semantic-commit.svg?token=vHfpxFNvotCsScqrpvMs&branch=master", + "href": "https://travis-ci.com/nitayneeman/vscode-git-semantic-commit" + } + ], "activationEvents": [ "*" ], @@ -48,6 +55,11 @@ "default": false, "markdownDescription": "Determines whether to preserve the last message scope that was inserted." }, + "gitSemanticCommit.scopeTemplate": { + "type": "string", + "default": "($scope)", + "markdownDescription": "Specifies scope template (`$scope` placeholder will be replaced with the passed scope). Check out [this](https://github.com/nitayneeman/vscode-git-semantic-commit#customize-your-scope) example." + }, "gitSemanticCommit.stageAll": { "type": "boolean", "default": true, @@ -56,20 +68,53 @@ "gitSemanticCommit.types": { "type": "array", "default": [ - "chore", - "docs", - "feat", - "fix", - "refactor", - "style", - "test" + { + "type": "build", + "description": "Development changes related to the build system" + }, + { + "type": "ci", + "description": "Development changes related to the continuous integration and deployment system" + }, + { + "type": "docs", + "description": "Documentation changes related to the project" + }, + { + "type": "feat", + "description": "Production changes related to new backward-compatible abilities or functionality" + }, + { + "type": "fix", + "description": "Production changes related to backward-compatible bug fixes" + }, + { + "type": "perf", + "description": "Production changes related to backward-compatible performance improvements" + }, + { + "type": "refactor", + "description": "Development changes related to modifying the codebase" + }, + { + "type": "style", + "description": "Development changes related to styling the codebase" + }, + { + "type": "test", + "description": "Development changes related to tests" + } ], "items": { - "type": "string" + "type": [ + "string", + "object" + ], + "description": "Can be either a string, or an object. If an object, use type for the commit type, and description to give a short description for the particular commit type." }, "minItems": 1, "uniqueItems": true, - "markdownDescription": "Specifies the supported message types." + "markdownDescription": "Specifies the supported message types. Check out [this](https://github.com/nitayneeman/vscode-git-semantic-commit#customize-your-types) example." } } }, @@ -109,7 +154,7 @@ "vscode:prepublish": "npm run compile", "compile": "tsc -p ./", "watch": "tsc -watch -p ./", - "pretest": "npm run compile && ./scripts/pretest.sh", + "pretest": "npm run compile && git init test-temp --quiet", "test": "node ./out/test/runTest.js" }, "devDependencies": { diff --git a/scripts/pretest.sh b/scripts/pretest.sh deleted file mode 100755 index fd07655..0000000 --- a/scripts/pretest.sh +++ /dev/null @@ -1,5 +0,0 @@ -mkdir test-temp - -cd test-temp - -git init --quiet \ No newline at end of file diff --git a/src/commands/semantic-commit.ts b/src/commands/semantic-commit.ts index fdb0d49..45ee6f9 100644 --- a/src/commands/semantic-commit.ts +++ b/src/commands/semantic-commit.ts @@ -2,7 +2,7 @@ import { window, workspace, ExtensionContext, QuickPickItem } from 'vscode'; import { getConfiguration, ConfigurationProperties } from '../config'; import { Git } from '../git'; -import { workspaceStorageKey } from '../constants'; +import { workspaceStorageKey, scopeTemplatePlaceholder } from '../constants'; import { Command } from './common'; const enum ActionType { @@ -17,7 +17,7 @@ export class SemanticCommitCommand extends Command { context: ExtensionContext; scope: string; - types: string[]; + types: (string | {type: string, description: string})[]; constructor(context: ExtensionContext) { super(); @@ -75,6 +75,11 @@ export class SemanticCommitCommand extends Command { return getConfiguration()[ConfigurationProperties.stageAll]; } + private get scopeTemplate() { + const template = getConfiguration()[ConfigurationProperties.scopeTemplate]; + return template.length ? template : scopeTemplatePlaceholder; + } + private hasScope() { return this.scope.length > 0; } @@ -105,13 +110,17 @@ export class SemanticCommitCommand extends Command { private createQuickPickItems(): QuickPickItem[] { const hasScope = this.hasScope(); - const typeItems = this.types.map(type => ({ - label: `$(git-commit) Commit with "${type}" type`, - alwaysShow: true, - actionType: ActionType.subject, - type, - description: '' - })); + const typeItems = this.types.map(item => { + const description = typeof item === "string" ? "" : item.description + const type = typeof item === "string" ? item : item.type + return ({ + label: `$(git-commit) Commit with "${type}" type`, + alwaysShow: true, + actionType: ActionType.subject, + type, + description + }) + }); return [ { @@ -129,7 +138,10 @@ export class SemanticCommitCommand extends Command { private async performCommit(type: string, subject: string) { if (subject.length > 0) { - const message = `${type}${this.hasScope() ? `(${this.scope})` : ''}: ${subject}`; + const scope = this.hasScope() + ? this.scopeTemplate.replace(scopeTemplatePlaceholder, this.scope) + : ''; + const message = `${type}${scope}: ${subject}`; if (this.isStageAllEnabled()) { try { diff --git a/src/config.ts b/src/config.ts index fbdbac3..fd9b719 100644 --- a/src/config.ts +++ b/src/config.ts @@ -8,6 +8,7 @@ enum ConfigurationProperties { commitOptions = 'commitOptions', preserveScope = 'preserveScope', stageAll = 'stageAll', + scopeTemplate = 'scopeTemplate', types = 'types' } diff --git a/src/constants.ts b/src/constants.ts index 8ae7f0d..2bf3a4b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -2,4 +2,6 @@ const extensionIdentifier = 'gitSemanticCommit'; const workspaceStorageKey = 'gitSemanticCommit'; -export { extensionIdentifier, workspaceStorageKey }; +const scopeTemplatePlaceholder = '$scope'; + +export { extensionIdentifier, workspaceStorageKey, scopeTemplatePlaceholder }; diff --git a/src/git.ts b/src/git.ts index 75f30b4..be71cb0 100644 --- a/src/git.ts +++ b/src/git.ts @@ -9,9 +9,9 @@ export class Git { } static async add() { - const { stdout: hasStaged } = await this.status(['--porcelain', '--untracked-files=no']); + const { stdout: changes } = await this.diff(['--cached']); - if (!hasStaged) { + if (changes.length === 0) { return this.execute(getWorkspaceFolder(), 'add', [`--all`]); } } @@ -24,7 +24,7 @@ export class Git { return exec(`git ${command} ${options.join(' ')}`, { cwd }); } - private static async status(options: string[] = []) { - return this.execute(getWorkspaceFolder(), 'status', [...options]); + private static async diff(options: string[] = []) { + return this.execute(getWorkspaceFolder(), 'diff', [...options]); } } diff --git a/src/test/runTest.ts b/src/test/runTest.ts index b317851..01bfac7 100644 --- a/src/test/runTest.ts +++ b/src/test/runTest.ts @@ -5,7 +5,7 @@ async function main() { try { const extensionDevelopmentPath = path.resolve(__dirname, '../../'); const extensionTestsPath = path.resolve(__dirname, './suite/index'); - const testWorkspace = path.resolve(__dirname, './test-temp'); + const testWorkspace = path.resolve(__dirname, '../../test-temp'); await runTests({ extensionDevelopmentPath, diff --git a/src/test/suite/extension.test.ts b/src/test/suite/extension.test.ts index 80cb566..25da345 100644 --- a/src/test/suite/extension.test.ts +++ b/src/test/suite/extension.test.ts @@ -1,44 +1,54 @@ -import * as assert from 'assert'; -import * as vscode from 'vscode'; +import * as assert from "assert"; +import * as vscode from "vscode"; -import { createFile, clearDirectory, getLastMessage } from './common'; +import { createFile, clearDirectory, getLastMessage } from "./common"; -suite('Extension Test Suite', () => { +suite("Extension Test Suite", () => { const { workspaceFolders } = vscode.workspace; - const directoryPath = workspaceFolders ? workspaceFolders[0].uri.fsPath : ''; + const directoryPath = workspaceFolders ? workspaceFolders[0].uri.fsPath : ""; suiteTeardown(() => clearDirectory(directoryPath)); - test('should commit with "chore" type', async () => { - const sampleSubject = 'add new file'; - const expectedMessage = `chore: ${sampleSubject}`; + test('should commit with "build" type', async () => { + const sampleSubject = "add new file"; + const expectedMessage = `build: ${sampleSubject}`; - await createFile(directoryPath, 'Hello World'); + await createFile(directoryPath, "Hello World"); await vscode.env.clipboard.writeText(sampleSubject); - await vscode.commands.executeCommand('gitSemanticCommit.semanticCommit'); - await vscode.commands.executeCommand('editor.action.clipboardPasteAction'); - await vscode.commands.executeCommand('workbench.action.quickOpenSelectNext'); - await vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'); + await vscode.commands.executeCommand("gitSemanticCommit.semanticCommit"); + await vscode.commands.executeCommand("editor.action.clipboardPasteAction"); + await vscode.commands.executeCommand( + "workbench.action.quickOpenSelectNext" + ); + await vscode.commands.executeCommand( + "workbench.action.acceptSelectedQuickOpenItem" + ); await new Promise(resolve => setTimeout(resolve, 3000)); const { stdout: message } = await getLastMessage(directoryPath); assert.equal(message.includes(expectedMessage), true); }); - test('should commit with a scope and "chore" type', async () => { - const sampleScope = 'scope'; - const sampleSubject = 'add new file'; - const expectedMessage = `chore(${sampleScope}): ${sampleSubject}`; + test('should commit with a scope and "build" type', async () => { + const sampleScope = "scope"; + const sampleSubject = "add new file"; + const expectedMessage = `build(${sampleScope}): ${sampleSubject}`; - await createFile(directoryPath, 'Hello World'); + await createFile(directoryPath, "Hello World"); await vscode.env.clipboard.writeText(sampleScope); - await vscode.commands.executeCommand('gitSemanticCommit.semanticCommit'); - await vscode.commands.executeCommand('editor.action.clipboardPasteAction'); - await vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'); + await vscode.commands.executeCommand("gitSemanticCommit.semanticCommit"); + await vscode.commands.executeCommand("editor.action.clipboardPasteAction"); + await vscode.commands.executeCommand( + "workbench.action.acceptSelectedQuickOpenItem" + ); await vscode.env.clipboard.writeText(sampleSubject); - await vscode.commands.executeCommand('editor.action.clipboardPasteAction'); - await vscode.commands.executeCommand('workbench.action.quickOpenSelectNext'); - await vscode.commands.executeCommand('workbench.action.acceptSelectedQuickOpenItem'); + await vscode.commands.executeCommand("editor.action.clipboardPasteAction"); + await vscode.commands.executeCommand( + "workbench.action.quickOpenSelectNext" + ); + await vscode.commands.executeCommand( + "workbench.action.acceptSelectedQuickOpenItem" + ); await new Promise(resolve => setTimeout(resolve, 3000)); const { stdout: message } = await getLastMessage(directoryPath);