Skip to content

Commit

Permalink
Add dotnet-format (#386)
Browse files Browse the repository at this point in the history
  • Loading branch information
AndrewBabbitt97 authored Feb 7, 2022
1 parent ba7834b commit a1f4ef1
Show file tree
Hide file tree
Showing 12 changed files with 1,048 additions and 1 deletion.
8 changes: 8 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,14 @@ jobs:
cd ../swiftlint/
mint bootstrap --link --overwrite=y
- name: Set up .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: "6.0.x"

- name: Install dotnet-format
run: dotnet tool install -g dotnet-format

# Tests

- name: Run tests
Expand Down
45 changes: 44 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ _**Note:** The behavior of actions like this one is currently limited in the con

## Supported tools

- **C#:**
- [dotnet-format](https://github.com/dotnet/format)
- **CSS:**
- [stylelint](https://stylelint.io)
- **Go:**
Expand All @@ -41,6 +43,8 @@ _**Note:** The behavior of actions like this one is currently limited in the con
- [swift-format](https://github.com/apple/swift-format) (official)
- [SwiftFormat](https://github.com/nicklockwood/SwiftFormat) (by Nick Lockwood)
- [SwiftLint](https://github.com/realm/SwiftLint)
- **VB.NET:**
- [dotnet-format](https://github.com/dotnet/format)

## Usage

Expand Down Expand Up @@ -251,11 +255,49 @@ jobs:
flake8: true
```

### C# and VB.NET example (dotnet_format)

```yml
name: Lint
on:
# Trigger the workflow on push or pull request,
# but only for the main branch
push:
branches:
- main
pull_request:
branches:
- main
jobs:
run-linters:
name: Run linters
runs-on: ubuntu-latest
steps:
- name: Check out Git repository
uses: actions/checkout@v2
- name: Set up .NET
uses: actions/setup-dotnet@v1
with:
dotnet-version: "6.0.x"
- name: Install dotnet-format
run: dotnet tool install -g dotnet-format
- name: Run linters
uses: wearerequired/lint-action@v1
with:
dotnet_format: true
```

## Configuration

### Linter-specific options

`[linter]` can be one of `black`, `erblint`, `eslint`, `flake8`, `gofmt`, `golint`, `mypy`, `oitnb`, `php_codesniffer`, `prettier`, `rubocop`, `stylelint`, `swift_format_official`, `swift_format_lockwood`, `swiftlint` and `xo`:
`[linter]` can be one of `black`, `dotnet_format`, `erblint`, `eslint`, `flake8`, `gofmt`, `golint`, `mypy`, `oitnb`, `php_codesniffer`, `prettier`, `rubocop`, `stylelint`, `swift_format_official`, `swift_format_lockwood`, `swiftlint` and `xo`:

- **`[linter]`:** Enables the linter in your repository. Default: `false`
- **`[linter]_args`**: Additional arguments to pass to the linter. Example: `eslint_args: "--max-warnings 0"` if ESLint checks should fail even if there are no errors and only warnings. Default: `""`
Expand Down Expand Up @@ -294,6 +336,7 @@ Some options are not be available for specific linters:
| Linter | auto-fixing | extensions |
| --------------------- | :---------: | :--------: |
| black | ✅ | ✅ |
| dotnet_format | ✅ | ✅ |
| erblint | ❌ | ❌ (erb) |
| eslint | ✅ | ✅ |
| flake8 | ❌ | ✅ |
Expand Down
20 changes: 20 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,26 @@ inputs:
required: false
default: ""

dotnet_format:
description: Enable or disable dotnet-format checks
required: false
default: "false"
dotnet_format_args:
description: Additional arguments to pass to the linter
required: false
default: ""
dotnet_format_dir:
description: Directory where the dotnet-format command should be run
required: false
dotnet_format_extensions:
description: Extensions of files to check with dotnet-format
required: false
default: "cs"
dotnet_format_command_prefix:
description: Shell command to prepend to the linter command
required: false
default: ""

runs:
using: node12
main: ./dist/index.js
Expand Down
85 changes: 85 additions & 0 deletions src/linters/dotnet-format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const { run } = require("../utils/action");
const commandExists = require("../utils/command-exists");
const { initLintResult } = require("../utils/lint-result");

const PARSE_REGEX = /^(.*)\(([0-9]+),([0-9]+)\): (warning|error) (.*) \[.*$/gm;

/** @typedef {import('../utils/lint-result').LintResult} LintResult */

/**
* https://github.com/dotnet/format
*/
class DotnetFormat {
static get name() {
return "dotnet_format";
}

/**
* Verifies that all required programs are installed. Throws an error if programs are missing
* @param {string} dir - Directory to run the linting program in
* @param {string} prefix - Prefix to the lint command
*/
static async verifySetup(dir, prefix = "") {
// Verify that dotnet is installed (required to execute dotnet format)
if (!(await commandExists("dotnet"))) {
throw new Error(".NET SDK is not installed");
}

// Verify that dotnet-format is installed
try {
run(`${prefix} dotnet format --version`, { dir });
} catch (err) {
throw new Error(`${this.name} is not installed`);
}
}

/**
* Runs the linting program and returns the command output
* @param {string} dir - Directory to run the linter in
* @param {string[]} extensions - File extensions which should be linted
* @param {string} args - Additional arguments to pass to the linter
* @param {boolean} fix - Whether the linter should attempt to fix code style issues automatically
* @param {string} prefix - Prefix to the lint command
* @returns {{status: number, stdout: string, stderr: string}} - Output of the lint command
*/
static lint(dir, extensions, args = "", fix = false, prefix = "") {
if (extensions.length !== 1 || extensions[0] !== "cs") {
throw new Error(`${this.name} error: File extensions are not configurable`);
}

const fixArg = fix ? "" : "--verify-no-changes";
return run(`${prefix} dotnet format ${fixArg} ${args}`, {
dir,
ignoreErrors: true,
});
}

/**
* Parses the output of the lint command. Determines the success of the lint process and the
* severity of the identified code style violations
* @param {string} dir - Directory in which the linter has been run
* @param {{status: number, stdout: string, stderr: string}} output - Output of the lint command
* @returns {LintResult} - Parsed lint result
*/
static parseOutput(dir, output) {
const lintResult = initLintResult();
lintResult.isSuccess = output.status === 0;

const matches = output.stderr.matchAll(PARSE_REGEX);
for (const match of matches) {
const [_line, pathFull, line, _column, level, message] = match;
const path = pathFull.substring(dir.length + 1);
const lineNr = parseInt(line, 10);
lintResult[level].push({
path,
firstLine: lineNr,
lastLine: lineNr,
message: `${message}`,
});
}

return lintResult;
}
}

module.exports = DotnetFormat;
2 changes: 2 additions & 0 deletions src/linters/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const Black = require("./black");
const DotnetFormat = require("./dotnet-format");
const Erblint = require("./erblint");
const ESLint = require("./eslint");
const Flake8 = require("./flake8");
Expand Down Expand Up @@ -30,6 +31,7 @@ const linters = {

// Formatters (should be run after linters)
black: Black,
dotnet_format: DotnetFormat,
gofmt: Gofmt,
oitnb: Oitnb,
prettier: Prettier,
Expand Down
2 changes: 2 additions & 0 deletions test/linters/linters.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const { copy, remove } = require("fs-extra");

const { normalizeDates, normalizePaths, createTmpDir } = require("../test-utils");
const blackParams = require("./params/black");
const dotnetFormatParams = require("./params/dotnet-format");
const erblintParams = require("./params/erblint");
const eslintParams = require("./params/eslint");
const eslintTypescriptParams = require("./params/eslint-typescript");
Expand All @@ -22,6 +23,7 @@ const xoParams = require("./params/xo");

const linterParams = [
blackParams,
dotnetFormatParams,
erblintParams,
eslintParams,
eslintTypescriptParams,
Expand Down
84 changes: 84 additions & 0 deletions test/linters/params/dotnet-format.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const { EOL } = require("os");
const { join } = require("path");

const DotnetFormat = require("../../../src/linters/dotnet-format");

const testName = "dotnet-format";
const linter = DotnetFormat;
const commandPrefix = "";
const extensions = ["cs"];

// Linting without auto-fixing
function getLintParams(dir) {
const stderrPart1 = `${join(
dir,
"file2.cs",
)}(20,31): error WHITESPACE: Fix whitespace formatting. Delete 1 characters. [${join(
dir,
"dotnet-format.csproj",
)}`;
const stderrPart2 = `${join(dir, "file2.cs")}(1,1): error IMPORTS: Fix imports ordering. [${join(
dir,
"dotnet-format.csproj",
)}`;
const stderrPart3 = `${join(
dir,
"file1.cs",
)}(1,1): warning IDE0073: A source file is missing a required header. [${join(
dir,
"dotnet-format.csproj",
)}`;
return {
// Expected output of the linting function
cmdOutput: {
status: 2,
stderrParts: [stderrPart1, stderrPart2, stderrPart3],
stderr: `${stderrPart1}${EOL}${stderrPart2}${EOL}${stderrPart3}`,
},
// Expected output of the parsing function
lintResult: {
isSuccess: false,
warning: [
{
path: "file1.cs",
firstLine: 1,
lastLine: 1,
message: `IDE0073: A source file is missing a required header.`,
},
],
error: [
{
path: "file2.cs",
firstLine: 20,
lastLine: 20,
message: `WHITESPACE: Fix whitespace formatting. Delete 1 characters.`,
},
{
path: "file2.cs",
firstLine: 1,
lastLine: 1,
message: `IMPORTS: Fix imports ordering.`,
},
],
},
};
}

// Linting with auto-fixing
function getFixParams(dir) {
return {
// Expected output of the linting function
cmdOutput: {
status: 0,
stderr: ``,
},
// Expected output of the parsing function
lintResult: {
isSuccess: true,
warning: [],
error: [],
},
};
}

module.exports = [testName, linter, commandPrefix, extensions, getLintParams, getFixParams];
Loading

0 comments on commit a1f4ef1

Please sign in to comment.