Skip to content

Commit

Permalink
fix: Update ESLint to v9, update config, and fix new lint errors (#144)
Browse files Browse the repository at this point in the history
  • Loading branch information
meyfa authored Oct 13, 2024
1 parent 58643d5 commit b0bec98
Show file tree
Hide file tree
Showing 34 changed files with 569 additions and 706 deletions.
3 changes: 0 additions & 3 deletions .eslintrc.yml

This file was deleted.

3 changes: 0 additions & 3 deletions backend/.eslintrc.yml

This file was deleted.

8 changes: 8 additions & 0 deletions backend/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import eslintConfig from '@meyfa/eslint-config'

export default [
...eslintConfig,
{
ignores: ['dist']
}
]
3 changes: 2 additions & 1 deletion backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
},
"scripts": {
"build": "node -e \"fs.rmSync('./dist',{force:true,recursive:true})\" && tsc",
"lint": "tsc --noEmit -p tsconfig.lint.json && eslint --ignore-path .gitignore .",
"lint": "tsc --noEmit -p tsconfig.lint.json && eslint .",
"lint-fix": "tsc --noEmit -p tsconfig.lint.json && eslint --fix .",
"test": "mocha --require tsx --recursive \"test/**/*.ts\""
},
"dependencies": {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/api/cronjob.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export const cronjobRoute = ({ cronJobController }: Controllers): FastifyPluginA

let nextScheduleTime: string | undefined
if (schedule != null) {
const interval = cronParser.parseExpression(schedule ?? '', {
const interval = cronParser.parseExpression(schedule, {
tz: typeof cronJob.spec?.timeZone === 'string' ? cronJob.spec.timeZone : undefined
})
nextScheduleTime = interval.next().toISOString()
Expand Down
9 changes: 5 additions & 4 deletions backend/src/api/jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ function project (job: V1Job): JobsItem {
const isSuccess = typeof job.status?.succeeded === 'number' && job.status.succeeded > 0
const isActive = typeof job.status?.active === 'number' && job.status.active > 0

const isManual = job.metadata?.annotations?.[ForemanAnnotations.Manual] === 'true'
const repositoryScope = job.metadata?.annotations?.[ForemanAnnotations.RepositoryScope]
const debugLogging = job.metadata?.annotations?.[ForemanAnnotations.DebugLogging] != null
const isManual = job.metadata.annotations?.[ForemanAnnotations.Manual] === 'true'
const repositoryScope = job.metadata.annotations?.[ForemanAnnotations.RepositoryScope]
const debugLogging = job.metadata.annotations?.[ForemanAnnotations.DebugLogging] != null
? job.metadata.annotations[ForemanAnnotations.DebugLogging] === 'true'
: undefined
const triggeredBy = job.metadata?.annotations?.[ForemanAnnotations.TriggeredBy] != null
const triggeredBy = job.metadata.annotations?.[ForemanAnnotations.TriggeredBy] != null
? parseLogin(job.metadata.annotations[ForemanAnnotations.TriggeredBy])
: undefined

Expand All @@ -74,6 +74,7 @@ interface UserDescriptor {

function parseLogin (login: string): UserDescriptor {
const [strategy, username] = login.split(':')
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
return { strategy: strategy ?? '', username: username ?? '' }
}

Expand Down
2 changes: 1 addition & 1 deletion backend/src/auth/local-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export async function makeLocalStrategy (adminUser: {
return
}
done(null, false)
}).catch(done)
}).catch((err: unknown) => done(err))
})
}

Expand Down
2 changes: 1 addition & 1 deletion backend/src/controllers/job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class JobController {
if (jobs == null) {
return undefined
}
return jobs.find(j => j.metadata?.namespace === job.namespace && j.metadata?.name === job.name)
return jobs.find((j) => j.metadata?.namespace === job.namespace && j.metadata.name === job.name)
}

invalidateCache (cronJob: V1CronJob): void {
Expand Down
4 changes: 2 additions & 2 deletions backend/src/controllers/pod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export class PodController {
const result: V1Pod[] = []
for (const job of jobs) {
assert.ok(job.metadata?.namespace != null)
assert.ok(job.metadata?.name != null)
assert.ok(job.metadata.name != null)
const pods = await this.getPodsForJob({
namespace: job.metadata.namespace,
name: job.metadata.name
Expand All @@ -51,7 +51,7 @@ export class PodController {
name: string
}): Promise<V1Pod | undefined> {
for (const pod of await this.listAllPods()) {
if (pod.metadata?.namespace === podMetadata.namespace && pod.metadata?.name === podMetadata.name) {
if (pod.metadata?.namespace === podMetadata.namespace && pod.metadata.name === podMetadata.name) {
return pod
}
}
Expand Down
8 changes: 4 additions & 4 deletions backend/src/kubernetes/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,9 +105,9 @@ export class KubernetesApi {
env: Record<string, string>
}): Promise<V1Job> {
assert.ok(options.cronJob.metadata?.namespace != null)
assert.ok(options.cronJob.metadata?.name != null)
assert.ok(options.cronJob.metadata.name != null)
const { name, namespace } = options.cronJob.metadata
assert.ok(options.cronJob.spec?.jobTemplate?.metadata != null)
assert.ok(options.cronJob.spec?.jobTemplate.metadata != null)
this.log.info({
options: {
namespace,
Expand Down Expand Up @@ -167,7 +167,7 @@ function applyMetadataName (jobBody: k8s.V1Job, name: string): k8s.V1Job {
}

function applyEnvToJobContainers (jobBody: k8s.V1Job, env: Record<string, string>): k8s.V1Job {
if (jobBody.spec?.template?.spec?.containers == null) {
if (jobBody.spec?.template.spec?.containers == null) {
// No containers to apply env to
return jobBody
}
Expand Down Expand Up @@ -202,7 +202,7 @@ function applyTtl (jobBody: k8s.V1Job, ttlSecondsAfterFinished: number): k8s.V1J
}
}

function mergeEnv (env: V1EnvVar[], newEnv: Record<string, string>): V1EnvVar[] {
function mergeEnv (env: V1EnvVar[], newEnv: Partial<Record<string, string>>): V1EnvVar[] {
// Remove env vars that will be overwritten, then add new env vars
return env.filter((envVar) => newEnv[envVar.name] == null)
.concat(Object.entries(newEnv).map(([name, value]) => ({ name, value })))
Expand Down
2 changes: 1 addition & 1 deletion backend/src/util/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export function getAvailableMemory (reserve = 0): number | undefined {
// See https://docs.libuv.org/en/v1.x/misc.html#c.uv_get_constrained_memory
// It is important that we don't return a gigantic number here, as the scrypt algorithm doesn't allow it.
const constrainedMemory = process.constrainedMemory()
if (constrainedMemory != null && constrainedMemory > 0 && constrainedMemory <= MAX_CONSTRAINED_MEMORY) {
if (constrainedMemory > 0 && constrainedMemory <= MAX_CONSTRAINED_MEMORY) {
const memoryUsage = process.memoryUsage.rss()
return Math.max(0, constrainedMemory - memoryUsage - reserve)
}
Expand Down
6 changes: 5 additions & 1 deletion backend/tsconfig.lint.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"allowJs": true
},
"include": [
"src",
"test"
"test",
"eslint.config.js"
]
}
8 changes: 8 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import eslintConfig from '@meyfa/eslint-config'

export default [
...eslintConfig,
{
ignores: ['dist']
}
]
38 changes: 0 additions & 38 deletions frontend/.eslintrc.yml

This file was deleted.

57 changes: 57 additions & 0 deletions frontend/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import eslintConfig from '@meyfa/eslint-config'
import pluginReact from 'eslint-plugin-react'
import pluginReactHooks from 'eslint-plugin-react-hooks'
import pluginJsxA11y from 'eslint-plugin-jsx-a11y'
import { fixupPluginRules } from '@eslint/compat'

export default [
...eslintConfig,
pluginReact.configs.flat.recommended,
pluginReact.configs.flat['jsx-runtime'],
pluginJsxA11y.flatConfigs.recommended,
{
ignores: ['dist']
},
{
plugins: {
'react-hooks': fixupPluginRules(pluginReactHooks)
},

settings: {
react: {
version: 'detect'
}
},

rules: {
...pluginReactHooks.configs.recommended.rules,

'react/no-typos': ['error'],
'react/style-prop-object': ['warn'],
'react/jsx-pascal-case': ['warn', {
allowAllCaps: true,
ignore: []
}],

'react/void-dom-elements-no-children': ['error'],
'react/no-unstable-nested-components': ['error'],
'react/prop-types': ['error', {
ignore: ['children']
}],

// disable in favor of @stylistic
'jsx-quotes': 'off',
'react/jsx-indent': 'off',
'react/jsx-indent-props': 'off',
'react/jsx-first-prop-new-line': 'off',
'react/jsx-max-props-per-line': 'off',
'react/jsx-props-no-multi-spaces': 'off',
'react/jsx-tag-spacing': 'off',
'react/jsx-wrap-multilines': 'off',

// might clash with @stylistic in the future, but are needed for now
'react/jsx-closing-bracket-location': ['error'],
'react/jsx-equals-spacing': ['error', 'never']
}
}
]
3 changes: 2 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"private": true,
"scripts": {
"build": "vite build",
"lint": "tsc --noEmit -p tsconfig.lint.json && eslint --ignore-path .gitignore ."
"lint": "tsc --noEmit -p tsconfig.lint.json && eslint .",
"lint-fix": "tsc --noEmit -p tsconfig.lint.json && eslint --fix ."
},
"devDependencies": {
"@types/luxon": "3.4.2",
Expand Down
7 changes: 3 additions & 4 deletions frontend/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { Jobs } from './pages/Jobs.js'
import clsx from 'clsx'
import Icon from './components/Icon.js'
import { faChevronDown, faChevronUp, faPaintRoller } from '@fortawesome/free-solid-svg-icons'
import { ColoredSkeleton } from './components/ColoredSkeleton.js'
import { useMobileNavigation } from './util/navigation.js'

export const App: FunctionComponent = () => {
Expand Down Expand Up @@ -56,17 +55,17 @@ export const App: FunctionComponent = () => {
'absolute top-3 right-4 rounded border-2 border-white/25 hocus:border-white/50 p-2 leading-none',
isMobileNavigation ? 'block' : 'hidden'
)}
onClick={() => setAsideExpanded(state => !state)}
onClick={() => setAsideExpanded((state) => !state)}
>
<Icon icon={asideExpanded ? faChevronUp : faChevronDown} />
</button>
{!loading && userInfo !== false && (
<div className={clsx('mt-4', isMobileNavigation && !asideExpanded ? 'hidden' : 'block')}>
<Navigation onNavigate={() => setAsideExpanded(false)} />
<div className='my-4'>
{!loading ? <span>Logged in as: {userInfo?.username} ({userInfo?.strategy} login)</span> : <ColoredSkeleton />}
<span>Logged in as: {userInfo?.username} ({userInfo?.strategy} login)</span>
</div>
<Button onClick={dispatchLogout} disabled={loading || logoutInProgress}>
<Button onClick={dispatchLogout} disabled={logoutInProgress}>
Logout
</Button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export type TriggerJobOptions = TriggerRoute['Body']
const route = <T extends {}, Args extends unknown[]> (route: ApiRoute<T, Args>): ApiRoute<T, Args> => route

export const api = {
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions

userInfo: route({
request: () => ({ url: 'auth/me' }),
transformResponse: async (response): Promise<MeRoute['Reply'] | false> => await response.json(),
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/dispatch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export type ApiDispatchHook<T extends {}, Args extends unknown[]> = FetchState<T
* @param route The route to dispatch to.
* @returns An object with a dispatch method, and the current state of the request.
*/
export function useApiDispatch <T extends {}, Args extends unknown[]> (route: ApiRoute<T, Args>): ApiDispatchHook<T, Args> {
export function useApiDispatch<T extends {}, Args extends unknown[]> (route: ApiRoute<T, Args>): ApiDispatchHook<T, Args> {
const fetcher = useApiFetcher<T>()
const [inProgress, setInProgress] = useState(false)

Expand Down
11 changes: 7 additions & 4 deletions frontend/src/api/fetch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export type FetchHook<T extends {}> = FetchState<T> & {
reset: () => void
}

export function useApiFetcher <T extends {}> (): FetchHook<T> {
export function useApiFetcher<T extends {}> (): FetchHook<T> {
const [state, setState] = useState<FetchState<T>>({
data: undefined,
error: undefined
Expand All @@ -47,7 +47,10 @@ export function useApiFetcher <T extends {}> (): FetchHook<T> {
// the response is not an error
return await transform.transformResponse(response)
})
.catch(async (error) => {
.catch(async (error: unknown) => {
if (!(error instanceof Error)) {
throw new Error(String(error))
}
// the response is an error, but may still become a valid response via the transform
const transformed: T | Error = transform.transformError?.(error) ?? error
if (transformed instanceof Error) {
Expand All @@ -64,13 +67,13 @@ export function useApiFetcher <T extends {}> (): FetchHook<T> {
error: undefined
}))
})
.catch(async (error) => {
.catch(async (error: unknown) => {
// all transforms are applied and the response is an error
if (signal?.aborted === true) return
setState((state) => ({
...state,
data: undefined,
error
error: error instanceof Error ? error : new Error(String(error))
}))
})
.finally(() => {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/api/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export interface SubscriptionOptions {
* @param args The arguments to pass to the route.
* @returns An object with the current state of the request.
*/
export function useApiSubscription <T extends {}, Args extends unknown[]> (
export function useApiSubscription<T extends {}, Args extends unknown[]> (
options: SubscriptionOptions,
route: ApiRoute<T, Args>,
...args: Args
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/JobPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const JobPanel: FunctionComponent<{
<div className='text-gray-200 text-sm'>
{props.startTime != null ? DateTime.fromISO(props.startTime).toRelative() : <ColoredSkeleton />}
{props.manual && (
<Annotation icon={faPaintRoller} text='Manual' />
<Annotation icon={faPaintRoller} text='Manual' />
)}
</div>
</LinkCard>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/LogDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ const LogDisplay: FunctionComponent<{
useLayoutEffect(() => {
if (props.follow) {
logElement.current?.scrollTo({
top: logElement.current?.scrollHeight
top: logElement.current.scrollHeight
})
}
}, [props.follow, logs])
Expand Down
Loading

0 comments on commit b0bec98

Please sign in to comment.