implement tool for publishing packages from a mono-repo #1
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't looked at the exact implementation yet. I'll do that when I get to the AirBnB.
"dependencies": { | ||
"@fixture/public-dep": "^0.0.1" | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love all these test fixtures. Is @fixture
a reserved namespace or just something you chose to use just for testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's just something I made up fro testing... nothing actually gets published as part of the test tests.
} else { | ||
console.log(`would run: ${command}`); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No exit code for a successful run?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm going to add a process.exit(0);
but it has to come right at the end of the try
block.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or after the catch?
@@ -0,0 +1,22 @@ | |||
{ | |||
"name": "antwerp", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it, but why antwerp
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming things is hard. I started out with pubtools but then I thought I'd change it to pubtool since this is really only one tool, but that's already taken. I started thinking about pubs I've been in in videos games and there was one in Hero's Quest I (aka Quest for Glory I) where you have to say a secret password to the goon guarding the entrance to the thieves' guild. One of the passwords was antwerp
. I'm open to better names as this name is not very descriptive and only tangentially related to the task that the tool performs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, antwerp
is the name of this creature in the game:
In my journey through Benelux in the spring I visited Antwerp the city which has this really old wooden escalator which leads to a tunnel that you can walk, bike, motorbike through. Unsurprisingly it smells really woody. If you're ever in Antwerp it's a must see... along with the MAS.
package.json
Outdated
{ | ||
"name": "antwerp", | ||
"version": "0.0.1", | ||
"description": "", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Definitely needs a description! 😁
"npm publish --access=public packages/public-dep", | ||
"git tag @fixture/public-pkg@0.0.1", | ||
"npm publish --access=public packages/public-pkg", | ||
]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the ease with which we can test this without necessarily having to run it fully although there's no substitute for actually running and checking those outputted commands really work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's tough b/c there isn't a good way to mock out npm
. At least with git
I can run commands locally and verify things about the state of the local repo.
|
||
// We assume that if a there's a tag for the current version of a package that | ||
// it's been published already. In the future we should check if that version | ||
// exists on npm and attempt to republish the package if it isn't. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Capture that in an issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Captured in #3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can update the comment to link back to the GitHub issue.
src/utils.js
Outdated
// Check that depedency versions are satisified | ||
// TODO: fallback to check if any tags exist that would satisfy the dep | ||
if (!semver.satisfies(pkgVerMap[depName], deps[depName])) { | ||
throw new Error(`${depName}@${pkgVerMap[depName]} doesn't satify ${depName}@${deps[depName]}`) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: "satify" should be "satisfy"
src/utils.js
Outdated
throw new Error(`${depName}@${pkgVerMap[depName]} doesn't satify ${depName}@${deps[depName]}`) | ||
} | ||
|
||
// Check to see if any depedencies of public packages are private |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NIT: "depedencies" should be "dependencies"
child_process.execSync("git push --tags"); | ||
} else { | ||
console.log(`would run: git push --tags`); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel like the text git push --tags
should be in a constant, and then there should be an maybeRunCommand
command that takes that string like this:
function (command, description) {
console.log(description);
const isDryRun = argv["dry-run"];
if (isDryRun) {
console.log(`would run: ${command}`);
} else {
child_process.execSync(command);
}
}
That way we can reuse this for any command.
const semver = require("semver"); | ||
|
||
function getTags() { | ||
return child_process.execSync(`git tag`, {encoding: "utf8"}).split("\n").filter(Boolean); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find these chains easier to read if they are lined up by the dots.
return child_process
.execSync...
.split...
.filter...
YMMV
function getWorkspaces() { | ||
const pkgJson = JSON.parse(fs.readFileSync("package.json", "utf8")); | ||
return pkgJson.workspaces.reduce((result, wsGlob) => { | ||
return result.concat(glob.sync(wsGlob)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
braces and return
are redundant.
// bumps the version automatically | ||
commands.push(`npm publish --access=public ${workspace}`); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this getCommands
call is actually doing some useful stuff. I wonder if it is clear from the name.
Perhaps generateCommandList
or something would be better?
Certainly should add a comment that explains what it's doing.
- Returns command list for tagging and publishing all public packages
const newVersion = semver.inc(json.version, release); | ||
json.version = newVersion; | ||
fs.writeFileSync(pkgJsonPath, JSON.stringify(json, null, 4)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this is the step that we don't do with antwerp
. antwerp
assumes you've done all the version changes that you need to and then just ensure that things are tagged with those versions before publish, after asserting that the dependencies are available for those packages.
Is that right?
pkgVerMap[pkgJson.name] = pkgJson.version; | ||
depMap[pkgJson.name] = pkgJson.dependencies || {}; | ||
pkgJsonMap[pkgJson.name] = pkgJson; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, this loop is ensuring that even though the dependency may not exist yet (because it's on a version of the package that isn't released), it will when antwerp
is finished. Right?
Can we get this loop in its own method to make that a little clearer?
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, this needs to be its own function too, I think. Either the whole loop or its contents.
getTags, | ||
getCommands, | ||
getWorkspaces, | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any thoughts on supporting use-cases that want to consume this as an API versus a tool?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think there's a little refactoring to do just to get things clearer.
We have a new workflow that we're going to try with |
The reason for creating this tool is that
lerna
does a couple of things things which we'd like to avoid with publishing packages from the wonder-blocks mono-repo:lerna
to automatically bump the version of packages that depend on it… this feels fundamentally wrong since the dependee may not be ready to use the updated version of the dependency. Also, if the dependee is using version ^1.0.0 and the dependency is bumped to 1.1.0, then there's no reason the update the dependee's version.lerna
is responsible for bumping versions (as well as publishing) which means that you have to commit changes without bumping versions. In repos that publish a single package this is fine b/c other packages can’t rely on in between states. This is different in mono-repos b/c you may change the version of a dependency in the same commit that you change a package to rely on that new version. This means that we should be bumping versions in the same commit that we’re making this change. This avoids having commits in the repo that you can never checkout and run b/c of an inconsistent state. The publish (and tagging) can and should be done in a separate commit.TODO:
Test Plan:
yarn test
npm link
foo
andbar
packages inworkspaces-test
and commit changesantwerp --dry-run
fromworkspaces-test
folder@kevinbarabash/foo@0.1.10
and@kevinbarabash/bar@0.1.11
and publish@kevinbarabash/foo
and@kevinbarabash/bar
packages. Notice that it doesn't try to bump or publish@kevinbarabash/foobar
which relies on version^0.1.0
of both of those packages.antwerp
again without the--dry-run
flag and verify that it's published those packages to https://npmjs.org/~kevinbarabash and that the most recent commit has indeed been tagged appropriately.