Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support single-purpose repos #84

Merged
merged 1 commit into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/format-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ jobs:
node-version: lts/*
cache: yarn
- run: yarn install
- run: yarn format-check
- run: yarn format:check
28 changes: 14 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# moker [![npm](https://img.shields.io/npm/v/moker)](https://www.npmjs.com/package/moker)

**No more struggles setting up monorepos. Kick-start monorepos, workspaces and
tooling:**
**No more struggles setting up new JavaScript repository. Kick-start
single-purpose repos, monorepos, monorepo workspaces and common tooling:**

```bash
# initialize a monorepo
yarn dlx moker create my-monorepo
cd my-monorepo
yarn dlx moker create --monorepo my-repo
cd my-repo

# install common tools
yarn moker use prettier husky lint-staged doctoc semantic-release
Expand All @@ -18,10 +18,10 @@ yarn moker add --template cra client

## Features

- 👢 Kick-start a monorepo with ease
- 🧰 Monorepo plugins to use pre-configured common tooling
- ➕ Add workspaces on demand
- 🧬 Workspace templates for a library, React app, API or CLI
- 👢 Kick-start a new repo or monorepo using Yarn
- 🧰 Plugins to use pre-configured common tooling
- ➕ Quickly add workspaces to a monorepo
- 🧬 Workspace templates for a shared library, React app, API or CLI
- ⚡ Extensible, bring your own plugins

> 🤓 The core plugins make some assumptions you may not agree with. If that's
Expand Down Expand Up @@ -69,7 +69,7 @@ yarn moker add --template cra client

## Prerequisites

You will need Node v14+ and Yarn v3+ in order to use `moker`.
You will need Node v14+ and Yarn v2+ in order to use `moker`.

- Install Node with [nvm](https://github.com/nvm-sh/nvm#install--update-script)
or using [nodesource](https://github.com/nodesource/distributions#debinstall).
Expand All @@ -84,7 +84,7 @@ You will need Node v14+ and Yarn v3+ in order to use `moker`.
Create a new monorepo:

```bash
yarn dlx moker create my-repo
yarn dlx moker create --monorepo my-repo
```

This will initialize a new monorepo in the `my-repo` directory.
Expand Down Expand Up @@ -197,7 +197,7 @@ level.

## `jest` _workspace_

This plugin sets up [Jest](https://jestjs.io) and adds a `test` and `watch:test`
This plugin sets up [Jest](https://jestjs.io) and adds a `test` and `test:watch`
script to both the workspace and the monorepo.

## `lint-staged` _monorepo_
Expand Down Expand Up @@ -238,7 +238,7 @@ _Current plan:_
- We can remove .npmrc file
- We need to modify .yarnrc.yml / .releaserc.json
- We can get rid of `"publishConfig"` in workspaces pkg
- We need to change `prepublishOnly` to `prepublish`
- [x] We need to change `prepublishOnly` to `prepublish`
- Document weird command (esp. JSON string echo)
- npm whoami fix not needed!

Expand Down Expand Up @@ -288,7 +288,7 @@ If you have the `husky` plugin installed, it will also add a pre-commit hook.
## `typescript` _workspace_

This plugin sets up [TypeScript](https://www.typescriptlang.org) and adds a
`build` and `watch:build` script to both the workspace and the monorepo.
`build` and `build:watch` script to both the workspace and the monorepo.

# Available templates

Expand Down Expand Up @@ -324,10 +324,10 @@ Contributions are very welcome!

## Roadmap

- [ ] Adapt for non-monorepo use-cases (WIP)
- [ ] Add LICENSE file to monorepo
- [ ] Support for `swc`/`esbuild`
- [ ] A compat lib (which builds cjs and mjs targets)
- [ ] Adapt for non-monorepo use-cases (?)
- [ ] Blog post / tutorial
- [ ] Docs for writing custom plugins / templates
- [x] github-actions plugin
Expand Down
2 changes: 1 addition & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@
| :------------------------------------------------------------------------- | :----: | :------------------------------------------------------------ |
| [packages/core/src/yarnrc.ts](packages/core/src/yarnrc.ts#L23) | 23 | etc, fix later |
| [packages/cli/src/commands/list.ts](packages/cli/src/commands/list.ts#L15) | 15 | list workspaces using https://yarnpkg.com/cli/workspaces/list |
| [packages/plugins/src/jest/jest.ts](packages/plugins/src/jest/jest.ts#L35) | 35 | install jest without ts-jest |
| [packages/plugins/src/jest/jest.ts](packages/plugins/src/jest/jest.ts#L31) | 31 | install jest without ts-jest |
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,12 @@
"scripts": {
"start": "node packages/cli/moker.js",
"build": "yarn workspaces foreach --topological --verbose run build",
"build:watch": "yarn workspaces foreach --parallel --interlaced run build:watch",
"test": "yarn workspaces foreach --topological --verbose run test",
"watch:build": "yarn workspaces foreach --parallel --interlaced run watch:build",
"watch:test": "yarn workspaces foreach --parallel --interlaced run watch:test",
"test:watch": "yarn workspaces foreach --parallel --interlaced run test:watch",
"postinstall": "husky install && node scripts/postinstall.js",
"format": "prettier --write --ignore-unknown .",
"format-check": "prettier --check --ignore-unknown .",
"format:check": "prettier --check --ignore-unknown .",
"doctoc": "doctoc README.md",
"todos": "leasot --exit-nicely --reporter markdown --ignore \"**/node_modules\" \"**/*.ts\" > TODO.md",
"release": "semantic-release"
Expand Down
6 changes: 3 additions & 3 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@
],
"scripts": {
"start": "node moker.js",
"prepublishOnly": "yarn clean && yarn build && cp ../../README.md .",
"prepublish": "yarn clean && yarn build && cp ../../README.md .",
"clean": "rm -rf dist && rm -rf types",
"build": "yarn clean && tsc",
"build:watch": "yarn build && tsc --watch",
"test": "jest",
"watch:build": "tsc --watch",
"watch:test": "jest --watch"
"test:watch": "jest --watch"
},
"dependencies": {
"@mokr/core": "workspace:*",
Expand Down
45 changes: 30 additions & 15 deletions packages/cli/src/commands/create.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import {
applyTemplate,
createMonorepo,
createRepo,
DEFAULT_LICENSE,
DEFAULT_SCOPED,
DEFAULT_WORKSPACES_DIRECTORY,
installPlugin,
isReadableAndWritableDirectory,
loadAllPlugins,
runDependencyQueues,
task,
Expand All @@ -13,42 +15,55 @@ import { command } from "bandersnatch";
import { resolve } from "node:path";

export const create = command("create")
.description("Create a new monorepo")
.description("Create a new repo")
.argument("path", {
description: "Monorepo path, basename will be used as the monorepo name.",
prompt: "What is the name of your monorepo?",
description: "Repo path, basename will be used as the name.",
prompt: "What is the name of your repo?",
})
.option("monorepo", {
description: "Create a monorepo instead of a single-purpose repo",
type: "boolean",
})
.option("template", {
description: "Use monorepo template",
description: "Use repo template",
type: "string",
})
.option("plugin", {
description: "Kick-start with this plugin",
type: "array",
default: [] as string[],
})
.option("scoped", {
description: "Use scoped packages",
boolean: true,
prompt: "Do you want to use scoped package names?",
default: DEFAULT_SCOPED,
})
.option("license", {
description: "License",
choices: ["MIT", "GPLv3"],
prompt: "What license do you want to publish your packages with?",
default: DEFAULT_LICENSE,
})
.option("workspacesDirectory", {
description: "Workspaces directory",
prompt: "Which directory should we save workspaces to?",
description: "Workspaces directory (only used with --monorepo)",
default: DEFAULT_WORKSPACES_DIRECTORY,
})
.action(async ({ path, template, plugin, ...options }) => {
.option("scoped", {
description: "Use scoped packages (only used with --monorepo)",
boolean: true,
default: DEFAULT_SCOPED,
})
.option("force", {
description:
"Initialize repo even if path already exists. WARNING: some files may be overwritten!",
type: "boolean",
})
.action(async ({ path, monorepo, template, plugin, force, ...options }) => {
const directory = resolve(path);
const type = monorepo ? "monorepo" : "repo";
const initializer = monorepo ? createMonorepo : createRepo;

if ((await isReadableAndWritableDirectory({ directory })) && !force) {
throw new Error(`${directory} already exists`);
}

await task(`Create new monorepo in ${directory}`, () =>
createMonorepo({ directory, ...options })
await task(`Create new ${type} in ${directory}`, () =>
initializer({ directory, ...options })
);

if (template) {
Expand Down
6 changes: 3 additions & 3 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
"types"
],
"scripts": {
"prepublishOnly": "yarn build",
"prepublish": "yarn build",
"clean": "rm -rf dist && rm -rf types",
"build": "yarn clean && tsc",
"build:watch": "yarn build && tsc --watch",
"test": "jest",
"watch:build": "tsc --watch",
"watch:test": "jest --watch"
"test:watch": "jest --watch"
},
"dependencies": {
"chalk": "5.1.2",
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from "./json.js";
export * from "./monorepo.js";
export * from "./package.js";
export * from "./plugin.js";
export * from "./repo.js";
export * from "./template.js";
export * from "./utils/index.js";
export * from "./workspace.js";
Expand Down
49 changes: 19 additions & 30 deletions packages/core/src/monorepo.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import { join } from "node:path";
import { isReadableAndWritableDirectory } from "./directory.js";
import { hasPackage, Package, readPackage, writePackage } from "./package.js";
import { enqueueInstallDependency, initYarn } from "./yarn.js";
import { Package, readPackage } from "./package.js";
import {
createRepo,
CreateRepoOptions,
DEFAULT_LICENSE,
isRepo,
} from "./repo.js";
import { addYarnPlugin } from "./yarn.js";

export const DEFAULT_SCOPED = true;
export const DEFAULT_LICENSE = "MIT";
export const DEFAULT_WORKSPACES_DIRECTORY = "packages";

export type MonorepoPackage = Package & {
Expand All @@ -19,50 +23,35 @@ type PkgOption = {
pkg: Package;
};

type CreateMonorepoOptions = DirOption & {
scoped?: boolean;
license?: string;
initialVersion?: string;
workspacesDirectory?: string;
};
export type CreateMonorepoOptions = DirOption &
CreateRepoOptions & {
scoped?: boolean;
workspacesDirectory?: string;
};

export async function createMonorepo({
directory,
scoped = DEFAULT_SCOPED,
license = DEFAULT_LICENSE,
workspacesDirectory = DEFAULT_WORKSPACES_DIRECTORY,
}: CreateMonorepoOptions) {
if (await isReadableAndWritableDirectory({ directory })) {
throw new Error(`${directory} already exists`);
}

await initYarn({ directory });

await writePackage({
await createRepo({
directory,
data: {
license,
license,
additionalPackageOptions: {
private: true,
workspaces: [`${workspacesDirectory}/*`],
moker: {
scoped,
plugins: [],
},
scripts: {
build: "echo 'not implemented'",
test: "echo 'not implemented'",
},
},
});

enqueueInstallDependency({
directory,
identifier: "moker",
dev: true,
});
await addYarnPlugin({ directory, name: "workspace-tools" });
}

export async function isMonorepo({ directory }: DirOption) {
if (!(await hasPackage({ directory }))) {
if (!(await isRepo({ directory }))) {
return false;
}

Expand Down
Loading