feat: use action logging and error reporting
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
|
import * as action from '@actions/core'
|
||||||
import * as core from '@spyglassmc/core'
|
import * as core from '@spyglassmc/core'
|
||||||
import * as je from '@spyglassmc/java-edition'
|
import * as je from '@spyglassmc/java-edition'
|
||||||
import * as mcdoc from '@spyglassmc/mcdoc'
|
import * as mcdoc from '@spyglassmc/mcdoc'
|
||||||
@@ -6,11 +7,42 @@ import path from "path"
|
|||||||
import { glob } from "glob"
|
import { glob } from "glob"
|
||||||
import fs from "fs"
|
import fs from "fs"
|
||||||
|
|
||||||
|
export interface ActionOptions {
|
||||||
|
/**
|
||||||
|
* If set to true, all errors are reported. If set to false, only the first error is reported
|
||||||
|
*/
|
||||||
|
reportAllErrors: boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If set to true, each error is described, indicating the exact issue. If set to false, only the number of errors in each file is reported
|
||||||
|
*/
|
||||||
|
verbose: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
class ActionLogger implements core.Logger {
|
||||||
|
error(data: any, ...args: any[]): void {
|
||||||
|
action.error(data)
|
||||||
|
}
|
||||||
|
info(data: any, ...args: any[]): void {
|
||||||
|
action.info(data)
|
||||||
|
}
|
||||||
|
log(data: any, ...args: any[]): void {
|
||||||
|
action.debug(data)
|
||||||
|
}
|
||||||
|
warn(data: any, ...args: any[]): void {
|
||||||
|
action.warning(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export class CustomService extends core.Service {
|
export class CustomService extends core.Service {
|
||||||
rootDir: string
|
rootDir: string
|
||||||
|
options: ActionOptions
|
||||||
|
|
||||||
constructor(rootDir: string, version: string) {
|
constructor(rootDir: string, version: string, options: ActionOptions) {
|
||||||
rootDir = path.resolve(rootDir)
|
rootDir = path.resolve(rootDir)
|
||||||
|
action.info(`rootDir = ${rootDir}`)
|
||||||
|
action.info(`version = ${version}`)
|
||||||
const fullRootDir = core.fileUtil.ensureEndingSlash("file://" + rootDir)
|
const fullRootDir = core.fileUtil.ensureEndingSlash("file://" + rootDir)
|
||||||
const config = {
|
const config = {
|
||||||
env: {
|
env: {
|
||||||
@@ -34,7 +66,7 @@ export class CustomService extends core.Service {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
super({
|
super({
|
||||||
logger: console,
|
logger: new ActionLogger(),
|
||||||
profilers: new core.ProfilerFactory(console, [
|
profilers: new core.ProfilerFactory(console, [
|
||||||
'cache#load',
|
'cache#load',
|
||||||
'cache#save',
|
'cache#save',
|
||||||
@@ -53,11 +85,13 @@ export class CustomService extends core.Service {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
this.rootDir = rootDir
|
this.rootDir = rootDir
|
||||||
|
this.options = options
|
||||||
}
|
}
|
||||||
|
|
||||||
async shutdown() {
|
async shutdown() {
|
||||||
console.log("Shutting down")
|
action.startGroup("Shutdown")
|
||||||
await this.project.close()
|
await this.project.close()
|
||||||
|
action.endGroup()
|
||||||
}
|
}
|
||||||
|
|
||||||
private listFilesByExtension(extension: string) {
|
private listFilesByExtension(extension: string) {
|
||||||
@@ -74,44 +108,97 @@ export class CustomService extends core.Service {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkFile(path: string, lang: string) {
|
private getLineAndColumn(pos: number, content: string) {
|
||||||
|
const before = content.slice(0, pos)
|
||||||
|
const line = before.split("\n").length
|
||||||
|
const col = pos - before.lastIndexOf("\n")
|
||||||
|
return { line, col }
|
||||||
|
}
|
||||||
|
|
||||||
|
private getErrorProperties(error: core.LanguageError, path: string, content: string): action.AnnotationProperties {
|
||||||
|
const {line: startLine, col: startColumn} = this.getLineAndColumn(error.range.start, content)
|
||||||
|
const {line: endLine, col: endColumn} = this.getLineAndColumn(error.range.end, content)
|
||||||
|
return {
|
||||||
|
file: path,
|
||||||
|
startLine, startColumn,
|
||||||
|
endLine, endColumn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async checkFile(path: string, lang: string): Promise<boolean> {
|
||||||
const url = this.makeFileUrl(path)
|
const url = this.makeFileUrl(path)
|
||||||
this.project.onDidOpen(url, lang, 0, this.getFileContent(path))
|
const content = this.getFileContent(path)
|
||||||
|
this.project.onDidOpen(url, lang, 0, content)
|
||||||
const docAndNode = this.project.getClientManaged(url)
|
const docAndNode = this.project.getClientManaged(url)
|
||||||
if (!docAndNode) {
|
if (!docAndNode) {
|
||||||
console.error(`File ${path} is not loaded`)
|
action.error(`File ${path} is not loaded`)
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
const { node } = docAndNode
|
const { node } = docAndNode
|
||||||
const errors = core.FileNode.getErrors(node)
|
const errors = core.FileNode.getErrors(node)
|
||||||
if (errors.length !== 0) {
|
if (errors.length !== 0) {
|
||||||
console.error(`${errors.length} error${errors.length > 1 ? "s" : ""} in ${path}`)
|
const msg = `${errors.length} error${errors.length > 1 ? "s" : ""} in ${path}`
|
||||||
|
|
||||||
|
if (this.options.verbose) {
|
||||||
|
action.startGroup(msg)
|
||||||
|
for (const err of errors) {
|
||||||
|
action.error(
|
||||||
|
err.message,
|
||||||
|
this.getErrorProperties(err, path, content)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
action.endGroup()
|
||||||
|
} else {
|
||||||
|
action.error(msg)
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
async checkAllFiles() {
|
async checkAllFiles(): Promise<boolean> {
|
||||||
console.log("Checking all files")
|
|
||||||
const jsonFiles = await this.listFilesByExtension("json")
|
const jsonFiles = await this.listFilesByExtension("json")
|
||||||
const funcFiles = await this.listFilesByExtension("mcfunction")
|
const funcFiles = await this.listFilesByExtension("mcfunction")
|
||||||
console.log("Files to check")
|
action.info(
|
||||||
console.log(`- JSON: ${jsonFiles.length}`)
|
"Files to check:" + "\n" +
|
||||||
console.log(`- Function: ${funcFiles.length}`)
|
`- JSON: ${jsonFiles.length}` + "\n" +
|
||||||
|
`- Function: ${funcFiles.length}`
|
||||||
|
)
|
||||||
|
let success = true
|
||||||
for (const jsonFile of jsonFiles) {
|
for (const jsonFile of jsonFiles) {
|
||||||
this.checkFile(jsonFile, "json")
|
if (!this.checkFile(jsonFile, "json")) {
|
||||||
|
success = false
|
||||||
|
if (!this.options.reportAllErrors) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (const funcFile of funcFiles) {
|
for (const funcFile of funcFiles) {
|
||||||
this.checkFile(funcFile, "mcfunction")
|
if (!this.checkFile(funcFile, "mcfunction")) {
|
||||||
|
success = false
|
||||||
|
if (!this.options.reportAllErrors) {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return success
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function checkDatapack(rootDir: string, version: string): Promise<void> {
|
export async function checkDatapack(rootDir: string, version: string, reportAll: boolean, verbose: boolean): Promise<void> {
|
||||||
console.log(`Checking datapack in directory ${rootDir} for Minecraft version ${version}`)
|
action.startGroup("Initialization")
|
||||||
const service = new CustomService(rootDir, version)
|
const service = new CustomService(rootDir, version, {
|
||||||
|
reportAllErrors: reportAll,
|
||||||
|
verbose: verbose
|
||||||
|
})
|
||||||
|
|
||||||
await service.project.ready()
|
await service.project.ready()
|
||||||
|
action.endGroup()
|
||||||
|
|
||||||
await service.checkAllFiles()
|
const success = await service.checkAllFiles()
|
||||||
|
if (!success) {
|
||||||
|
action.setFailed("Some files contain errors")
|
||||||
|
}
|
||||||
|
|
||||||
await service.shutdown()
|
await service.shutdown()
|
||||||
}
|
}
|
@@ -4,8 +4,10 @@ import { checkDatapack } from "./check_datapack.js"
|
|||||||
async function run(): Promise<void> {
|
async function run(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
const rootDir = core.getInput("rootDir")
|
const rootDir = core.getInput("rootDir")
|
||||||
let version = core.getInput("version")
|
const version = core.getInput("version")
|
||||||
await checkDatapack(rootDir, version)
|
const reportAll = core.getBooleanInput("reportAllErrors")
|
||||||
|
const verbose = core.getBooleanInput("verbose")
|
||||||
|
await checkDatapack(rootDir, version, reportAll, verbose)
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof Error) {
|
if (error instanceof Error) {
|
||||||
|
Reference in New Issue
Block a user