Make overwriting artifacts configurable
I am working on publishing our example bundles and wanted to be able to publish the bundle only if it's a new bundle version. I don't want to overwrite an existing bundle, because it should instead be published to a new version. Accidentally overwriting existing bundle versions is the mess that I'm trying to get myself out of, because incompatible versions of porter were pushed to bundle versions that people were using already.
In development, it totally makes sense to push over an existing tag, but I feel like that isn't the best default. Or at least I should have a way to have porter prevent me from dorking up an existing bundle.
There are a couple scenarios that would be great to handle:
- I call porter publish and the bundle is exactly the same as what is already published. When overwrites are not configured, porter should tell me that the bundle is the same (i.e. it really doesn't need to be pushed again). Porter should return 0 (success) since really it's already pushed and that's what I wanted.
- I call porter publish and the bundle is different from what's already published. It could be because the bundle.json has changed, or perhaps I'm building with a different version of Porter or with different bundle contents, so the hash of the bundle is different. When overwrites are not configured, porter should return an error instructing me to bump the bundle version.
I realize that docker overwrites by default but while that's a great default for dev machines, it's not a safe default IMO. I would prefer that we are inconsistent in this area and instead are safe by default. If they really want to overwrite, following git's lead and requiring a --force flag would work and still fit with a lot of developers mental model.
ALL IN on this. Provide a --force if people really wanna, but by default fail out. YAASSSSSS
I'd really like to see the --force flag on publish before v1 since it's a breaking change. The more nuanced error messages can happen post v1.
I agree that the default behavior should return an error instead of overwrite the existing bundle
Here are some notes based on what I have learned about diffing a local and remote image:
- Neither the id, content digest, or layer digests from
docker image inspect LOCAL(local image) anddocker manifest inspect REMOTEcan be used to compare since the digests are different between a machines due to hashing algorithms and compression differences. - The only way to compare images are either via the repository digest, or with a tool like container-diff, which extracts and standardizes the contents of the image for comparison.
- The performance of container-diff is prohibitive to run on every command that pushes to a registry. Just for porter-hello, it takes 13s against a local registry.
So for now this is what we can do:
When porter goes to push to a registry, if a repository digest is present, we can compare it to the destination and if they are the some, not return an error and just exit early since it's already pushed. Otherwise, when the repo digest is not present, for example because we built it locally and have never pushed it from this machine, we have to assume that it is different and require --force to proceed.
The smarter comparison is cool, but too slow to use.
Closed by #2331.