Skip to content

Commit

Permalink
Add npm package (#400)
Browse files Browse the repository at this point in the history
  • Loading branch information
amacneil committed Feb 27, 2023
1 parent 7b085d2 commit 57a17ac
Show file tree
Hide file tree
Showing 17 changed files with 810 additions and 10 deletions.
35 changes: 34 additions & 1 deletion .github/workflows/ci.yml
Expand Up @@ -71,7 +71,7 @@ jobs:
- name: Upload build artifacts
uses: actions/upload-artifact@v3
with:
name: ${{ matrix.os }}-${{ matrix.arch }}
name: dbmate-${{ matrix.os }}-${{ matrix.arch }}
path: dist/dbmate-*

- name: Publish binaries
Expand Down Expand Up @@ -163,3 +163,36 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

npm:
name: NPM
runs-on: ubuntu-latest
needs: build

steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: 16
registry-url: https://registry.npmjs.org
cache: npm
cache-dependency-path: typescript/package-lock.json

- uses: actions/download-artifact@v3
with:
path: dist

- run: find dist

- run: npm ci
working-directory: typescript

- run: npm run generate
working-directory: typescript

- run: npm run publish
if: ${{ startsWith(github.ref, 'refs/tags/v') }}
working-directory: typescript
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_PUBLISH_TOKEN }}
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Expand Up @@ -2,7 +2,7 @@ name: Release

on:
push:
tags: 'v*'
tags: "v*"

jobs:
homebrew:
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
@@ -1,8 +1,10 @@
.DS_Store
.env
*.log
/.cache
/db
/dbmate
/dist
/testdata/db/schema.sql
/vendor
node_modules
20 changes: 12 additions & 8 deletions README.md
Expand Up @@ -52,6 +52,15 @@ For a comparison between dbmate and other popular database schema migration tool

## Installation

**NPM**

Install using [NPM](https://www.npmjs.com/):

```sh
$ npm install --save-dev dbmate
$ npx dbmate --help
```

**macOS**

Install using [Homebrew](https://brew.sh/):
Expand All @@ -62,7 +71,7 @@ $ brew install dbmate

**Linux**

Download the binary directly:
Install the binary directly:

```sh
$ sudo curl -fsSL -o /usr/local/bin/dbmate https://github.com/amacneil/dbmate/releases/latest/download/dbmate-linux-amd64
Expand Down Expand Up @@ -95,7 +104,7 @@ $ docker run --rm -it --network=host -v "$(pwd)/db:/db" ghcr.io/amacneil/dbmate

**Heroku**

To use dbmate on Heroku, the easiest method is to store the linux binary in your git repository:
To use dbmate on Heroku, either use the NPM method, or store the linux binary in your git repository:

```sh
$ mkdir -p bin
Expand All @@ -104,12 +113,7 @@ $ chmod +x bin/dbmate
$ git add bin/dbmate
$ git commit -m "Add dbmate binary"
$ git push heroku master
```

You can then run dbmate on heroku:

```sh
$ heroku run bin/dbmate up
$ heroku run bin/dbmate --help
```

## Commands
Expand Down
4 changes: 4 additions & 0 deletions typescript/.gitignore
@@ -0,0 +1,4 @@
/packages/@dbmate
/packages/dbmate/LICENSE
/packages/dbmate/package.json
/packages/dbmate/README.md
1 change: 1 addition & 0 deletions typescript/.npmrc
@@ -0,0 +1 @@
save-exact=true
3 changes: 3 additions & 0 deletions typescript/README.md
@@ -0,0 +1,3 @@
# Dbmate NPM package

This directory contains scripts to generate and publish the dbmate npm package.
120 changes: 120 additions & 0 deletions typescript/generate.ts
@@ -0,0 +1,120 @@
import { readFile, writeFile, copyFile, chmod, mkdir } from "fs/promises";
import { parse as parseYaml } from "yaml";
import rimraf from "rimraf";
import Handlebars from "handlebars";

type MatrixItem = {
os: string;
arch: string;
};

type PackageJson = {
version: string;
optionalDependencies: Record<string, string>;
};

// map GOOS to NPM
const OS_MAP: Record<string, string> = {
linux: "linux",
macos: "darwin",
windows: "win32",
};

// map GOARCH to NPM
const ARCH_MAP: Record<string, string> = {
amd64: "x64",
arm: "arm",
arm64: "arm64",
};

// fetch version number
async function getVersion(): Promise<string> {
const versionFile = await readFile("../pkg/dbmate/version.go", "utf8");
const matches = versionFile.match(/Version = "([^"]+)"/);

if (!matches || !matches[1]) {
throw new Error("Unable to detect version from version.go");
}

return matches[1];
}

// fetch github actions build matrix
async function getBuildMatrix() {
const contents = await readFile("../.github/workflows/ci.yml", "utf8");
const ci = parseYaml(contents);

return ci.jobs.build.strategy.matrix.include as MatrixItem[];
}

// copy and update template into new package
async function copyTemplate(
filename: string,
targetDir: string,
vars: Record<string, string>
) {
const source = await readFile(`packages/template/${filename}`, "utf8");
const template = Handlebars.compile(source);
await writeFile(`${targetDir}/${filename}`, template(vars));
}

async function main() {
// parse root package.json template
const version = await getVersion();
const rootPackage: PackageJson = JSON.parse(
await readFile("packages/dbmate/package.template.json", "utf8")
);
rootPackage.version = version;

// generate npm packages
const buildMatrix = await getBuildMatrix();
for (const build of buildMatrix) {
const jsOS = OS_MAP[build.os];
if (!jsOS) {
throw new Error(`Unknown os ${build.os}`);
}

const jsArch = ARCH_MAP[build.arch];
if (!jsArch) {
throw new Error(`Unknown arch ${build.arch}`);
}

const name = `@dbmate/${jsOS}-${jsArch}`;
const targetDir = `packages/@dbmate/${jsOS}-${jsArch}`;
const binext = jsOS === "win32" ? ".exe" : "";
const templateVars = { jsOS, jsArch, name, version };

// generate package directory
console.log(`Generate ${name}`);
await rimraf(targetDir);
await mkdir(`${targetDir}/bin`, { recursive: true });
await copyTemplate("package.json", targetDir, templateVars);
await copyTemplate("README.md", targetDir, templateVars);

// copy binary from github actions artifact
const binfile = `${targetDir}/bin/dbmate${binext}`;
await copyFile(
`../dist/dbmate-${build.os}-${build.arch}/dbmate-${build.os}-${build.arch}${binext}`,
binfile
);
await chmod(binfile, 0o755);

// record dependency in root package
rootPackage.optionalDependencies[name] = version;
}

// write root package.json
await writeFile(
"packages/dbmate/package.json",
JSON.stringify(rootPackage, undefined, 2)
);

// copy readme and license
await copyFile("../LICENSE", "packages/dbmate/LICENSE");
await copyFile("../README.md", "packages/dbmate/README.md");
}

main().catch((e) => {
console.error(e);
process.exit(1);
});

0 comments on commit 57a17ac

Please sign in to comment.