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 je from '@spyglassmc/java-edition'
|
||||
import * as mcdoc from '@spyglassmc/mcdoc'
|
||||
@@ -6,11 +7,42 @@ import path from "path"
|
||||
import { glob } from "glob"
|
||||
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 {
|
||||
rootDir: string
|
||||
options: ActionOptions
|
||||
|
||||
constructor(rootDir: string, version: string) {
|
||||
constructor(rootDir: string, version: string, options: ActionOptions) {
|
||||
rootDir = path.resolve(rootDir)
|
||||
action.info(`rootDir = ${rootDir}`)
|
||||
action.info(`version = ${version}`)
|
||||
const fullRootDir = core.fileUtil.ensureEndingSlash("file://" + rootDir)
|
||||
const config = {
|
||||
env: {
|
||||
@@ -34,7 +66,7 @@ export class CustomService extends core.Service {
|
||||
}
|
||||
}
|
||||
super({
|
||||
logger: console,
|
||||
logger: new ActionLogger(),
|
||||
profilers: new core.ProfilerFactory(console, [
|
||||
'cache#load',
|
||||
'cache#save',
|
||||
@@ -53,11 +85,13 @@ export class CustomService extends core.Service {
|
||||
},
|
||||
})
|
||||
this.rootDir = rootDir
|
||||
this.options = options
|
||||
}
|
||||
|
||||
async shutdown() {
|
||||
console.log("Shutting down")
|
||||
action.startGroup("Shutdown")
|
||||
await this.project.close()
|
||||
action.endGroup()
|
||||
}
|
||||
|
||||
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)
|
||||
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)
|
||||
if (!docAndNode) {
|
||||
console.error(`File ${path} is not loaded`)
|
||||
return
|
||||
action.error(`File ${path} is not loaded`)
|
||||
return false
|
||||
}
|
||||
const { node } = docAndNode
|
||||
const errors = core.FileNode.getErrors(node)
|
||||
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() {
|
||||
console.log("Checking all files")
|
||||
async checkAllFiles(): Promise<boolean> {
|
||||
const jsonFiles = await this.listFilesByExtension("json")
|
||||
const funcFiles = await this.listFilesByExtension("mcfunction")
|
||||
console.log("Files to check")
|
||||
console.log(`- JSON: ${jsonFiles.length}`)
|
||||
console.log(`- Function: ${funcFiles.length}`)
|
||||
action.info(
|
||||
"Files to check:" + "\n" +
|
||||
`- JSON: ${jsonFiles.length}` + "\n" +
|
||||
`- Function: ${funcFiles.length}`
|
||||
)
|
||||
let success = true
|
||||
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) {
|
||||
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> {
|
||||
console.log(`Checking datapack in directory ${rootDir} for Minecraft version ${version}`)
|
||||
const service = new CustomService(rootDir, version)
|
||||
export async function checkDatapack(rootDir: string, version: string, reportAll: boolean, verbose: boolean): Promise<void> {
|
||||
action.startGroup("Initialization")
|
||||
const service = new CustomService(rootDir, version, {
|
||||
reportAllErrors: reportAll,
|
||||
verbose: verbose
|
||||
})
|
||||
|
||||
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()
|
||||
}
|
@@ -4,8 +4,10 @@ import { checkDatapack } from "./check_datapack.js"
|
||||
async function run(): Promise<void> {
|
||||
try {
|
||||
const rootDir = core.getInput("rootDir")
|
||||
let version = core.getInput("version")
|
||||
await checkDatapack(rootDir, version)
|
||||
const version = core.getInput("version")
|
||||
const reportAll = core.getBooleanInput("reportAllErrors")
|
||||
const verbose = core.getBooleanInput("verbose")
|
||||
await checkDatapack(rootDir, version, reportAll, verbose)
|
||||
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
|
Reference in New Issue
Block a user