It happened that a small bug in the remote helper caused a patch not to
merge correctly on push. Hence, I implemented a `rad-merge` tool for
these cases where we need to fix broken state.
Instead of having two types, we simply have one, called `Entry`, which
we rename from `Change`.
There was no real benefit to having two almost identical types, but lots
of added complexity. This patch simplifies the crate by removing one of
the types.
This change allows for files (blobs) to be embedded into COB entries.
This allows for things like image attachments in issue comments for example.
For now, we only enable this in the `issue` COB.
The way it works is that relevant COB actions carry metadata about which
files are attached to them; and we store those files as blobs inside the
COB entry's *tree* object, under an `embeds/` folder.
The `Embed<T>` type is used for the above, and either carries actual
content, or carries a content-id. Retrieving the actual content is as
simple as asking the repository for a blob with that content-id.
As a possible future extension, MIME types could be stored alongside the
files in a "metadata" file. This could help clients display the content
appropriately.
> I'm going to be making a set of breaking changes to COBs in order to
stabilize the data formats. This is hopefully a one-time change that
bundles various breaking changes.
All COBs have been reworked: issue, patch, id.
The changes included are:
* Revise the assign and tag actions to take a single list of
assignees/tags to set, instead of an "add" and a "remove" list. This
makes API usage simpler when editing issues, and simplifies the apply
function
* Rename "tags" to "labels", and the tag action to label. This is
because tag is confusing in the context of git, as it could mean a git
tag. Using label removes that confusion.
* Use DIDs instead of PublicKeys for assignees -- this is more
future-proof
* Modify the manifest file format in the COB tree. Mainly, remove the
`history_type` key which is redundant, and use camelCase for keys
* Flatten the `Thread` actions into the parent action type
* Ensure that operations on redacted objects do not fail, since
redactions could have happened concurrently
* Use a consistent naming scheme for actions, using `.` as separator
* Consolidate comment types and remove `CodeComment`, by adding an
optional `location` field to `Comment`
* Add many placeholder actions that are not yet implemented
To preserve backwards compatibility, a `legacy` module is created with
the old `apply` function. When loading the manifest, we check whether it
is a legacy COB or a "stable" COB, and in the legacy case, use the
legacy code to materialize the state and then convert the object into
the stable type. Eventually, we'll delete the legacy code.
It turns out that the CRDT formed by the union of Git DAGs
is enough to guarantee everything we need for COBs.
This changes the following things:
* COB operations no longer need to be commutative
* COB histories are traversed in the same deterministic order on all
replicas
* It's now possible to implement RSMs on top of COBs, eg. scripting
* Lamport clocks have been removed
* `radicle-crdt` is no longer a dependency of `radicle`
* COBs are no longer instances of `Semilattice`
* The `Ops` type was removed in favor of having `Op` contain multiple
actions
This new trait is used when only signing refs is needed, and not general
write access to a repository.
We also implement `ReadRepository` and `SignRepository` for
`DraftStore`.
The additional flexibility in choosing a backend for the COB store will
allow things like "draft" COBs that are stored in a different location,
without changing much of the logic.
This patch incorporates several important changes to code review:
* Code review verdict is no longer editable
* Made reviews redactable instead
* Renamed review top-level comment to "summary"
* Renamed inline comments to "comments"
* Made inline comments addressable by `EntryId`
* This is to allow for editing
* Removed inline comments from review creation
* Added a `CodeComment` action instead
* Removed `Semilattice` instance from `Review`
* Added a `EditReview` action instead to have more control
* Made it valid for revisions to be redacted concurrently with a review/merge
Most of these changes are needed to support proper inline code comments.
There were a few subtle issues with the apply logic of certain COBs
that should be fixed now.
Note that the underlying store guarantees exactly-once delivery, and so
it does not make sense to test idempotence at the patch level.
* `CodeLocation` had a `blob` and `commit` field. These are redundant,
since the review lives under a revision.
We also change the line range to be diff-compatible, with an old and
new range. The ranges are optional to account for different scenarios
like file deletion, move etc.
* `CodeComment` had redundant getters which were removed in favor of
public fields. We also remove the `timestamp` field, as it will be
the same as the review timestamp.
We test to make sure that in the event of concurrent operations,
traversal order is deterministic.
This required some changes to the testing infrastructure. We're also
able to simplify the `Actor` type that now has redundant functionality.
Simplify graph traversal and evaluation by building in some of the
functionality into `radicle-dag`, namely the pruning fold.
We avoid building vectors of graph nodes this way, and simply iterate
over the graph in one go.
Though these are perhaps not the final error types, we name them the same
across COBs and have them work the same way.
All COB modules now have a `Error` enum.
In a future change, we may want the `FromHistory` trait to support
multiple error types, eg. one for `apply` and one for `validate`.
This adds a simple `validate` function to COBs that is run on load. It
allows COBs to check whether they are valid, once all operations are
loaded, and return an error if not.
We change `Patch::latest` to always return something, because a patch is
malformed if it doesn't have at least one revision, and thus would not
load in the first place.
This also implies that there is a latest revision in the face of
concurrent updates.
Note that currently, traversal order for concurrent updates is still random.
This will be fixed in another patch.
Before this change, if a merge op referred to a commit that was not on
the default branch, the merge op and all descendant ops would be pruned.
This is a bad idea because the state of the default branch can change
*after* the merge op is created, which is out of the control of the
merge op author.
Therefore, instead of exiting, we keep processing ops (but ignore the
merge), in case the merge is invalid for this specific reason.
When applying a `Merge` action, we verify that the commit is in the
history of the default branch of that user.
Since this is not the case when issuing a `rad merge`, and since that
command is no longer needed with the push-based merge, we remove the
`rad merge` command completely.
Move `merges` from `Revision` to `Patch`, and key them by actor.
This ensures that only one merge is possible per actor. We also make
sure that only one revision can be merged at a time, and signal a
conflict if more than one revision is considered merged.
Finally, we make sure that merges have the same target-branch commit
to be considered equal.
Allows patches to have their state updated to `Merged` with a `git push`
to the default branch.
Currently, due to the limitations of the COB store, this requires a
linear search through all patches. This will eventually become a problem
when projects have thousands of patches, so we should look into
long-term solutions.
This change updates to the latest radicle-git-ext, which required a
few changes within the radicle family of crates.
One set of changes is that the radicle-git-ext crate subsumes
git-commit, git-trailers, and git-ref-format -- so all those imports
go through radicle-git-ext.
The commit code requires that parent `Oid`s point to commits, which
made some tests fail. One of the reasons for these failures is that
the patch tests used fabricated `Oid`s and so the verification would
fail. This is fixed by allowing the test context code to create
`PatchRequest`s that create valid commits.
The other reason for failure was that the identity `Action` passed an
`Oid` that pointed to a blob. This is fixed by removing that code and
making a note of it in documentation.
The final major change was moving the Refspec type into git-ref-format
and removing the AsRefspecs trait. The trait was not required and
could its usage could be replaced by simpler code.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This change ensures that we include as a parent to the initial commit
of a patch COB, the head of the branch we are proposing as a patch.
This was already happening for patch updates, but we forgot to also
include it for the initial patch revision.
This ensures that the code is always fetched alongside the patch.
If the reference did not exist it is not necessary to create a new
`sigrefs` entry. Check that the reference exists before removing from
the cob store and only sign if it did.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit fixes the inconsistency with the `rad patch` command,
which previously displayed an empty table when there were no issues. Now,
the CLI will display a message indicating that there are no issues to display.
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
This commit adds the cob state of either patches or issues to the
corresponding endpoint.
So we can either query a cob listing with the required state or expect
the default state.
And once filtered by cob state we paginate.
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
Add a test case showing that when a review is made with a None value
to an already set field, it will remove the original value.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This allows change commits to have more than one parent that isn't
part of the DAG.
We can use this to create dependencies towards git objects such as
commits, in the case of patch actions.
When a merge is applied to a patch, we check whether the threshold
of delegates has been reached, at which point we set the patch status
to `merged`.
This requires threading the identity document oid through the "apply"
process.
Revision IDs are globally unique. Users will be able to use the
Revision ID in place of its patch ID.
Make `rad merge` refuse to merge an older revision unless the `--force`
option is given.
Using LWWReg::from will always set the clock value to the default,
which can end up being used wrong.
Instead, introduce a constructor method `initial` to indicate that it
should be used on initial construction, while `new` should be used for
newer values of the register.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
Replaces pub accessors to struct fields with methods
Also creates some methods to compute necessary information
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
To be able to change the description of a patch revision, without the
need to create a new revision.
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
Using LWWReg::from was giving subsequent actions
the same clock value as their predecessors.
This resulted in a Reject not being able
to turn into an Accept on a second review of a patch.
The solution is to use the clock value that was produced for the Op
and pass that into new, avoiding the call to from.
Co-authored-by: Fintan Halpenny <fintan.halpenny@gmail.com>
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
We implement a new `Element` trait which allows for more complex output
to be drawn, such as vertical and horizontal stacks.
We adapt `Table` to work within this system.
We refresh the output of `rad patch show` to use these new tools.
For display purposes in the web client, we add with this commit the
some needed properties to the revisions in the patch endpoint.
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
The Reaction type needs to ensure that the `char` stored for its value
meets certain requirements -- via its `new` constructor.
To ensure Reaction is always constructed correctly, the `pub` accessor
is removed, and the Deserialize implementation is implemented by hand
-- as opposed to using derive.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
If Ops::try_from fails in from_history then it means that some
operations failed to be parsed.
If this happens, then a warning should be logged so that these failure
cases can be more easily traced.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
By introducing a small limitation: only allowing entries in the change
graph to be addressable, instead of individual operations; we
drastically simplify the CRDT implementation.
There are four advantages:
1. Op ids are just regular SHA-1s
2. There's no need for relative IDs, ops never refer to other ops within the
same commit
3. There's no need for a nonce, since commits can't collide, and neither can op IDs
4. `OpId` can just be an alias of `EntryId`
The disadvantage of course, is that we have to be mindful of how we
create op transactions, since each transaction creates an addressable
unit. For example, we must not include multiple patch revisions in the
same transaction.
Before this change, the identity document would be loaded for the
COB signer. This meant that a fork would be needed for that signer.
After this change, it's no longer necessary, since the identity doc
head is computed from available remotes.
While making those changes, it was also apparent that some of the
identity-related functions had bad names and error types, this
was fixed as well.
It's fairly easy for a user to (by mistake or intentionally) create two
operations with the same OpId. This patch makes it much less likely,
and ensures that if the OpId is equal, it's because the operations
are identical.
The olpc-json crate's CanonicalFormatter does not escape certain
control characters, including new lines. This means that when a COB
gets serialized that includes new lines, those new lines are
serialized verbatim. Upon deserialization `serde_json` -- and any
other JSON deserializer -- will fail due to the encounter of these
control characters.
This behaviour was prevented in radicle-link with the definition of
its own CanoncialFormatter that encodes the control characters
correctly.
Inline this definition of the formatter, under MIT license, to ensure
the correct and remove oplc-cjson.
The behaviour is checked using a multiline test in the issue COB.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
Instead of showing just public keys we need to show the fully qualified
spec for a NID which is prefixed by `did🔑` While we want to maintain
`Author` and `ActorId` for internal use.
Signed-off-by: Sebastian Martinez <me@sebastinez.dev>
The CLI commands and output use PublicKey, ActorId, and NodeId for
peer identifiers.
Instead Did should be standardised for use in CLI arguments and
outputs.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
In order to make identity changes where the threshold is higher than
1, it is necessary to gather signatures of delegates to surpass that
threshold.
To achieve this the Proposal cob is introduced for proposing changes
and gathering the signatures over those changes.
Once a quorum is reached the Proposal can be published, committing the
new identity document to storage.
Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
By using `0` as the clock value for an empty state (without operations),
we simplify transaction code. Previously, there was no clock value for
empty states, which meant that we had to sometimes use an `Option`.