-
Notifications
You must be signed in to change notification settings - Fork 131
Shellcheck integration #342
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
71c6a4a
Add support for shellcheck
shabbyrobe 82cff73
Remove unnecessary import
shabbyrobe 866dc7a
Add some comments
shabbyrobe 19c4077
Merge diagnostics from treesitter and shellcheck
shabbyrobe 6749d2f
Lint
shabbyrobe 4d77858
Testing for shellcheck integration
shabbyrobe 7093b2f
Fix linter use of stdin after unsuccessful spawn
shabbyrobe efe1676
Fix diagnostics not clearing on successful lint
shabbyrobe b76dc57
Improve workflow task name
shabbyrobe c4566b6
Remove old FIXME
shabbyrobe 8c84492
Error is an acceptable default severity
shabbyrobe 8d8cc16
Use record for severity mapping
shabbyrobe f85f18f
Remove unnecessary undefined
shabbyrobe 64c5df4
Force options to be passed to linter
shabbyrobe bdee9f8
Remove duplicate executablePath line
shabbyrobe cadba02
Fix typo
shabbyrobe f576bf5
Add SHELLCHECK_PATH to vscode extension
shabbyrobe 48648f9
Simplify test mocking
shabbyrobe 2945070
Re-run linter
shabbyrobe a9697fe
Add console error assertion
shabbyrobe 0f607ba
Fix child_process event order for different node versions
shabbyrobe File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import * as path from 'path' | ||
import * as LSP from 'vscode-languageserver' | ||
|
||
import { FIXTURE_DOCUMENT, FIXTURE_FOLDER } from '../../../testing/fixtures' | ||
import Linter, { assertShellcheckResult } from '../linter' | ||
|
||
function textToDoc(txt: string) { | ||
return LSP.TextDocument.create('foo', 'bar', 0, txt) | ||
} | ||
|
||
describe('linter', () => { | ||
it('should set canLint to false if executable empty', () => { | ||
expect(new Linter({ executablePath: null }).canLint).toBe(false) | ||
}) | ||
|
||
it('should set canLint to true if executable not empty', () => { | ||
expect(new Linter({ executablePath: null }).canLint).toBe(false) | ||
}) | ||
|
||
it('should set canLint to false when linting fails', async () => { | ||
jest.spyOn(console, 'error').mockImplementation() | ||
const executablePath = '77b4d3f6-c87a-11ec-9b62-a3c90f66d29f' | ||
const linter = new Linter({ | ||
executablePath, | ||
}) | ||
expect(await linter.lint(textToDoc(''), [])).toEqual([]) | ||
expect(linter.canLint).toBe(false) | ||
expect(console.error).toBeCalledWith( | ||
expect.stringContaining('shellcheck not available at path'), | ||
) | ||
}) | ||
|
||
it('should lint when shellcheck present', async () => { | ||
// prettier-ignore | ||
const shell = [ | ||
'#!/bin/bash', | ||
'echo $foo', | ||
].join('\n') | ||
|
||
const expected: LSP.Diagnostic[] = [ | ||
{ | ||
message: 'SC2154: foo is referenced but not assigned.', | ||
severity: 2, | ||
code: 2154, | ||
source: 'shellcheck', | ||
range: { start: { line: 1, character: 5 }, end: { line: 1, character: 9 } }, | ||
}, | ||
{ | ||
message: 'SC2086: Double quote to prevent globbing and word splitting.', | ||
severity: 3, | ||
code: 2086, | ||
source: 'shellcheck', | ||
range: { start: { line: 1, character: 5 }, end: { line: 1, character: 9 } }, | ||
}, | ||
] | ||
|
||
const linter = new Linter({ executablePath: 'shellcheck' }) | ||
const result = await linter.lint(textToDoc(shell), []) | ||
expect(result).toEqual(expected) | ||
}) | ||
|
||
it('should correctly follow sources with correct cwd', async () => { | ||
const linter = new Linter({ executablePath: 'shellcheck', cwd: FIXTURE_FOLDER }) | ||
const result = await linter.lint(FIXTURE_DOCUMENT.SHELLCHECK_SOURCE, []) | ||
expect(result).toEqual([]) | ||
}) | ||
|
||
it('should fail to follow sources with incorrect cwd', async () => { | ||
const linter = new Linter({ | ||
executablePath: 'shellcheck', | ||
cwd: path.resolve(path.join(FIXTURE_FOLDER, '../')), | ||
}) | ||
// prettier-ignore | ||
const expected = [ | ||
{ message: 'SC1091: Not following: shellcheck/sourced.sh: openBinaryFile: does not exist (No such file or directory)', severity: 3, code: 1091, source: 'shellcheck', range: { start: { line: 3, character: 7 }, end: { line: 3, character: 19 } }, }, | ||
{ message: 'SC2154: foo is referenced but not assigned.', severity: 2, code: 2154, source: 'shellcheck', range: { start: { line: 5, character: 6 }, end: { line: 5, character: 10 } }, }, | ||
] | ||
const result = await linter.lint(FIXTURE_DOCUMENT.SHELLCHECK_SOURCE, []) | ||
expect(result).toEqual(expected) | ||
}) | ||
|
||
it('should follow sources with incorrect cwd if correct path is passed as a workspace path', async () => { | ||
const linter = new Linter({ | ||
executablePath: 'shellcheck', | ||
cwd: path.resolve(path.join(FIXTURE_FOLDER, '../')), | ||
}) | ||
const result = await linter.lint(FIXTURE_DOCUMENT.SHELLCHECK_SOURCE, [ | ||
{ uri: `file://${path.resolve(FIXTURE_FOLDER)}`, name: 'fixtures' }, | ||
]) | ||
expect(result).toEqual([]) | ||
}) | ||
}) | ||
|
||
describe('shellcheck', () => { | ||
it('asserts one valid shellcheck JSON comment', async () => { | ||
// prettier-ignore | ||
const shellcheckJSON = { | ||
comments: [ | ||
{ file: 'testing/fixtures/comment-doc-on-hover.sh', line: 43, endLine: 43, column: 1, endColumn: 7, level: 'warning', code: 2034, message: 'bork bork', fix: null, }, | ||
], | ||
} | ||
assertShellcheckResult(shellcheckJSON) | ||
}) | ||
|
||
it('asserts two valid shellcheck JSON comment', async () => { | ||
// prettier-ignore | ||
const shellcheckJSON = { | ||
comments: [ | ||
{ file: 'testing/fixtures/comment-doc-on-hover.sh', line: 43, endLine: 43, column: 1, endColumn: 7, level: 'warning', code: 2034, message: 'bork bork', fix: null, }, | ||
{ file: 'testing/fixtures/comment-doc-on-hover.sh', line: 45, endLine: 45, column: 2, endColumn: 8, level: 'warning', code: 2035, message: 'bork bork', fix: null, }, | ||
], | ||
} | ||
assertShellcheckResult(shellcheckJSON) | ||
}) | ||
|
||
it('fails shellcheck JSON with null comments', async () => { | ||
const shellcheckJSON = { comments: null } | ||
expect(() => assertShellcheckResult(shellcheckJSON)).toThrow() | ||
}) | ||
|
||
it('fails shellcheck JSON with string commment', async () => { | ||
const shellcheckJSON = { comments: ['foo'] } | ||
expect(() => assertShellcheckResult(shellcheckJSON)).toThrow() | ||
}) | ||
|
||
it('fails shellcheck JSON with invalid commment', async () => { | ||
const make = (tweaks = {}) => ({ | ||
comments: [ | ||
{ | ||
file: 'testing/fixtures/comment-doc-on-hover.sh', | ||
line: 43, | ||
endLine: 43, | ||
column: 1, | ||
endColumn: 7, | ||
level: 'warning', | ||
code: 2034, | ||
message: 'bork bork', | ||
fix: null, | ||
...tweaks, | ||
}, | ||
], | ||
}) | ||
assertShellcheckResult(make()) // Defaults should work | ||
|
||
expect(() => assertShellcheckResult(make({ file: 9 }))).toThrow() | ||
expect(() => assertShellcheckResult(make({ line: '9' }))).toThrow() | ||
expect(() => assertShellcheckResult(make({ endLine: '9' }))).toThrow() | ||
expect(() => assertShellcheckResult(make({ column: '9' }))).toThrow() | ||
expect(() => assertShellcheckResult(make({ endColumn: '9' }))).toThrow() | ||
expect(() => assertShellcheckResult(make({ level: 9 }))).toThrow() | ||
expect(() => assertShellcheckResult(make({ code: '9' }))).toThrow() | ||
expect(() => assertShellcheckResult(make({ message: 9 }))).toThrow() | ||
}) | ||
}) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.