Skip to content

Commit 4aaa9f3

Browse files
committed
Add/tweak CMake, GitHub, and lefthook lint config
1 parent 8ebec85 commit 4aaa9f3

5 files changed

Lines changed: 150 additions & 12 deletions

File tree

config/common.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,41 @@ export const octokit = new Octokit({ auth: process.env.GITHUB_AUTH_TOKEN })
2323

2424
export const skipHyperupcallFunding = ['ecc-computing-club']
2525

26+
export async function* fileMustHaveName(
27+
mapping: Record<string, string[]>,
28+
): AsyncGenerator<Issue> {
29+
for (let goodFile in mapping) {
30+
const badFiles = mapping[goodFile]
31+
if (goodFile.slice(0, 2) === './') {
32+
goodFile = goodFile.slice(2)
33+
}
34+
35+
for (let badFile of badFiles) {
36+
if (badFile.slice(0, 2) === './') {
37+
badFile = badFile.slice(2)
38+
}
39+
40+
if (await fileExists(badFile)) {
41+
const correctFileExists = await fileExists(goodFile)
42+
if (correctFileExists) {
43+
yield {
44+
message: dedent`
45+
-> Expected file "${badFile}" to not exist because "${goodFile}" already exists
46+
-> But, found both files exist`,
47+
}
48+
} else {
49+
yield {
50+
message: dedent`
51+
-> Expected file to be named "${goodFile}"
52+
-> But, found file named "${badFile}"`,
53+
fix: () => fs.rename(badFile, goodFile),
54+
}
55+
}
56+
}
57+
}
58+
}
59+
}
60+
2661
export async function* filesMustHaveContent(
2762
mapping: Record<string, null | string>,
2863
): AsyncGenerator<Issue> {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import * as fs from 'node:fs/promises'
2+
import path from 'node:path'
3+
import { fileExists } from '#common'
4+
import { globby } from 'globby'
5+
import type { Issues } from '#types'
6+
7+
export const issues: Issues = async function* issues() {
8+
const workflowsDir = '.github/workflows'
9+
10+
if (!(await fileExists(workflowsDir))) {
11+
return
12+
}
13+
14+
const yamlFiles = await globby(['*.yml'], { cwd: workflowsDir })
15+
16+
if (yamlFiles.length > 0) {
17+
yield {
18+
message: [
19+
`Expected GitHub workflow files to use ".yaml" extension`,
20+
`But, found ${yamlFiles} file with ".yml" extension`,
21+
],
22+
fix: () =>
23+
Promise.all(yamlFiles.map((file) =>
24+
fs.rename(
25+
path.join(workflowsDir, file),
26+
path.join(workflowsDir, file).replace(/\.yml$/, '.yaml'),
27+
)
28+
)),
29+
}
30+
}
31+
}

config/lint-rules/400-ecosystem/_/lefthook.ts

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,39 @@
11
import type { Issues } from '#types'
2-
import { fileExists, filesMustHaveContent } from '#common'
2+
import { fileExists, fileMustHaveName, filesMustHaveContent } from '#common'
33
import * as yaml from 'std/yaml'
44
import { execa } from 'execa'
55

66
export const issues: Issues = async function* issues() {
77
// Check that there is only one configuration file.
88
{
99
// https://lefthook.dev/configuration/index.html#config-file-name
10+
yield* fileMustHaveName({
11+
'.lefthook.yaml': [
12+
'.lefthook.yml',
13+
'lefthook.yaml',
14+
'lefthook.yml',
15+
],
16+
})
17+
1018
yield* filesMustHaveContent({
11-
'lefthook.yml': null,
12-
'.lefthook.yml': null,
13-
'lefthook.yaml': null,
14-
'.lefthook.yaml': `assert_lefthook_installed: true`,
15-
'lefthook.toml': null,
1619
'.lefthook.toml': null,
17-
'lefthook.json': null,
1820
'.lefthook.json': null,
21+
'lefthook.toml': null,
22+
'lefthook.json': null,
1923
})
24+
25+
if (!await fileExists('.lefthook.yaml')) {
26+
yield {
27+
message: [
28+
`Expected to find a ".lefthook.yaml" file`,
29+
],
30+
fix: () =>
31+
Deno.writeTextFile(
32+
'.lefthook.yaml',
33+
`assert_lefthook_installed: true\n`,
34+
),
35+
}
36+
}
2037
}
2138

2239
// Check that lefthook is activated for the current project.
@@ -26,17 +43,22 @@ export const issues: Issues = async function* issues() {
2643
message: [
2744
`Expected lefthook to be activated for current project`,
2845
],
29-
fix: async () => execa`lefthook install`,
46+
fix: () => execa`lefthook install`,
3047
}
3148
}
3249
}
3350

51+
type LefthookConfig = { assert_lefthook_installed: boolean }
3452
// Check that specific values are set.
3553
{
36-
const lefthookConfig = yaml.parse(await Deno.readTextFile('.lefthook.yaml')) as Record<
37-
PropertyKey,
38-
unknown
39-
>
54+
const lefthookConfig = yaml.parse(await Deno.readTextFile('.lefthook.yaml'))
55+
if (typeof lefthookConfig !== 'object' || lefthookConfig === null) {
56+
yield {
57+
message: [
58+
`Expected ".lefthook.yaml" to contain an object`,
59+
],
60+
}
61+
}
4062
if (lefthookConfig.assert_lefthook_installed != true) {
4163
yield {
4264
message: [
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { issues } from '../cpp/cmake.ts'
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as fs from 'node:fs/promises'
2+
import { fileExists } from '#common'
3+
import type { Issues } from '#types'
4+
5+
export const issues: Issues = async function* issues() {
6+
const CmakeListsText = 'CMakeLists.txt'
7+
8+
if (!(await fileExists(CmakeListsText))) {
9+
return
10+
}
11+
12+
const content = await fs.readFile(CmakeListsText, 'utf-8')
13+
14+
if (!/^[ \t]*cmake_minimum_required[ \t]*\([ \t]*VERSION[ \t]+/i.test(content)) {
15+
yield {
16+
message: [
17+
`Expected file "${CmakeListsText}" to include cmake_minimum_required(VERSION ...)`,
18+
'But, it could not be found',
19+
],
20+
}
21+
}
22+
23+
if (!/^[ \t]*project[ \t]*\(/im.test(content)) {
24+
yield {
25+
message: [
26+
`Expected file "${CmakeListsText}" to include project(...)`,
27+
'But, it could not be found',
28+
],
29+
}
30+
}
31+
32+
if (!/^[ \t]*set[ \t]*\([ \t]*CMAKE_EXPORT_COMPILE_COMMANDS[ \t]+ON[ \t]*\)/im.test(content)) {
33+
yield {
34+
message: [
35+
`Expected file "${CmakeListsText}" to include set(CMAKE_EXPORT_COMPILE_COMMANDS ON)`,
36+
'But, found no CMAKE_EXPORT_COMPILE_COMMANDS setting',
37+
],
38+
}
39+
}
40+
41+
if (!/^[ \t]*set[ \t]*\([ \t]*CMAKE_COLOR_DIAGNOSTICS[ \t]+ON[ \t]*\)/im.test(content)) {
42+
yield {
43+
message: [
44+
`Expected file "${CmakeListsText}" to include set(CMAKE_COLOR_DIAGNOSTICS ON)`,
45+
'But, found no CMAKE_COLOR_DIAGNOSTICS setting',
46+
],
47+
}
48+
}
49+
}

0 commit comments

Comments
 (0)