diff --git a/.automation/clean-code-base-for-tests.sh b/.automation/clean-code-base-for-tests.sh index f5d15c5a..eed6bc0f 100755 --- a/.automation/clean-code-base-for-tests.sh +++ b/.automation/clean-code-base-for-tests.sh @@ -41,7 +41,7 @@ CleanTestFiles() { ################## mapfile -t FIND_CMD < <( cd "${GITHUB_WORKSPACE}" || exit 1 - find "${GITHUB_WORKSPACE}" -type f -name "*_bad_*" 2>&1 + find "${GITHUB_WORKSPACE}" -type f -name "*_bad_*" -o -path "*javascript_prettier*" -name "*javascript_good*" 2>&1 ) ####################### diff --git a/.automation/test/javascript_prettier/README.md b/.automation/test/javascript_prettier/README.md new file mode 100644 index 00000000..6917a7e1 --- /dev/null +++ b/.automation/test/javascript_prettier/README.md @@ -0,0 +1,19 @@ +# Javascript Test Cases + +This folder holds the test cases for **Javascript**. + +## Additional Docs + +No Additional information is needed for this test case. + +## Good Test Cases + +The test cases denoted: `LANGUAGE_good_FILE.EXTENSION` are all valid, and should pass successfully when linted. + +- **Note:** They are linted utilizing the default linter rules. + +## Bad Test Cases + +The test cases denoted: `LANGUAGE_bad_FILE.EXTENSION` are **NOT** valid, and should trigger errors when linted. + +- **Note:** They are linted utilizing the default linter rules. diff --git a/.automation/test/javascript_prettier/javascript_bad_1.js b/.automation/test/javascript_prettier/javascript_bad_1.js new file mode 100644 index 00000000..98e5ee29 --- /dev/null +++ b/.automation/test/javascript_prettier/javascript_bad_1.js @@ -0,0 +1,225 @@ +var http = require('http') +var createHandler = require( 'github-webhook-handler') + +var handler = createHandler( { path : /webhook, secret : (process.env.SECRET) }) + +var userArray = [ 'user1' ] +here is some garbage = that + +var teamDescription = Team of Robots +var teamPrivacy = 'closed' // closed (visible) / secret (hidden) are options here + +var teamName = process.env.GHES_TEAM_NAME +var teamAccess = 'pull' // pull,push,admin options here +var teamId = '' + +var orgRepos = [] + +// var creator = "" + +var foo = someFunction(); +var bar = a + 1; + +http.createServer(function (req, res) { + handler(req, res, function (err) { + console.log(err) + res.statusCode = 404 + res.end('no such location') + }) +}).listen(3000) + +handler.on('error', function (err) { + console.await.error('Error:', err.message) +}) + +handler.on('repository', function (event) { + if (event.payload.action === 'created') { + const repo = event.payload.repository.full_name + console.log(repo) + const org = event.payload.repository.owner.login + getTeamID(org) + setTimeout(checkTeamIDVariable, 1000) + } +}) + +handler.on('team', function (event) { +// TODO user events such as being removed from team or org + if (event.payload.action === 'deleted') { + // const name = event.payload.team.name + const org = event.payload.organization.login + getRepositories(org) + setTimeout(checkReposVariable, 5000) + } else if (event.payload.action === 'removed_from_repository') { + const org = event.payload.organization.login + getTeamID(org) + // const repo = event.payload.repository.full_name + setTimeout(checkTeamIDVariable, 1000) + } +}) + +function getTeamID (org) { + const https = require('https') + + const options = { + hostname: (process.env.GHE_HOST), + port: 443 + path: '/api/v3/orgs/' + org + '/teams', + method: 'GET', + headers: { + Authorization: 'token ' + (process.env.GHE_TOKEN), + 'Content-Type': 'application/json' + } + } + let body = [] + const req = https.request(options, (res) => { + res.on('data', (chunk) => { + body.push(chunk) + }).on('end', () => { + body = JSON.parse(Buffer.concat(body)) + body.forEach(item => { + if (item.name === teamName) { + teamId = item.id + } + }) + }) + }) + + req.on('error, (error) => { + console.error(error) + }) + + req.end() +} + +function checkTeamIDVariable (repo) { + if (typeof teamId != 'undefined') { + addTeamToRepo(repo, teamId) + } +} + +function checkReposVariable (org) { + if (typeof orgRepos !== 'undefined') { + // for(var repo of orgRepos) { + // addTeamToRepo(repo, teamId) + // } + reCreateTeam(org) + } +} + +function addTeamToRepo (repo, teamId) { + const https = require('https') + const data = JSON.stringify({ + permission: teamAccess + }) + + const options = { + hostname: (process.env.GHE_HOST), + port: 443, + path: '/api/v3/teams/' + teamId + '/repos/' + repo, + method: 'PUT', + headers: { + Authorization: 'token ' + (process.env.GHE_TOKEN), + 'Content-Type': 'application/json', + 'Content-Length': data.length + } + } + let body = [] + + const req = https.request(options, (res) => { + res.on('data', (chunk) => { + + body.push(chunk) + + }).on('end', () => { + + body = Buffer.concat(body).toString() + console.log(res.statusCode) + console.log('added team to ' + repo) + }) + }) + + req.on('error', (error) => { + console.error(error) + }) + + req.write(data) + req.end() +} + +function reCreateTeam (org) { + const https = require('https') + const data = JSON.stringify({ + name: teamName, + description: teamDescription, + privacy: teamPrivacy + maintainers: userArray, + repo_names: orgRepos + }) + + const options = { + hostname: (process.env.GHE_HOST), + port: 443 + path: '/api/v3/orgs/' + org + '/teams', + method: 'POST', + headers: { + Authorization: 'token ' + (process.env.GHE_TOKEN), + 'Content-Type': 'application/json', + 'Content-Length': data.length + } + } + // const body = [] + const req = https.request(options, (res) => { + if (res.statusCode !== 201) { + console.log('Status code: ' + res.statusCode) + console.log('Added ' + teamName + ' to ' + org + ' Failed') + res.on('data', function (chunk) { + console.log('BODY: ' + chunk) + }) + } else { + console.log('Added ' + teamName ' to ' + org) + } + }) + + req.on('error', (error) => { + console.error(error) + }) + + req.write(data) + req.end() +} + +function getRepositories (org) { + orgRepos = [] + + const https = require('https') + + const options = { + hostname: (process.env.GHE_HOST), + port: '443', + path: '/api/v3/orgs/' + org + "/repos", + method: 'GET', + headers: { + Authorization: 'token ' + (process.env.GHE_TOKEN), + 'Content-Type': 'application/json' + } + } + let body = [] + const req = https.request(options, (res) => { + res.on('data', (chunk) => { + body.push(chunk) + + }).on('end', () => { + body = JSON.parse(Buffer.concat(body)) + body.forEach(item => { + orgRepos.push(item.full_name) + + console.log(item.full_name) + }) + }) + }) + + req.on('error', (error) => { + console.error(error) + }) + req.end() +} diff --git a/.automation/test/javascript_prettier/javascript_good_1.js b/.automation/test/javascript_prettier/javascript_good_1.js new file mode 100644 index 00000000..309d71be --- /dev/null +++ b/.automation/test/javascript_prettier/javascript_good_1.js @@ -0,0 +1,223 @@ +var http = require("http"); +var createHandler = require("github-webhook-handler"); +var handler = createHandler({ path: "/webhook", secret: process.env.SECRET }); + +var userArray = ["user1"]; + +var teamDescription = "Team of Robots"; +var teamPrivacy = "closed"; // closed (visible) / secret (hidden) are options here + +var teamName = process.env.GHES_TEAM_NAME; +var teamAccess = "pull"; // pull,push,admin options here +var teamId = ""; + +var orgRepos = []; + +// var creator = "" + +http + .createServer(function (req, res) { + handler(req, res, function (err) { + console.log(err); + res.statusCode = 404; + res.end("no such location"); + }); + }) + .listen(3000); + +handler.on("error", function (err) { + console.error("Error:", err.message); +}); + +handler.on("repository", function (event) { + if (event.payload.action === "created") { + const repo = event.payload.repository.full_name; + console.log(repo); + const org = event.payload.repository.owner.login; + getTeamID(org); + setTimeout(checkTeamIDVariable, 1000); + } +}); + +handler.on("team", function (event) { + // TODO user events such as being removed from team or org + if (event.payload.action === "deleted") { + // const name = event.payload.team.name + const org = event.payload.organization.login; + getRepositories(org); + setTimeout(checkReposVariable, 5000); + } else if (event.payload.action === "removed_from_repository") { + const org = event.payload.organization.login; + getTeamID(org); + // const repo = event.payload.repository.full_name + setTimeout(checkTeamIDVariable, 1000); + } +}); + +function getTeamID(org) { + const https = require("https"); + + const options = { + hostname: process.env.GHE_HOST, + port: 443, + path: "/api/v3/orgs/" + org + "/teams", + method: "GET", + headers: { + Authorization: "token " + process.env.GHE_TOKEN, + "Content-Type": "application/json", + }, + }; + let body = []; + const req = https.request(options, (res) => { + res + .on("data", (chunk) => { + body.push(chunk); + }) + .on("end", () => { + body = JSON.parse(Buffer.concat(body)); + body.forEach((item) => { + if (item.name === teamName) { + teamId = item.id; + } + }); + }); + }); + + req.on("error", (error) => { + console.error(error); + }); + + req.end(); +} + +function checkTeamIDVariable(repo) { + if (typeof teamId !== "undefined") { + addTeamToRepo(repo, teamId); + } +} + +function checkReposVariable(org) { + if (typeof orgRepos !== "undefined") { + // for(var repo of orgRepos) { + // addTeamToRepo(repo, teamId) + // } + reCreateTeam(org); + } +} + +function addTeamToRepo(repo, teamId) { + const https = require("https"); + const data = JSON.stringify({ + permission: teamAccess, + }); + + const options = { + hostname: process.env.GHE_HOST, + port: 443, + path: "/api/v3/teams/" + teamId + "/repos/" + repo, + method: "PUT", + headers: { + Authorization: "token " + process.env.GHE_TOKEN, + "Content-Type": "application/json", + "Content-Length": data.length, + }, + }; + let body = []; + const req = https.request(options, (res) => { + res + .on("data", (chunk) => { + body.push(chunk); + }) + .on("end", () => { + body = Buffer.concat(body).toString(); + console.log(res.statusCode); + console.log("added team to " + repo); + }); + }); + + req.on("error", (error) => { + console.error(error); + }); + + req.write(data); + req.end(); +} + +function reCreateTeam(org) { + const https = require("https"); + const data = JSON.stringify({ + name: teamName, + description: teamDescription, + privacy: teamPrivacy, + maintainers: userArray, + repo_names: orgRepos, + }); + + const options = { + hostname: process.env.GHE_HOST, + port: 443, + path: "/api/v3/orgs/" + org + "/teams", + method: "POST", + headers: { + Authorization: "token " + process.env.GHE_TOKEN, + "Content-Type": "application/json", + "Content-Length": data.length, + }, + }; + // const body = [] + const req = https.request(options, (res) => { + if (res.statusCode !== 201) { + console.log("Status code: " + res.statusCode); + console.log("Added " + teamName + " to " + org + " Failed"); + res.on("data", function (chunk) { + console.log("BODY: " + chunk); + }); + } else { + console.log("Added " + teamName + " to " + org); + } + }); + + req.on("error", (error) => { + console.error(error); + }); + + req.write(data); + req.end(); +} + +function getRepositories(org) { + orgRepos = []; + + const https = require("https"); + + const options = { + hostname: process.env.GHE_HOST, + port: 443, + path: "/api/v3/orgs/" + org + "/repos", + method: "GET", + headers: { + Authorization: "token " + process.env.GHE_TOKEN, + "Content-Type": "application/json", + }, + }; + let body = []; + const req = https.request(options, (res) => { + res + .on("data", (chunk) => { + body.push(chunk); + }) + .on("end", () => { + body = JSON.parse(Buffer.concat(body)); + body.forEach((item) => { + orgRepos.push(item.full_name); + console.log(item.full_name); + }); + }); + }); + + req.on("error", (error) => { + console.error(error); + }); + + req.end(); +} diff --git a/.automation/test/javascript_prettier/reports/expected-JAVASCRIPT_STANDARD.tap b/.automation/test/javascript_prettier/reports/expected-JAVASCRIPT_STANDARD.tap new file mode 100644 index 00000000..a521a0fa --- /dev/null +++ b/.automation/test/javascript_prettier/reports/expected-JAVASCRIPT_STANDARD.tap @@ -0,0 +1,7 @@ +TAP version 13 +1..2 +not ok 1 - javascript_bad_1.js + --- + message: standard Use JavaScript Standard Style (https //standardjs.com)\n /tmp/lint/.automation/test/javascript_standard/javascript_bad_1.js Parsing error Unterminated regular expression\n + ... +ok 2 - javascript_good_1.js diff --git a/README.md b/README.md index cfce3fc7..a21cf5d3 100644 --- a/README.md +++ b/README.md @@ -217,6 +217,7 @@ But if you wish to select or exclude specific linters, we give you full control | **FILTER_REGEX_EXCLUDE** | `none` | Regular expression defining which files will be excluded from linting (ex: `.*src/test.*`) | | **FILTER_REGEX_INCLUDE** | `all` | Regular expression defining which files will be processed by linters (ex: `.*src/.*`) | | **JAVASCRIPT_ES_CONFIG_FILE** | `.eslintrc.yml` | Filename for [eslint configuration](https://eslint.org/docs/user-guide/configuring#configuration-file-formats) (ex: `.eslintrc.yml`, `.eslintrc.json`) | +| **JAVASCRIPT_DEFAULT_STYLE** | `standard` | Flag to set the default style of javascript. Available options: **standard**/**prettier** | | **LINTER_RULES_PATH** | `.github/linters` | Directory for all linter configuration rules. | | **LOG_FILE** | `super-linter.log` | The file name for outputting logs. All output is sent to the log file regardless of `LOG_LEVEL`. | | **LOG_LEVEL** | `VERBOSE` | How much output the script will generate to the console. One of `ERROR`, `WARN`, `NOTICE`, `VERBOSE`, `DEBUG` or `TRACE`. | diff --git a/lib/functions/buildFileList.sh b/lib/functions/buildFileList.sh index 064b6191..f7845cc3 100755 --- a/lib/functions/buildFileList.sh +++ b/lib/functions/buildFileList.sh @@ -336,10 +336,7 @@ function BuildFileList() { ################################ FILE_ARRAY_JAVASCRIPT_ES+=("${FILE}") FILE_ARRAY_JAVASCRIPT_STANDARD+=("${FILE}") - - ##################### - # Get the JSX files # - ##################### + FILE_ARRAY_JAVASCRIPT_PRETTIER+=("${FILE}") ###################### # Get the JSON files # @@ -368,9 +365,9 @@ function BuildFileList() { ################################ FILE_ARRAY_OPENAPI+=("${FILE}") fi - ############################ + ######################## # Check if file is ARM # - ############################ + ######################## if DetectARMFile "${FILE}"; then ################################ # Append the file to the array # @@ -396,6 +393,9 @@ function BuildFileList() { FILE_ARRAY_STATES+=("${FILE}") fi + ##################### + # Get the JSX files # + ##################### elif [ "${FILE_TYPE}" == "jsx" ]; then ################################ # Append the file to the array # diff --git a/lib/linter.sh b/lib/linter.sh index d12dafa1..1c8f83bc 100755 --- a/lib/linter.sh +++ b/lib/linter.sh @@ -103,6 +103,10 @@ JAVA_FILE_NAME="sun_checks.xml" # shellcheck disable=SC2034 # Variable is referenced indirectly JAVASCRIPT_ES_FILE_NAME="${JAVASCRIPT_ES_CONFIG_FILE:-.eslintrc.yml}" # shellcheck disable=SC2034 # Variable is referenced indirectly +JAVASCRIPT_DEFAULT_STYLE="${JAVASCRIPT_DEFAULT_STYLE:-standard}" +JAVASCRIPT_STYLE_NAME='' # Variable for the style +JAVASCRIPT_STYLE='' # Variable for the style +# shellcheck disable=SC2034 # Variable is referenced indirectly JAVASCRIPT_STANDARD_FILE_NAME="${JAVASCRIPT_ES_CONFIG_FILE:-.eslintrc.yml}" # shellcheck disable=SC2034 # Variable is referenced indirectly JSX_FILE_NAME="${JAVASCRIPT_ES_CONFIG_FILE:-.eslintrc.yml}" @@ -151,12 +155,30 @@ TYPESCRIPT_STANDARD_FILE_NAME="${TYPESCRIPT_ES_CONFIG_FILE:-.eslintrc.yml}" # shellcheck disable=SC2034 # Variable is referenced indirectly YAML_FILE_NAME="${YAML_CONFIG_FILE:-.yaml-lint.yml}" +################################################# +# Parse if we are using JS standard or prettier # +################################################# +# Remove spaces +JAVASCRIPT_DEFAULT_STYLE=$(echo "${JAVASCRIPT_DEFAULT_STYLE}" | tr -d ' ') +# lowercase +JAVASCRIPT_DEFAULT_STYLE=$(echo "${JAVASCRIPT_DEFAULT_STYLE}" | tr '[:upper:]' '[:lower:]') +# Check and set +if [ "${JAVASCRIPT_DEFAULT_STYLE}" == "prettier" ]; then + # Set to prettier + JAVASCRIPT_STYLE_NAME='JAVASCRIPT_PRETTIER' + JAVASCRIPT_STYLE='prettier' +else + # Default to standard + JAVASCRIPT_STYLE_NAME='JAVASCRIPT_STANDARD' + JAVASCRIPT_STYLE='standard' +fi + ################## # Language array # ################## LANGUAGE_ARRAY=('ANSIBLE' 'ARM' 'BASH' 'BASH_EXEC' 'CLOUDFORMATION' 'CLOJURE' 'COFFEESCRIPT' 'CSHARP' 'CSS' 'DART' 'DOCKERFILE' 'DOCKERFILE_HADOLINT' 'EDITORCONFIG' 'ENV' 'GHERKIN' 'GO' 'GROOVY' 'HTML' - 'JAVA' 'JAVASCRIPT_ES' 'JAVASCRIPT_STANDARD' 'JSON' 'JSX' 'KUBERNETES_KUBEVAL' 'KOTLIN' 'LATEX' 'LUA' 'MARKDOWN' + 'JAVA' 'JAVASCRIPT_ES' "${JAVASCRIPT_STYLE_NAME}" 'JSON' 'JSX' 'KUBERNETES_KUBEVAL' 'KOTLIN' 'LATEX' 'LUA' 'MARKDOWN' 'OPENAPI' 'PERL' 'PHP_BUILTIN' 'PHP_PHPCS' 'PHP_PHPSTAN' 'PHP_PSALM' 'POWERSHELL' 'PROTOBUF' 'PYTHON_BLACK' 'PYTHON_PYLINT' 'PYTHON_FLAKE8' 'PYTHON_ISORT' 'R' 'RAKU' 'RUBY' 'SHELL_SHFMT' 'SNAKEMAKE_LINT' 'SNAKEMAKE_SNAKEFMT' 'STATES' 'SQL' 'TEKTON' 'TERRAFORM' 'TERRAFORM_TERRASCAN' 'TERRAGRUNT' 'TSX' 'TYPESCRIPT_ES' 'TYPESCRIPT_STANDARD' 'XML' 'YAML') @@ -185,7 +207,7 @@ LINTER_NAMES_ARRAY['GROOVY']="npm-groovy-lint" LINTER_NAMES_ARRAY['HTML']="htmlhint" LINTER_NAMES_ARRAY['JAVA']="checkstyle" LINTER_NAMES_ARRAY['JAVASCRIPT_ES']="eslint" -LINTER_NAMES_ARRAY['JAVASCRIPT_STANDARD']="standard" +LINTER_NAMES_ARRAY["${JAVASCRIPT_STYLE_NAME}"]="${JAVASCRIPT_STYLE}" LINTER_NAMES_ARRAY['JSON']="jsonlint" LINTER_NAMES_ARRAY['JSX']="eslint" LINTER_NAMES_ARRAY['KOTLIN']="ktlint" @@ -746,6 +768,7 @@ LINTER_COMMANDS_ARRAY['HTML']="htmlhint --config ${HTML_LINTER_RULES}" LINTER_COMMANDS_ARRAY['JAVA']="java -jar /usr/bin/checkstyle -c ${JAVA_LINTER_RULES}" LINTER_COMMANDS_ARRAY['JAVASCRIPT_ES']="eslint --no-eslintrc -c ${JAVASCRIPT_ES_LINTER_RULES}" LINTER_COMMANDS_ARRAY['JAVASCRIPT_STANDARD']="standard ${JAVASCRIPT_STANDARD_LINTER_RULES}" +LINTER_COMMANDS_ARRAY['JAVASCRIPT_PRETTIER']="prettier --check" LINTER_COMMANDS_ARRAY['JSON']="jsonlint" LINTER_COMMANDS_ARRAY['JSX']="eslint --no-eslintrc -c ${JSX_LINTER_RULES}" LINTER_COMMANDS_ARRAY['KOTLIN']="ktlint"