ekohacks 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -106,6 +106,7 @@ if (subcommand === 'ship') {
106
106
  changelog,
107
107
  pkg,
108
108
  gh: GhWrapper.create(),
109
+ git: GitWrapper.create(),
109
110
  npm: NpmWrapper.create(),
110
111
  confirm,
111
112
  narrate,
@@ -11,12 +11,13 @@ export class GitWrapper {
11
11
  return stdout;
12
12
  });
13
13
  }
14
- static createNull({ branch = 'main', dirty = false, behindOrigin = false, existingBranches = [], } = {}) {
14
+ static createNull({ branch = 'main', dirty = false, behindOrigin = false, existingBranches = [], versionOnMain = '0.0.0', } = {}) {
15
15
  const outputs = {
16
16
  'rev-parse --abbrev-ref HEAD': `${branch}\n`,
17
17
  'status --porcelain': dirty ? ' M some-file.ts\n' : '',
18
18
  'rev-parse main': behindOrigin ? 'local\n' : 'shared\n',
19
19
  'rev-parse origin/main': 'shared\n',
20
+ 'show origin/main:package.json': `${JSON.stringify({ version: versionOnMain })}\n`,
20
21
  };
21
22
  for (const existing of existingBranches) {
22
23
  outputs[`branch --list ${existing}`] = ` ${existing}\n`;
@@ -38,6 +39,13 @@ export class GitWrapper {
38
39
  async branchExists(branch) {
39
40
  return (await this.runGit(['branch', '--list', branch])).trim() !== '';
40
41
  }
42
+ // The version main carries on origin, not in this checkout: the Release targets
43
+ // GitHub's main, so a stale local package.json must not answer for it.
44
+ async versionOnMain() {
45
+ await this.runGit(['fetch', 'origin', 'main']);
46
+ const manifest = await this.runGit(['show', 'origin/main:package.json']);
47
+ return JSON.parse(manifest).version;
48
+ }
41
49
  async mainInSyncWithOrigin() {
42
50
  await this.runGit(['fetch', 'origin', 'main']);
43
51
  const local = (await this.runGit(['rev-parse', 'main'])).trim();
@@ -35,6 +35,7 @@ export const release = async ({ version, changelog, lockfile, pkg, git, npm, gh,
35
35
  changelog,
36
36
  pkg,
37
37
  gh,
38
+ git,
38
39
  npm,
39
40
  confirm,
40
41
  confirmRelease: skippable,
@@ -1,12 +1,19 @@
1
1
  import { setTimeout as delay } from 'node:timers/promises';
2
2
  import { changelogEntryFor } from './changelog.js';
3
3
  import { GhWrapper } from '../infrastructure/gh.js';
4
+ import { GitWrapper } from '../infrastructure/git.js';
4
5
  import { NpmWrapper } from '../infrastructure/npm.js';
5
- // The tail of RELEASING.md as a policy: cut the GitHub Release, approve the publish
6
- // gate, follow the run to green, and only report success once the registry serves the
7
- // version. The one human decision stays human: the gate is never approved without the
8
- // confirm answering yes.
9
- export const ship = async ({ version, changelog, pkg, gh, npm, confirm, confirmRelease = () => Promise.resolve(true), narrate, pollDelayMs = 15_000, findRunAttempts = 8, registryAttempts = 20, workflow = 'publish.yml', }) => {
6
+ // The tail of RELEASING.md as a policy: refuse a cut that has not landed on main, cut
7
+ // the GitHub Release, approve the publish gate, follow the run to green, and only
8
+ // report success once the registry serves the version. The one human decision stays
9
+ // human: the gate is never approved without the confirm answering yes.
10
+ export const ship = async ({ version, changelog, pkg, gh, git, npm, confirm, confirmRelease = () => Promise.resolve(true), narrate, pollDelayMs = 15_000, findRunAttempts = 8, registryAttempts = 20, workflow = 'publish.yml', }) => {
11
+ const onMain = await git.versionOnMain();
12
+ if (onMain !== version) {
13
+ return {
14
+ stopped: `main carries ${onMain ?? 'no version'}, not ${version}: the cut looks unfinished, run ekohacks release cut ${version}`,
15
+ };
16
+ }
10
17
  const tag = `v${version}`;
11
18
  if (!(await confirmRelease(`cut release ${tag}?`))) {
12
19
  return { stopped: 'release not approved' };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ekohacks",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "The EkoHacks CLI: our everyday operations, automated one small command at a time.",
5
5
  "repository": {
6
6
  "type": "git",