Skip to content

Commit

Permalink
feat: CLI Publish Command & Scaffolding
Browse files Browse the repository at this point in the history
* chore: migrate config to dedicated file

* chore: remove process environmental variables

* chore: migrate packages to deps, add initial publish CLI

* chore: fix cjs, esm, and ts usage

* feat: add in functional CLI to publish packages

* chore: export packages and bundles

* docs: add initial docs for CLI tool

* chore: add commander to generate a functional CLI
  • Loading branch information
crutchcorn authored Dec 31, 2023
1 parent 63f8103 commit 43925c4
Show file tree
Hide file tree
Showing 10 changed files with 673 additions and 1,274 deletions.
114 changes: 114 additions & 0 deletions bin/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#!/usr/bin/env node
import chalk from 'chalk'

const args = process.argv.slice(2)
import Liftoff from 'liftoff'
import minimist from 'minimist'
import v8flags from 'v8flags'
import interpret from 'interpret'
const argv = minimist(args)
import { pathToFileURL } from 'node:url'
import { createRequire } from 'node:module'
import { publish } from '../src/publish.js'
import { Command, Option } from 'commander'
import fs from 'node:fs'
import { dirname, join } from 'node:path'
import { fileURLToPath } from 'node:url'
const __dirname = dirname(fileURLToPath(import.meta.url))
const pkg = JSON.parse(
fs.readFileSync(join(__dirname, '../package.json'), 'utf8'),
)

const require = createRequire(import.meta.url)

async function requireOrImport(path) {
if (!path) return null
try {
return require(path)
} catch (e) {
if (pathToFileURL && e.code === 'ERR_REQUIRE_ESM') {
// This is needed on Windows, because import() fails if providing a Windows file path.
const url = pathToFileURL(path)
return import(url)
}
throw e
}
}

const Config = new Liftoff({
name: 'tanstack-config',
configName: 'tanstack.config',
extensions: interpret.jsVariants,
preload: 'esbuild-register/dist/node',
v8flags: v8flags,
})

function checkForConfigFile(configPath) {
if (configPath) return
console.error(
[
chalk.red('No tanstack.config.js file found!'),
"This may be because you're not passing the --config or --cwd flags.",
'If you are passing these flags, check that the path is correct.',
'',
'Otherwise, you can create a `tanstack.config.js` file in your project root.',
].join('\n'),
)
process.exit(1)
}

Config.prepare(
{
cwd: argv.cwd,
configPath: argv.config,
completion: argv.completion,
},
function (prepEnv) {
Config.execute(prepEnv, (env) => {
requireOrImport(env.configPath)
.then((configOpts) => {
const program = new Command()

program
.name('@tanstack/config')
.description(
'Configuration and tools for publishing and maintaining high-quality JavaScript packages',
)
.version(pkg.version)

if (configOpts) {
for (const key of Object.keys(configOpts)) {
program.setOptionValueWithSource(key, configOpts[key], 'config')
}
}

program
.command('publish')
.description(
'Publish your package with the current working directory',
)
.option(
'--cwd <dir>',
'Current working directory of the configuration file',
)
.option('--config <config>', 'The path to the configuration file')
.option('--tag <tag>', 'The tag to publish to')
.option('--branch <branch>', 'The branch to publish from')
.action((_str, opts) => {
checkForConfigFile(env.configPath)
return publish({
branchConfigs: configOpts.branchConfigs,
packages: configOpts.packages,
rootDir: configOpts.rootDir,
branch: opts.branch ?? process.env.BRANCH,
tag: opts.tag ?? process.env.TAG,
ghToken: process.env.GH_TOKEN,
})
})

program.parseAsync().catch(console.error)
})
.catch(console.error)
})
},
)
10 changes: 6 additions & 4 deletions src/config.js → config/tanstack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ import { resolve } from 'node:path'
import { fileURLToPath } from 'node:url'

/**
* List your npm packages here. The first package will be used as the versioner.
* @type {import('./types').Package[]}
* @type {import('../src/types.js').RunOptions["packages"]}
*/
export const packages = [
{
Expand All @@ -15,8 +14,7 @@ export const packages = [
]

/**
* Contains config for publishable branches.
* @type {Record<string, import('./types').BranchConfig>}
* @type {import('../src/types.js').RunOptions["branchConfigs"]}
*/
export const branchConfigs = {
main: {
Expand All @@ -34,4 +32,8 @@ export const branchConfigs = {
}

const __dirname = fileURLToPath(new URL('.', import.meta.url))

/**
* @type {import('../src/types.js').RunOptions["rootDir"]}
*/
export const rootDir = resolve(__dirname, '..')
68 changes: 67 additions & 1 deletion docs/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,70 @@ id: overview
title: Overview
---

// TODO: Write this
TanStack Config allows you to publish, update, and maintain your packages
without having to provide complex configuration.

# Required Pre-Requisites

The following tools are required to be installed on the system running TanStack Config scripts:

- [Node.js 18.17+](https://nodejs.org/en/download/current/)
- [Git CLI](https://git-scm.com/downloads)
- [GitHub CLI](https://cli.github.com/) (pre-installed on GitHub Actions CI/CD)
- [PNPM](https://pnpm.io/)

> PNPM is currently the only supported package manager for TanStack Config.
# Installation

To install TanStack Config, run the following command:

```bash
pnpm add --save-dev @tanstack/config
```

# Usage

You have two options for using TanStack Config:

- [CLI Usage](#cli-usage)
- [Programmatic Usage](#programmatic-usage)

## CLI Usage

To run the publish script for your package, run the following command:

```bash
pnpm run tanstack-config publish
```

## Programmatic Usage

To use the TanStack Config programmatically, you can import the `publish` function:

```ts
import { publish } from '@tanstack/config';

publish({
branchConfigs: configOpts.branchConfigs,
packages: configOpts.packages,
rootDir: configOpts.rootDir,
branch: process.env.BRANCH,
tag: process.env.TAG,
ghToken: process.env.GH_TOKEN,
})
.then(() => {
console.log('Successfully published packages!');
})
.catch(console.error)
```

> The programmatic usage is only available for ESM packages. To support this, you have to have:
>
> ```json
> {
> "type": "module"
> }
> ```
>
> in your `package.json` file and use `import` instead of `require`.
59 changes: 30 additions & 29 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,32 @@
"url": "https://github.com/sponsors/tannerlinsley"
},
"type": "module",
"types": "build/legacy/index.d.ts",
"main": "build/legacy/index.cjs",
"module": "build/legacy/index.js",
"types": "src/index.d.ts",
"module": "src/index.js",
"exports": {
".": {
"import": {
"types": "./build/modern/index.d.ts",
"default": "./build/modern/index.js"
"types": "./src/index.d.ts",
"default": "./src/index.js"
}
},
"./package.json": "./package.json"
},
"bin": {
"tanstack-config": "./bin/config.js"
},
"engines": {
"node": ">=18"
},
"preferGlobal": false,
"sideEffects": false,
"files": [
"src"
"src",
"bin"
],
"packageManager": "[email protected]",
"scripts": {
"cipublish": "node src/publish.js",
"cipublish": "node bin/config.js publish --cwd config",
"cipublishforce": "CI=true pnpm cipublish",
"prettier": "prettier --ignore-unknown '**/*'",
"prettier:write": "pnpm run prettier --write",
Expand All @@ -51,46 +58,40 @@
"devDependencies": {
"@commitlint/parse": "^17.6.5",
"@types/current-git-branch": "^1.1.6",
"@types/git-log-parser": "^1.2.3",
"@types/eslint": "^8.56.0",
"@types/git-log-parser": "^1.2.3",
"@types/jsonfile": "^6.1.4",
"@types/luxon": "^2.3.1",
"@types/node": "^18.15.3",
"@types/semver": "^7.3.13",
"@types/stream-to-array": "^2.3.3",
"@typescript-eslint/eslint-plugin": "^6.4.1",
"@typescript-eslint/parser": "^6.4.1",
"axios": "^0.26.1",
"bundlewatch": "^0.3.2",
"chalk": "^5.3.0",
"concurrently": "^8.2.1",
"cpy-cli": "^5.0.0",
"current-git-branch": "^1.1.0",
"esbuild-plugin-file-path-extensions": "^1.0.0",
"eslint": "^8.48.0",
"eslint-config-prettier": "^9.0.0",
"eslint-import-resolver-typescript": "^3.6.0",
"eslint-plugin-import": "^2.28.1",
"fs-extra": "^11.1.1",
"git-log-parser": "^1.2.0",
"jsdom": "^22.0.0",
"jsonfile": "^6.1.0",
"luxon": "^3.3.0",
"nx": "17.2.8",
"prettier": "^4.0.0-alpha.8",
"publint": "^0.1.15",
"rimraf": "^5.0.1",
"semver": "^7.3.8",
"stream-to-array": "^2.3.0",
"tsup": "8.0.1",
"type-fest": "^4.8.3",
"typescript": "^5.2.2"
},
"bundlewatch": {
"files": [
{
"path": "packages/*/build/umd/*.production.js"
}
]
"dependencies": {
"axios": "^0.26.1",
"chalk": "^5.3.0",
"commander": "^11.1.0",
"current-git-branch": "^1.1.0",
"esbuild-register": "^3.5.0",
"git-log-parser": "^1.2.0",
"interpret": "^3.1.1",
"jsonfile": "^6.1.0",
"liftoff": "^4.0.0",
"luxon": "^3.3.0",
"minimist": "^1.2.8",
"semver": "^7.3.8",
"stream-to-array": "^2.3.0",
"v8flags": "^4.0.1"
}
}
Loading

0 comments on commit 43925c4

Please sign in to comment.