Skip to content

Commit

Permalink
Merge branch 'master' into fix-bad-folder
Browse files Browse the repository at this point in the history
  • Loading branch information
illright committed Dec 27, 2024
2 parents 64ce7f2 + caa9ede commit 45dcacd
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .changeset/early-knives-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@steiger/pretty-reporter': minor
---

Make printed diagnostic location more readable
5 changes: 5 additions & 0 deletions .changeset/ten-weeks-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@feature-sliced/steiger-plugin': patch
---

Add an exception to the `insignificant-slice` rule when the only usage site is the App layer
70 changes: 70 additions & 0 deletions .github/workflows/bundle-size-trusted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# This is the trusted counterpart of the Bundle size workflow.
# It generates a report and posts a comment on the PR.

name: Bundle size (trusted)

on:
workflow_run:
workflows: [Bundle size]
types:
- completed

permissions:
pull-requests: write

jobs:
print:
name: Print the sizes
runs-on: ubuntu-latest
steps:
- name: Download the sizes
uses: actions/download-artifact@v4
with:
merge-multiple: true
path: '.'
github-token: ${{ secrets.GITHUB_TOKEN }}
run-id: ${{ github.event.workflow_run.id }}

- name: Create the report
id: create-report
uses: actions/github-script@v7
with:
result-encoding: string
script: |
function parseDuOutput(output) {
return Object.fromEntries(output.trim().split('\n').map(line => {
const [size, folderName] = line.split(/\s+/);
const [_packages, packageName, _dist] = folderName.split('/');
return [packageName, parseInt(size, 10)];
}));
}
function formatSize(sizeInBytes) {
if (sizeInBytes < 1000) {
return `${sizeInBytes} B`;
} else {
const sizeInKb = sizeInBytes / 1000;
return `${sizeInKb.toFixed(2)} KB`;
}
}
const fs = require('fs');
const sizes = parseDuOutput(fs.readFileSync(`sizes-${${{ toJson(github.base_ref) }}}.txt`, 'utf8'));
const sizesPR = parseDuOutput(fs.readFileSync(`sizes-${${{ toJson(github.head_ref) }}}.txt`, 'utf8'));
core.summary.addHeading('📊 Package size report', '3');
core.summary.addTable([
['Package', 'Before', 'After'].map((data) => ({ data, header: true })),
...Object.keys(sizes).map((packageName) => {
const size = sizes[packageName];
const sizePR = sizesPR[packageName];
return [packageName, formatSize(size), sizePR === size ? 'No change' : formatSize(sizePR)];
}),
]);
const report = core.summary.stringify();
core.summary.write();
return report;
- name: Post the report to the PR
uses: thollander/actions-comment-pull-request@24bffb9b452ba05a4f3f77933840a6a841d1b32b # v3.0.1
with:
message: ${{ steps.create-report.outputs.result }}
pr-number: ${{ github.event.workflow_run.pull_requests.number }}
comment-tag: bundle-size
44 changes: 44 additions & 0 deletions .github/workflows/bundle-size-untrusted.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# This workflow builds the packages on the base branch and the PR branch, and then records the sizes of the built packages.
# The size comparison is done in a separate workflow because this one can't leave PR comments.

name: Bundle size

on:
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
build:
name: Build on the base branch and the PR branch
strategy:
matrix:
branch:
- ${{ github.base_ref }}
- ${{ github.head_ref }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
ref: ${{ matrix.branch }}

- name: Setup
uses: ./.github/actions/setup

- name: Build the packages
run: turbo run build

- name: Collect sizes in bytes
id: sizes
run: du -sb packages/*/dist > sizes-${{ matrix.branch }}.txt

- name: Upload the sizes
uses: actions/upload-artifact@v4
with:
name: sizes-${{ matrix.branch }}
path: sizes-${{ matrix.branch }}.txt
53 changes: 53 additions & 0 deletions .github/workflows/pkg-pr-new.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Publish Approved Pull Requests to pkg.pr.new
on:
pull_request_review:
types: [submitted]

permissions:
contents: read
pull-requests: read

jobs:
check:
# First, trigger a permissions check on the user approving the pull request.
if: github.event.review.state == 'approved'
runs-on: ubuntu-latest
outputs:
has-permissions: ${{ steps.checkPermissions.outputs.result }}
steps:
- name: Check permissions
id: checkPermissions
uses: actions/github-script@v7
with:
result-encoding: string
# The approver must have write access to the repository to trigger the package preview.
script: |
const { data: { permission } } =
await github.rest.repos.getCollaboratorPermissionLevel({
...context.repo,
username: context.actor,
});
return permission === 'write' || permission === 'admin';
publish:
needs: check
# Publish the preview package only if the permissions check passed.
if: needs.check.outputs.has-permissions == 'true'
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4

- run: corepack enable
- uses: actions/setup-node@v4
with:
node-version: 22
cache: 'pnpm'

- name: Install dependencies
run: pnpm install

- name: Build
run: pnpm exec turbo build

- run: pnpm dlx pkg-pr-new publish './packages/*'
1 change: 1 addition & 0 deletions packages/pretty-reporter/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
"dependencies": {
"chalk": "^5.3.0",
"figures": "^6.1.0",
"picocolors": "^1.1.1",
"terminal-link": "^3.0.0"
}
}
18 changes: 9 additions & 9 deletions packages/pretty-reporter/src/format-single-diagnostic.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { relative } from 'node:path'
import figures from 'figures'
import terminalLink from 'terminal-link'
import chalk from 'chalk'
import pc from 'picocolors'
import type { Diagnostic } from '@steiger/types'

export function formatSingleDiagnostic(d: Diagnostic, cwd: string): string {
const x = d.severity === 'error' ? chalk.red(figures.cross) : chalk.yellow(figures.warning)
const s = chalk.reset(figures.lineDownRight)
const bar = chalk.reset(figures.lineVertical)
const e = chalk.reset(figures.lineUpRight)
const message = chalk.reset(d.message)
const autofixable = d.fixes !== undefined && d.fixes.length > 0 ? chalk.green(`${figures.tick} Auto-fixable`) : null
const location = chalk.gray(formatLocation(d.location, cwd))
const ruleName = chalk.blue(terminalLink(d.ruleName, d.getRuleDescriptionUrl(d.ruleName).toString()))
const x = d.severity === 'error' ? pc.red(figures.cross) : pc.yellow(figures.warning)
const s = pc.reset(figures.lineDownRight)
const bar = pc.reset(figures.lineVertical)
const e = pc.reset(figures.lineUpRight)
const message = pc.reset(d.message)
const autofixable = d.fixes !== undefined && d.fixes.length > 0 ? pc.green(`${figures.tick} Auto-fixable`) : null
const location = pc.underline(formatLocation(d.location, cwd))
const ruleName = pc.blue(terminalLink(d.ruleName, d.getRuleDescriptionUrl(d.ruleName).toString()))

return `
${s} ${location}
Expand Down
14 changes: 7 additions & 7 deletions packages/pretty-reporter/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import chalk from 'chalk'
import pc from 'picocolors'
import figures from 'figures'
import type { Diagnostic } from '@steiger/types'

Expand All @@ -7,7 +7,7 @@ import { s } from './pluralization.js'

export function formatPretty(diagnostics: Array<Diagnostic>, cwd: string) {
if (diagnostics.length === 0) {
return chalk.green(`${figures.tick} No problems found!`)
return pc.green(`${figures.tick} No problems found!`)
}

const errors = diagnostics.filter((d) => d.severity === 'error')
Expand All @@ -16,17 +16,17 @@ export function formatPretty(diagnostics: Array<Diagnostic>, cwd: string) {
let footer =
'Found ' +
[
errors.length > 0 && chalk.red.bold(`${errors.length} error${s(errors.length)}`),
warnings.length > 0 && chalk.yellow.bold(`${warnings.length} warning${s(warnings.length)}`),
errors.length > 0 && pc.bold(pc.red(`${errors.length} error${s(errors.length)}`)),
warnings.length > 0 && pc.bold(pc.yellow(`${warnings.length} warning${s(warnings.length)}`)),
]
.filter(Boolean)
.join(' and ')

const autofixable = diagnostics.filter((d) => (d.fixes?.length ?? 0) > 0)
if (autofixable.length === diagnostics.length) {
footer += ` (all can be fixed automatically with ${chalk.green.bold('--fix')})`
footer += ` (all can be fixed automatically with ${pc.bold(pc.green('--fix'))})`
} else if (autofixable.length > 0) {
footer += ` (${autofixable.length} can be fixed automatically with ${chalk.green.bold('--fix')})`
footer += ` (${autofixable.length} can be fixed automatically with ${pc.bold(pc.green('--fix'))})`
} else {
footer += ' (none can be fixed automatically)'
}
Expand All @@ -36,7 +36,7 @@ export function formatPretty(diagnostics: Array<Diagnostic>, cwd: string) {
diagnostics.map((d) => formatSingleDiagnostic(d, cwd)).join('\n\n') +
'\n\n' +
// Due to formatting characters, it won't be exactly the size of the footer, that is okay
chalk.gray(figures.line.repeat(footer.length)) +
pc.gray(figures.line.repeat(footer.length)) +
'\n ' +
footer +
'\n'
Expand Down
20 changes: 20 additions & 0 deletions packages/steiger-plugin-fsd/src/insignificant-slice/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ vi.mock('node:fs', async (importOriginal) => {
'/features/comments/ui/CommentCard.tsx': '',
'/features/comments/index.ts': '',

'/widgets/sidebar/ui/Sidebar.tsx': '',
'/widgets/sidebar/index.ts': '',

'/pages/editor/ui/EditorPage.tsx':
'import { Button } from "@/shared/ui"; import { Editor } from "./Editor"; import { CommentCard } from "@/features/comments"; import { UserAvatar } from "@/entities/user"',
'/pages/editor/ui/Editor.tsx':
Expand All @@ -43,6 +46,8 @@ vi.mock('node:fs', async (importOriginal) => {
'/pages/settings/index.ts': '',
'/pages/home/index.ts': '',
'/pages/category/index.ts': '',

'/app/layouts/BaseLayout.tsx': 'import { Sidebar } from "@/widgets/sidebar"',
},
originalFs,
)
Expand Down Expand Up @@ -95,6 +100,21 @@ it('reports no errors on a project with no insignificant slices', async () => {
expect((await insignificantSlice.check(root)).diagnostics).toEqual([])
})

it('reports no errors when the only usage of a slice is on the App layer', async () => {
const root = parseIntoFsdRoot(`
📂 widgets
📂 sidebar
📂 ui
📄 Sidebar.tsx
📄 index.ts
📂 app
📂 layouts
📄 BaseLayout.tsx
`)

expect((await insignificantSlice.check(root)).diagnostics).toEqual([])
})

it('reports errors on a project with insignificant slices', async () => {
const root = parseIntoFsdRoot(`
📂 shared
Expand Down
10 changes: 6 additions & 4 deletions packages/steiger-plugin-fsd/src/insignificant-slice/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ const insignificantSlice = {
if (targetLocationKeys.size === 1) {
const referenceLocationKey = [...targetLocationKeys][0]
if (unslicedLayers.includes(referenceLocationKey)) {
diagnostics.push({
message: `This slice has only one reference on layer "${referenceLocationKey}". Consider moving this code to "${referenceLocationKey}".`,
location: { path: join(root.path, sourceLocationKey) },
})
if (referenceLocationKey !== 'app') {
diagnostics.push({
message: `This slice has only one reference on layer "${referenceLocationKey}". Consider moving this code to "${referenceLocationKey}".`,
location: { path: join(root.path, sourceLocationKey) },
})
}
} else {
diagnostics.push({
message: `This slice has only one reference in slice "${referenceLocationKey}". Consider merging them.`,
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 45dcacd

Please sign in to comment.