wip: cli and changelog commit upload
This commit is contained in:
parent
a14cbd4437
commit
b182329146
66
apps/api/src/changelog/commit/byId.ts
Normal file
66
apps/api/src/changelog/commit/byId.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { changelog, changelog_version, db } from '@boring.tools/database'
|
||||||
|
import { VersionByIdParams, VersionOutput } from '@boring.tools/schema'
|
||||||
|
import { createRoute } from '@hono/zod-openapi'
|
||||||
|
import { and, eq } from 'drizzle-orm'
|
||||||
|
|
||||||
|
export const byId = createRoute({
|
||||||
|
method: 'get',
|
||||||
|
path: '/:id',
|
||||||
|
request: {
|
||||||
|
params: VersionByIdParams,
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: VersionOutput,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'Return version by id',
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
description: 'Bad Request',
|
||||||
|
},
|
||||||
|
500: {
|
||||||
|
description: 'Internal Server Error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const byIdFunc = async ({
|
||||||
|
userId,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
userId: string
|
||||||
|
id: string
|
||||||
|
}) => {
|
||||||
|
const versionResult = await db.query.changelog_version.findFirst({
|
||||||
|
where: eq(changelog_version.id, id),
|
||||||
|
with: {
|
||||||
|
commits: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!versionResult) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!versionResult.changelogId) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const changelogResult = await db.query.changelog.findMany({
|
||||||
|
where: and(eq(changelog.userId, userId)),
|
||||||
|
columns: {
|
||||||
|
id: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const changelogIds = changelogResult.map((cl) => cl.id)
|
||||||
|
|
||||||
|
if (!changelogIds.includes(versionResult.changelogId)) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return versionResult
|
||||||
|
}
|
60
apps/api/src/changelog/commit/create.ts
Normal file
60
apps/api/src/changelog/commit/create.ts
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import { changelog, changelog_commit, db } from '@boring.tools/database'
|
||||||
|
import { CommitCreateInput, CommitCreateOutput } from '@boring.tools/schema'
|
||||||
|
import { createRoute, type z } from '@hono/zod-openapi'
|
||||||
|
import { and, eq } from 'drizzle-orm'
|
||||||
|
import { HTTPException } from 'hono/http-exception'
|
||||||
|
import type { changelogCommitApi } from '.'
|
||||||
|
import { verifyAuthentication } from '../../utils/authentication'
|
||||||
|
|
||||||
|
export const route = createRoute({
|
||||||
|
method: 'post',
|
||||||
|
path: '/',
|
||||||
|
request: {
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
'application/json': { schema: CommitCreateInput },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
201: {
|
||||||
|
content: {
|
||||||
|
'application/json': { schema: CommitCreateOutput },
|
||||||
|
},
|
||||||
|
description: 'Commits created',
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
description: 'Bad Request',
|
||||||
|
},
|
||||||
|
500: {
|
||||||
|
description: 'Internal Server Error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const regsiterCommitCreate = (api: typeof changelogCommitApi) => {
|
||||||
|
return api.openapi(route, async (c) => {
|
||||||
|
const userId = verifyAuthentication(c)
|
||||||
|
|
||||||
|
const data: z.infer<typeof CommitCreateInput> = await c.req.json()
|
||||||
|
|
||||||
|
const changelogResult = await db.query.changelog.findFirst({
|
||||||
|
where: and(
|
||||||
|
eq(changelog.id, data[0].changelogId),
|
||||||
|
eq(changelog.userId, userId),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!changelogResult) {
|
||||||
|
throw new HTTPException(404, { message: 'Not Found' })
|
||||||
|
}
|
||||||
|
|
||||||
|
const [result] = await db.insert(changelog_commit).values(data).returning()
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
throw new HTTPException(404, { message: 'Not Found' })
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json(result, 200)
|
||||||
|
})
|
||||||
|
}
|
63
apps/api/src/changelog/commit/delete.ts
Normal file
63
apps/api/src/changelog/commit/delete.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
import { changelog, changelog_version, db } from '@boring.tools/database'
|
||||||
|
import { GeneralOutput } from '@boring.tools/schema'
|
||||||
|
import { createRoute } from '@hono/zod-openapi'
|
||||||
|
import { and, eq } from 'drizzle-orm'
|
||||||
|
import { HTTPException } from 'hono/http-exception'
|
||||||
|
|
||||||
|
export const remove = createRoute({
|
||||||
|
method: 'delete',
|
||||||
|
path: '/:id',
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: GeneralOutput,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'Removes a version by id',
|
||||||
|
},
|
||||||
|
404: {
|
||||||
|
content: {
|
||||||
|
'application/json': {
|
||||||
|
schema: GeneralOutput,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'Version not found',
|
||||||
|
},
|
||||||
|
500: {
|
||||||
|
description: 'Internal Server Error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const removeFunc = async ({
|
||||||
|
userId,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
userId: string
|
||||||
|
id: string
|
||||||
|
}) => {
|
||||||
|
const changelogResult = await db.query.changelog.findMany({
|
||||||
|
where: and(eq(changelog.userId, userId)),
|
||||||
|
with: {
|
||||||
|
versions: {
|
||||||
|
where: eq(changelog_version.id, id),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const findChangelog = changelogResult.find((change) =>
|
||||||
|
change.versions.find((ver) => ver.id === id),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!findChangelog?.versions.length) {
|
||||||
|
throw new HTTPException(404, {
|
||||||
|
message: 'Version not found',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return db
|
||||||
|
.delete(changelog_version)
|
||||||
|
.where(and(eq(changelog_version.id, id)))
|
||||||
|
.returning()
|
||||||
|
}
|
122
apps/api/src/changelog/commit/index.ts
Normal file
122
apps/api/src/changelog/commit/index.ts
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
import { OpenAPIHono } from '@hono/zod-openapi'
|
||||||
|
import type { Variables } from '../..'
|
||||||
|
import type { ContextModule } from '../../utils/sentry'
|
||||||
|
import { regsiterCommitCreate } from './create'
|
||||||
|
|
||||||
|
export const changelogCommitApi = new OpenAPIHono<{ Variables: Variables }>()
|
||||||
|
|
||||||
|
const module: ContextModule = {
|
||||||
|
name: 'changelog',
|
||||||
|
sub_module: 'version',
|
||||||
|
}
|
||||||
|
|
||||||
|
regsiterCommitCreate(changelogCommitApi)
|
||||||
|
|
||||||
|
// app.openapi(create, async (c) => {
|
||||||
|
// const userId = verifyAuthentication(c)
|
||||||
|
// try {
|
||||||
|
// const payload = await c.req.json()
|
||||||
|
// const result = await createFunc({ userId, payload })
|
||||||
|
|
||||||
|
// if (!result) {
|
||||||
|
// return c.json({ message: 'Version not created' }, 400)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// return c.json(result, 201)
|
||||||
|
// } catch (error) {
|
||||||
|
// return captureSentry({
|
||||||
|
// c,
|
||||||
|
// error,
|
||||||
|
// module,
|
||||||
|
// user: {
|
||||||
|
// id: userId,
|
||||||
|
// },
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
|
||||||
|
/* app.openapi(byId, async (c) => {
|
||||||
|
const userId = verifyAuthentication(c)
|
||||||
|
try {
|
||||||
|
const id = c.req.param('id')
|
||||||
|
const result = await byIdFunc({ userId, id })
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
return c.json({ message: 'Version not found' }, 404)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure all required properties are present and non-null
|
||||||
|
return c.json(
|
||||||
|
{
|
||||||
|
...result,
|
||||||
|
changelogId: result.changelogId || '',
|
||||||
|
version: result.version || '',
|
||||||
|
status: result.status || 'draft',
|
||||||
|
releasedAt: result.releasedAt,
|
||||||
|
commits: result.commits || [],
|
||||||
|
markdown: result.markdown || '',
|
||||||
|
},
|
||||||
|
200,
|
||||||
|
)
|
||||||
|
} catch (error) {
|
||||||
|
return captureSentry({
|
||||||
|
c,
|
||||||
|
error,
|
||||||
|
module,
|
||||||
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.openapi(update, async (c) => {
|
||||||
|
const userId = verifyAuthentication(c)
|
||||||
|
try {
|
||||||
|
const id = c.req.param('id')
|
||||||
|
|
||||||
|
if (!id) {
|
||||||
|
return c.json({ message: 'Version not found' }, 404)
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await updateFunc({
|
||||||
|
userId,
|
||||||
|
payload: await c.req.json(),
|
||||||
|
id,
|
||||||
|
})
|
||||||
|
|
||||||
|
return c.json(result)
|
||||||
|
} catch (error) {
|
||||||
|
return captureSentry({
|
||||||
|
c,
|
||||||
|
error,
|
||||||
|
module,
|
||||||
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.openapi(remove, async (c) => {
|
||||||
|
const userId = verifyAuthentication(c)
|
||||||
|
try {
|
||||||
|
const id = c.req.param('id')
|
||||||
|
const result = await removeFunc({ userId, id })
|
||||||
|
|
||||||
|
if (result.length === 0) {
|
||||||
|
return c.json({ message: 'Version not found' }, 404)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.json({ message: 'Version removed' })
|
||||||
|
} catch (error) {
|
||||||
|
return captureSentry({
|
||||||
|
c,
|
||||||
|
error,
|
||||||
|
module,
|
||||||
|
user: {
|
||||||
|
id: userId,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}) */
|
72
apps/api/src/changelog/commit/update.ts
Normal file
72
apps/api/src/changelog/commit/update.ts
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
import { changelog, changelog_version, db } from '@boring.tools/database'
|
||||||
|
import { VersionUpdateInput, VersionUpdateOutput } from '@boring.tools/schema'
|
||||||
|
import { createRoute, type z } from '@hono/zod-openapi'
|
||||||
|
import { and, eq } from 'drizzle-orm'
|
||||||
|
import { HTTPException } from 'hono/http-exception'
|
||||||
|
|
||||||
|
export const update = createRoute({
|
||||||
|
method: 'put',
|
||||||
|
path: '/:id',
|
||||||
|
request: {
|
||||||
|
body: {
|
||||||
|
content: {
|
||||||
|
'application/json': { schema: VersionUpdateInput },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
responses: {
|
||||||
|
200: {
|
||||||
|
content: {
|
||||||
|
'application/json': { schema: VersionUpdateOutput },
|
||||||
|
},
|
||||||
|
description: 'Return updated version',
|
||||||
|
},
|
||||||
|
400: {
|
||||||
|
description: 'Bad Request',
|
||||||
|
},
|
||||||
|
500: {
|
||||||
|
description: 'Internal Server Error',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
export const updateFunc = async ({
|
||||||
|
userId,
|
||||||
|
payload,
|
||||||
|
id,
|
||||||
|
}: {
|
||||||
|
userId: string
|
||||||
|
payload: z.infer<typeof VersionUpdateInput>
|
||||||
|
id: string
|
||||||
|
}) => {
|
||||||
|
const changelogResult = await db.query.changelog.findMany({
|
||||||
|
where: and(eq(changelog.userId, userId)),
|
||||||
|
with: {
|
||||||
|
versions: {
|
||||||
|
where: eq(changelog_version.id, id),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const findChangelog = changelogResult.find((change) =>
|
||||||
|
change.versions.find((ver) => ver.id === id),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!findChangelog?.versions.length) {
|
||||||
|
throw new HTTPException(404, {
|
||||||
|
message: 'Version not found',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const [versionUpdateResult] = await db
|
||||||
|
.update(changelog_version)
|
||||||
|
.set({
|
||||||
|
status: payload.status,
|
||||||
|
markdown: payload.markdown,
|
||||||
|
releasedAt: payload.releasedAt ? new Date(payload.releasedAt) : null,
|
||||||
|
})
|
||||||
|
.where(and(eq(changelog_version.id, id)))
|
||||||
|
.returning()
|
||||||
|
|
||||||
|
return versionUpdateResult
|
||||||
|
}
|
@ -5,6 +5,7 @@ import { apiReference } from '@scalar/hono-api-reference'
|
|||||||
import { cors } from 'hono/cors'
|
import { cors } from 'hono/cors'
|
||||||
|
|
||||||
import changelog from './changelog'
|
import changelog from './changelog'
|
||||||
|
import { changelogCommitApi } from './changelog/commit'
|
||||||
import version from './changelog/version'
|
import version from './changelog/version'
|
||||||
import user from './user'
|
import user from './user'
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ app.use('/v1/*', authentication)
|
|||||||
app.route('/v1/user', user)
|
app.route('/v1/user', user)
|
||||||
app.route('/v1/changelog', changelog)
|
app.route('/v1/changelog', changelog)
|
||||||
app.route('/v1/changelog/version', version)
|
app.route('/v1/changelog/version', version)
|
||||||
|
app.route('/v1/changelog/commit', changelogCommitApi)
|
||||||
app.route('/v1/page', pageApi)
|
app.route('/v1/page', pageApi)
|
||||||
|
|
||||||
app.doc('/openapi.json', {
|
app.doc('/openapi.json', {
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-hook-form": "^7.53.0",
|
"react-hook-form": "^7.53.0",
|
||||||
"tailwindcss-animate": "^1.0.7",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
|
"usehooks-ts": "^3.1.0",
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -9,15 +9,26 @@ import {
|
|||||||
SidebarMenuSubButton,
|
SidebarMenuSubButton,
|
||||||
SidebarMenuSubItem,
|
SidebarMenuSubItem,
|
||||||
} from '@boring.tools/ui'
|
} from '@boring.tools/ui'
|
||||||
import { Link } from '@tanstack/react-router'
|
import { Link, useLocation } from '@tanstack/react-router'
|
||||||
import { ChevronRightIcon, FileStackIcon, PlusIcon } from 'lucide-react'
|
import { ChevronRightIcon, FileStackIcon, PlusIcon } from 'lucide-react'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useLocalStorage } from 'usehooks-ts'
|
||||||
import { useChangelogList } from '../hooks/useChangelog'
|
import { useChangelogList } from '../hooks/useChangelog'
|
||||||
|
|
||||||
export const SidebarChangelog = () => {
|
export const SidebarChangelog = () => {
|
||||||
|
const location = useLocation()
|
||||||
|
const [value, setValue] = useLocalStorage('sidebar-changelog-open', false)
|
||||||
const { data, error } = useChangelogList()
|
const { data, error } = useChangelogList()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const firstElement = location.href.split('/')[1]
|
||||||
|
if (firstElement === 'changelog') {
|
||||||
|
setValue(true)
|
||||||
|
}
|
||||||
|
}, [location, setValue])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapsible asChild>
|
<Collapsible asChild open={value} onOpenChange={() => setValue(!value)}>
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton asChild tooltip="Changelog">
|
<SidebarMenuButton asChild tooltip="Changelog">
|
||||||
<Link
|
<Link
|
||||||
|
@ -9,15 +9,26 @@ import {
|
|||||||
SidebarMenuSubButton,
|
SidebarMenuSubButton,
|
||||||
SidebarMenuSubItem,
|
SidebarMenuSubItem,
|
||||||
} from '@boring.tools/ui'
|
} from '@boring.tools/ui'
|
||||||
import { Link } from '@tanstack/react-router'
|
import { Link, useLocation } from '@tanstack/react-router'
|
||||||
import { ChevronRightIcon, NotebookTextIcon, PlusIcon } from 'lucide-react'
|
import { ChevronRightIcon, NotebookTextIcon, PlusIcon } from 'lucide-react'
|
||||||
|
import { useEffect } from 'react'
|
||||||
|
import { useLocalStorage } from 'usehooks-ts'
|
||||||
import { usePageList } from '../hooks/usePage'
|
import { usePageList } from '../hooks/usePage'
|
||||||
|
|
||||||
export const SidebarPage = () => {
|
export const SidebarPage = () => {
|
||||||
|
const location = useLocation()
|
||||||
|
const [value, setValue] = useLocalStorage('sidebar-page-open', false)
|
||||||
const { data, error } = usePageList()
|
const { data, error } = usePageList()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const firstElement = location.href.split('/')[1]
|
||||||
|
if (firstElement === 'page') {
|
||||||
|
setValue(true)
|
||||||
|
}
|
||||||
|
}, [location, setValue])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Collapsible asChild>
|
<Collapsible asChild open={value} onOpenChange={() => setValue(!value)}>
|
||||||
<SidebarMenuItem>
|
<SidebarMenuItem>
|
||||||
<SidebarMenuButton asChild tooltip="Page">
|
<SidebarMenuButton asChild tooltip="Page">
|
||||||
<Link to="/page" activeProps={{ className: 'bg-sidebar-accent' }}>
|
<Link to="/page" activeProps={{ className: 'bg-sidebar-accent' }}>
|
||||||
|
@ -13,7 +13,6 @@ import { useChangelogById } from '../hooks/useChangelog'
|
|||||||
const Component = () => {
|
const Component = () => {
|
||||||
const { id } = Route.useParams()
|
const { id } = Route.useParams()
|
||||||
const { data, error, isPending, refetch } = useChangelogById({ id })
|
const { data, error, isPending, refetch } = useChangelogById({ id })
|
||||||
console.log(data)
|
|
||||||
if (error) {
|
if (error) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center mt-32 flex-col">
|
<div className="flex items-center justify-center mt-32 flex-col">
|
||||||
@ -65,16 +64,7 @@ const Component = () => {
|
|||||||
</TooltipContent>
|
</TooltipContent>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<Tooltip>
|
*/}
|
||||||
<TooltipTrigger asChild>
|
|
||||||
<Button variant={'ghost'}>
|
|
||||||
<Globe2Icon strokeWidth={1.5} />
|
|
||||||
</Button>
|
|
||||||
</TooltipTrigger>
|
|
||||||
<TooltipContent>
|
|
||||||
<p>Public Page</p>
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip> */}
|
|
||||||
|
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
|
175
apps/cli/.gitignore
vendored
Normal file
175
apps/cli/.gitignore
vendored
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
|
||||||
|
logs
|
||||||
|
_.log
|
||||||
|
npm-debug.log_
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
.pnpm-debug.log*
|
||||||
|
|
||||||
|
# Caches
|
||||||
|
|
||||||
|
.cache
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
|
||||||
|
report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
|
||||||
|
pids
|
||||||
|
_.pid
|
||||||
|
_.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
|
||||||
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||||
|
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Snowpack dependency directory (https://snowpack.dev/)
|
||||||
|
|
||||||
|
web_modules/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional stylelint cache
|
||||||
|
|
||||||
|
.stylelintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variable files
|
||||||
|
|
||||||
|
.env
|
||||||
|
.env.development.local
|
||||||
|
.env.test.local
|
||||||
|
.env.production.local
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
|
|
||||||
|
.parcel-cache
|
||||||
|
|
||||||
|
# Next.js build output
|
||||||
|
|
||||||
|
.next
|
||||||
|
out
|
||||||
|
|
||||||
|
# Nuxt.js build / generate output
|
||||||
|
|
||||||
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
|
||||||
|
# public
|
||||||
|
|
||||||
|
# vuepress build output
|
||||||
|
|
||||||
|
.vuepress/dist
|
||||||
|
|
||||||
|
# vuepress v2.x temp and cache directory
|
||||||
|
|
||||||
|
.temp
|
||||||
|
|
||||||
|
# Docusaurus cache and generated files
|
||||||
|
|
||||||
|
.docusaurus
|
||||||
|
|
||||||
|
# Serverless directories
|
||||||
|
|
||||||
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
|
# yarn v2
|
||||||
|
|
||||||
|
.yarn/cache
|
||||||
|
.yarn/unplugged
|
||||||
|
.yarn/build-state.yml
|
||||||
|
.yarn/install-state.gz
|
||||||
|
.pnp.*
|
||||||
|
|
||||||
|
# IntelliJ based IDEs
|
||||||
|
.idea
|
||||||
|
|
||||||
|
# Finder (MacOS) folder config
|
||||||
|
.DS_Store
|
15
apps/cli/README.md
Normal file
15
apps/cli/README.md
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# cli
|
||||||
|
|
||||||
|
To install dependencies:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun install
|
||||||
|
```
|
||||||
|
|
||||||
|
To run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bun run src/index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
This project was created using `bun init` in bun v1.1.21. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
11
apps/cli/package.json
Normal file
11
apps/cli/package.json
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"name": "@boring.tools/cli",
|
||||||
|
"module": "src/index.ts",
|
||||||
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/bun": "latest"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5.0.0"
|
||||||
|
}
|
||||||
|
}
|
70
apps/cli/src/index.ts
Normal file
70
apps/cli/src/index.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
#! /usr/bin/env bun
|
||||||
|
import { parseArgs } from 'node:util'
|
||||||
|
import semver from 'semver'
|
||||||
|
import { z } from 'zod'
|
||||||
|
import { git_log } from './utils/git_log'
|
||||||
|
//import { pushCommits } from './pushCommits'
|
||||||
|
|
||||||
|
const ENV_VERSION = Bun.env.CHANGELOG_VERSION
|
||||||
|
const ENV_ID = Bun.env.CHANGELOG_ID
|
||||||
|
const ENV_TOKEN = Bun.env.CHANGELOG_TOKEN
|
||||||
|
|
||||||
|
const schema = z.object({
|
||||||
|
title: z.string().optional(),
|
||||||
|
version: z.string().optional(),
|
||||||
|
token: z.string(),
|
||||||
|
changelogId: z.string(),
|
||||||
|
})
|
||||||
|
export type Arguments = z.infer<typeof schema>
|
||||||
|
|
||||||
|
const { values } = parseArgs({
|
||||||
|
args: Bun.argv,
|
||||||
|
options: {
|
||||||
|
title: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
version: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
token: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
changelogId: {
|
||||||
|
type: 'string',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
strict: true,
|
||||||
|
allowPositionals: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
const mappedArguments = {
|
||||||
|
...values,
|
||||||
|
version: values.version || ENV_VERSION,
|
||||||
|
token: values.token || ENV_TOKEN,
|
||||||
|
changelogId: values.changelogId || ENV_ID,
|
||||||
|
}
|
||||||
|
|
||||||
|
const args = schema.safeParse(mappedArguments)
|
||||||
|
|
||||||
|
/*if (!args.success) {
|
||||||
|
console.error(
|
||||||
|
`@changelog/cli: Missing arguemnts: ${args.error.errors
|
||||||
|
.map((error) => error.path[0])
|
||||||
|
.join(', ')}`,
|
||||||
|
)
|
||||||
|
process.exit(1)
|
||||||
|
} */
|
||||||
|
|
||||||
|
// const version = semver.coerce(result.data.version);
|
||||||
|
|
||||||
|
// // Check for correct semver
|
||||||
|
// if (!version) {
|
||||||
|
// console.error(
|
||||||
|
// "@changelog/cli: Invalid version. Please provide a valid semver version."
|
||||||
|
// );
|
||||||
|
// process.exit(1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
//pushCommits(args.data)
|
||||||
|
|
||||||
|
git_log('')
|
45
apps/cli/src/utils/git_log.ts
Normal file
45
apps/cli/src/utils/git_log.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
const GITFORMAT = `--pretty=format:{
|
||||||
|
"commit": "%h",
|
||||||
|
"parent": "%p",
|
||||||
|
"refs": "%D",
|
||||||
|
"subject": "%s",
|
||||||
|
"notes": "%N",
|
||||||
|
"body": "%b",
|
||||||
|
"author": { "name": "%aN", "email": "%aE", "date": "%ad" },
|
||||||
|
"commiter": { "name": "%cN", "email": "%cE", "date": "%cd" }
|
||||||
|
},`
|
||||||
|
export const git_log = async (
|
||||||
|
from: string | undefined,
|
||||||
|
to = 'HEAD',
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||||
|
): Promise<any[]> => {
|
||||||
|
// https://git-scm.com/docs/pretty-formats
|
||||||
|
const r = await Bun.spawn([
|
||||||
|
'git',
|
||||||
|
'--no-pager',
|
||||||
|
'log',
|
||||||
|
`${from ? `${from}...` : ''}${to}`,
|
||||||
|
GITFORMAT,
|
||||||
|
//'--name-status',
|
||||||
|
'--date=iso',
|
||||||
|
])
|
||||||
|
const text = await new Response(r.stdout).text()
|
||||||
|
console.log(text)
|
||||||
|
r /* eturn text
|
||||||
|
.split('----\n')
|
||||||
|
.splice(1)
|
||||||
|
.map((line) => {
|
||||||
|
const [firstLine, , ..._body] = line.split('\n')
|
||||||
|
const [message, shortHash, authorName, date, authorEmail] =
|
||||||
|
firstLine.split('|')
|
||||||
|
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||||
|
const r: any = {
|
||||||
|
date,
|
||||||
|
message,
|
||||||
|
shortHash,
|
||||||
|
author: { name: authorName, email: authorEmail },
|
||||||
|
body: _body.join('\n'),
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}) */
|
||||||
|
}
|
27
apps/cli/tsconfig.json
Normal file
27
apps/cli/tsconfig.json
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
// Enable latest features
|
||||||
|
"lib": ["ESNext", "DOM"],
|
||||||
|
"target": "ESNext",
|
||||||
|
"module": "ESNext",
|
||||||
|
"moduleDetection": "force",
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"allowJs": true,
|
||||||
|
|
||||||
|
// Bundler mode
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"verbatimModuleSyntax": true,
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
// Best practices
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
|
||||||
|
// Some stricter flags (disabled by default)
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noUnusedParameters": false,
|
||||||
|
"noPropertyAccessFromIndexSignature": false
|
||||||
|
}
|
||||||
|
}
|
28
bruno/Changelog/Commit/Create.bru
Normal file
28
bruno/Changelog/Commit/Create.bru
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
meta {
|
||||||
|
name: Create
|
||||||
|
type: http
|
||||||
|
seq: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
get {
|
||||||
|
url: {{API_URL}}/v1/changelog/commit
|
||||||
|
body: json
|
||||||
|
auth: none
|
||||||
|
}
|
||||||
|
|
||||||
|
body:json {
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"changelogId": "aad2c981-e1cc-4de0-8185-8d1c117886b9",
|
||||||
|
"commit": "abc123",
|
||||||
|
"parent": "abc122",
|
||||||
|
"subject": "some",
|
||||||
|
"author": {
|
||||||
|
"name": "asd",
|
||||||
|
"email": "hello@hashdot.co",
|
||||||
|
"date": "somedate"
|
||||||
|
},
|
||||||
|
"body": ""
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
5
bruno/bruno.json
Normal file
5
bruno/bruno.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"version": "1",
|
||||||
|
"name": "boring.tools",
|
||||||
|
"type": "collection"
|
||||||
|
}
|
3
bruno/environments/Development.bru
Normal file
3
bruno/environments/Development.bru
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
vars {
|
||||||
|
API_URL: http://localhost:3000
|
||||||
|
}
|
@ -105,13 +105,24 @@ export const changelog_commit = pgTable(
|
|||||||
onDelete: 'cascade',
|
onDelete: 'cascade',
|
||||||
}),
|
}),
|
||||||
|
|
||||||
shortHash: varchar('shortHash', { length: 8 }).notNull(),
|
commit: varchar('commit', { length: 8 }).notNull(),
|
||||||
author: json('author').$type<{ name: string; email: string }>(),
|
parent: varchar('parent', { length: 8 }),
|
||||||
|
subject: text('subject').notNull(),
|
||||||
|
author: json('author').$type<{
|
||||||
|
name: string
|
||||||
|
email: string
|
||||||
|
date: string
|
||||||
|
}>(),
|
||||||
|
commiter: json('comitter').$type<{
|
||||||
|
name: string
|
||||||
|
email: string
|
||||||
|
date: string
|
||||||
|
}>(),
|
||||||
|
|
||||||
body: text('body'),
|
body: text('body'),
|
||||||
message: text('message').notNull(),
|
|
||||||
},
|
},
|
||||||
(table) => ({
|
(table) => ({
|
||||||
unique: uniqueIndex('unique').on(table.changelogId, table.shortHash),
|
unique: uniqueIndex('unique').on(table.changelogId, table.commit),
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
30
packages/schema/src/commit/base.ts
Normal file
30
packages/schema/src/commit/base.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { z } from '@hono/zod-openapi'
|
||||||
|
|
||||||
|
export const CommitOutput = z
|
||||||
|
.object({
|
||||||
|
id: z.string().uuid().openapi({
|
||||||
|
example: '9f00f912-f687-42ef-84d7-efde48ca11ef',
|
||||||
|
}),
|
||||||
|
changelogId: z.string().uuid().openapi({
|
||||||
|
example: '8f00f912-f687-42ef-84d7-efde48ca11ef',
|
||||||
|
}),
|
||||||
|
commit: z.string().openapi({
|
||||||
|
example: 'abc123',
|
||||||
|
}),
|
||||||
|
parent: z.string().optional().openapi({
|
||||||
|
example: 'abc122',
|
||||||
|
}),
|
||||||
|
subject: z.string(),
|
||||||
|
author: z.object({
|
||||||
|
name: z.string(),
|
||||||
|
email: z.string().email(),
|
||||||
|
date: z.string(),
|
||||||
|
}),
|
||||||
|
commiter: z.object({
|
||||||
|
name: z.string(),
|
||||||
|
email: z.string().email(),
|
||||||
|
date: z.string(),
|
||||||
|
}),
|
||||||
|
body: z.string().optional(),
|
||||||
|
})
|
||||||
|
.openapi('Commit')
|
14
packages/schema/src/commit/byId.ts
Normal file
14
packages/schema/src/commit/byId.ts
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import { z } from '@hono/zod-openapi'
|
||||||
|
|
||||||
|
export const VersionByIdParams = z.object({
|
||||||
|
id: z
|
||||||
|
.string()
|
||||||
|
.uuid()
|
||||||
|
.openapi({
|
||||||
|
param: {
|
||||||
|
name: 'id',
|
||||||
|
in: 'path',
|
||||||
|
},
|
||||||
|
example: 'a5ed5965-0506-44e6-aaec-0465ff9fe092',
|
||||||
|
}),
|
||||||
|
})
|
34
packages/schema/src/commit/create.ts
Normal file
34
packages/schema/src/commit/create.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import { z } from '@hono/zod-openapi'
|
||||||
|
import { CommitOutput } from './base'
|
||||||
|
|
||||||
|
export const CommitCreateOutput = CommitOutput
|
||||||
|
export const CommitCreateInput = z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
|
changelogId: z.string().uuid().openapi({
|
||||||
|
example: '8f00f912-f687-42ef-84d7-efde48ca11ef',
|
||||||
|
}),
|
||||||
|
commit: z.string().openapi({
|
||||||
|
example: 'abc123',
|
||||||
|
}),
|
||||||
|
parent: z.string().optional().openapi({
|
||||||
|
example: 'abc122',
|
||||||
|
}),
|
||||||
|
subject: z.string(),
|
||||||
|
author: z.object({
|
||||||
|
name: z.string(),
|
||||||
|
email: z.string().email(),
|
||||||
|
date: z.string(),
|
||||||
|
}),
|
||||||
|
commiter: z.object({
|
||||||
|
name: z.string(),
|
||||||
|
email: z.string().email(),
|
||||||
|
date: z.string(),
|
||||||
|
}),
|
||||||
|
body: z.string().optional(),
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
.openapi({
|
||||||
|
required: ['changelogId', 'version', 'markdown', 'releasedAt'],
|
||||||
|
})
|
5
packages/schema/src/commit/index.ts
Normal file
5
packages/schema/src/commit/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export * from './base'
|
||||||
|
//export * from './byId'
|
||||||
|
export * from './create'
|
||||||
|
//export * from './list'
|
||||||
|
//export * from './update'
|
4
packages/schema/src/commit/list.ts
Normal file
4
packages/schema/src/commit/list.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { z } from '@hono/zod-openapi'
|
||||||
|
import { VersionOutput } from './base'
|
||||||
|
|
||||||
|
export const VersionListOutput = z.array(VersionOutput)
|
21
packages/schema/src/commit/update.ts
Normal file
21
packages/schema/src/commit/update.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { z } from '@hono/zod-openapi'
|
||||||
|
import { VersionOutput } from './base'
|
||||||
|
|
||||||
|
export const VersionUpdateOutput = VersionOutput
|
||||||
|
export const VersionUpdateInput = z
|
||||||
|
.object({
|
||||||
|
markdown: z.string().optional(),
|
||||||
|
status: z
|
||||||
|
.enum(['draft', 'review', 'published'])
|
||||||
|
.default('draft')
|
||||||
|
.optional(),
|
||||||
|
releasedAt: z.date().or(z.string()).optional().nullable(),
|
||||||
|
})
|
||||||
|
.openapi({})
|
||||||
|
export const VersionUpdateParams = z
|
||||||
|
.object({
|
||||||
|
id: z.string().uuid(),
|
||||||
|
})
|
||||||
|
.openapi({
|
||||||
|
required: ['id'],
|
||||||
|
})
|
@ -3,3 +3,4 @@ export * from './user'
|
|||||||
export * from './changelog'
|
export * from './changelog'
|
||||||
export * from './version'
|
export * from './version'
|
||||||
export * from './page'
|
export * from './page'
|
||||||
|
export * from './commit'
|
||||||
|
Loading…
Reference in New Issue
Block a user