Skip to content
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 apps/cli/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@c0upons/cli",
"version": "0.1.0",
"version": "1.2.0",
"description": "c0upons CLI — search, submit, and manage coupons from the terminal",
"type": "module",
"bin": {
Expand Down
11 changes: 10 additions & 1 deletion apps/cli/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
#!/usr/bin/env node
import { readFileSync } from 'node:fs';
import { Command } from 'commander';
import chalk from 'chalk';
import ora from 'ora';
import 'dotenv/config';

// Read the version rather than repeating it. A literal here is a second source
// of truth that nothing checks, and it had already drifted: package.json said
// 0.1.0 while the shipped CLI was on 1.2.0. Resolved relative to this module,
// so it works from src/ under tsx and from dist/ after a build.
const { version } = JSON.parse(
readFileSync(new URL('../package.json', import.meta.url), 'utf8')
) as { version: string };

const BASE_URL = process.env.C0UPONS_API_URL ?? 'https://c0upons.com';

const program = new Command();

program
.name('c0upons')
.description('Search, submit, and manage coupon codes from the terminal')
.version('0.1.0');
.version(version);

program
.command('search <query>')
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@c0upons/web",
"version": "0.1.0",
"version": "1.2.0",
"private": true,
"type": "module",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "c0upons",
"version": "0.1.0",
"version": "1.2.0",
"private": true,
"type": "module",
"packageManager": "pnpm@9.15.0",
Expand All @@ -19,7 +19,7 @@
"lint": "turbo run lint",
"typecheck": "turbo run typecheck",
"clean": "turbo run clean && rm -rf node_modules .turbo",
"test": "turbo run test",
"test": "node --test test/*.test.mjs && turbo run test",
"setup:hooks": "git config core.hooksPath .githooks && echo 'Git hooks configured'"
},
"devDependencies": {
Expand Down
48 changes: 48 additions & 0 deletions test/versions.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// The repo carries its version in more places than anyone can hold in their
// head, and they had already drifted apart: the root and both workspaces said
// 0.1.0, the shipped CLI said 1.2.0, and the git tag agreed with the CLI. The
// shell script is the one that users actually see (`c0upons version`), so a
// silent disagreement means the version someone reports in a bug is not the
// version of the tree it came from.
//
// Nothing derives these automatically — the shell script is downloaded
// standalone, so its version has to be a literal — which is exactly why it
// needs a check instead of a convention.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';

const read = (p) => JSON.parse(readFileSync(new URL(p, import.meta.url), 'utf8'));

const root = read('../package.json');
const web = read('../apps/web/package.json');
const cli = read('../apps/cli/package.json');

/** The literal the shipped shell CLI reports as `c0upons version`. */
function shippedCliVersion() {
const script = readFileSync(new URL('../apps/web/public/cli/c0upons', import.meta.url), 'utf8');
const match = /^VERSION="([^"]+)"$/m.exec(script);
assert.ok(match, 'could not find a VERSION="…" line in apps/web/public/cli/c0upons');
return match[1];
}

test('every workspace agrees with the root version', () => {
assert.equal(web.version, root.version, '@c0upons/web disagrees with the root package version');
assert.equal(cli.version, root.version, '@c0upons/cli disagrees with the root package version');
});

test('the shipped CLI reports the repo version', () => {
assert.equal(
shippedCliVersion(),
root.version,
'apps/web/public/cli/c0upons VERSION= is out of step with package.json — bump both, since the ' +
'script is served standalone and cannot read package.json at runtime'
);
});

// The upgrade path replaces the binary from this URL, so a CLI that points
// somewhere else would strand every installed copy on its current version.
test('the shipped CLI upgrades from the canonical URL', () => {
const script = readFileSync(new URL('../apps/web/public/cli/c0upons', import.meta.url), 'utf8');
assert.match(script, /https:\/\/c0upons\.com\/cli\/c0upons/);
});
Loading