Commit Graph

732 Commits

Author SHA1 Message Date
Ian Darrow 642a62437b Update WeightSlider.js to allow 0 weights (#1005)
This commit #811, allowing users to set the weights of node/edge types to 0.

The WeightSlider now sets the weight to 0 when its dragged to its minimum value.
The logic for converting between weights and sliders has also been made more robust,
and is more thoroughly tested.

In cases where we wanted to set the weight to 0 (e.g. backwards Reaction edges),
the default weight has been changed.

Test plan:
Loading the UI, check that the sliders still work as expected (dragging them changes the displayed weight, dragging to the far left sets weight to 0). Check that the weights are consumed as expected (setting weight for issues to 0 leads to no cred for issues). Check that the weights for backwards reaction edges now have 0 weight. `git grep "TODO(#811)"` returns no hits.
2019-02-10 13:41:00 -07:00
Dandelion Mané c6afe5f9d5
Fix a build break due to merge conflicts (#1082)
PR #1075 added a new EdgeType, and #1080 added a new field to EdgeTypes.
Both PRs merged and this broke the build.

This very trivial commit fixes the build breakage in a noncontroversial
way (copies the placeholder edge description used for every other edge
over).

Test plan: `yarn test` passes.
2019-02-07 14:27:15 -07:00
Ana Noemi 466d33e4e6 Add descriptions for EdgeTypes (#1080) 2019-02-07 12:15:32 -07:00
Ana Noemi 6a9be3b7f4
Revert "Add descriptions for EdgeTypes (#1074)" (#1079)
This reverts commit 1e78437f71.
2019-02-01 11:52:35 -08:00
Ana Noemi 1e78437f71
Add descriptions for EdgeTypes (#1074)
* Add descriptions for EdgeTypes

* Displays edge and node description tooltip in weight configuration UI

* Update tests
2019-01-30 15:48:22 -05:00
Brian Litwin 0254f54375
Update github example data (#1077)
Updating github example data with support
for 🚀 and 👀 reaction types.

This follows #1068 and @decentralion updating
the archived repo with the new reaction types.

`src/plugins/github/fetchGithubRepoTest.sh -u`
(as @decentralion suggested) updated `example-github.json`

`yarn unit` caught two tests with failing snapshot
tests (`createGraph.test` and `relationalView.test`), so
I updated those with `yarn unit -u`

`yarn test -full` caught a failing snapshot test
at `sharness-full`, resolved by updating the
snapshot in `view.json.gz` with
 `UPDATE_SNAPSHOT=1 yarn test --full`.
Thanks to @wchargin for the [explanation] on how
to resolve that issue.

[explanation]: https://github.com/sourcecred/sourcecred/pull/1077#pullrequestreview-196805017

**Test Plan:**
`yarn test --full` is passing.

Additionally, the commands:
```sh
    filepath="./sharness/__snapshots__/example-github-load/data/sourcecred/example-github/github/view.json.gz" &&
    [ -f "${filepath}" ] &&  # sanity check
    diff -u \
        <(git show "HEAD:${filepath}" | gzip -d | jq .) \
        <(gzip -dc "${filepath}" | jq .) \
        ;
```

yields the following output:

```
--- /dev/fd/63  2019-01-27 08:34:15.020387301 -0500
+++ /dev/fd/62  2019-01-27 08:34:15.021095696 -0500
@@ -654,6 +654,22 @@
               "subtype": "USER",
               "login": "decentralion"
             }
+          },
+          {
+            "content": "ROCKET",
+            "user": {
+              "type": "USERLIKE",
+              "subtype": "USER",
+              "login": "decentralion"
+            }
+          },
+          {
+            "content": "EYES",
+            "user": {
+              "type": "USERLIKE",
+              "subtype": "USER",
+              "login": "decentralion"
+            }
           }
         ]
       }

```

Again, thanks @wchargin's for providing those commands and accompanying
explanation.
2019-01-27 13:50:48 -05:00
Brian Litwin 61266cace7
Update reaction types (#1068)
Resolves #1054
Added "ROCKET" and "EYES" to the list of reaction types.
Added "ROCKET" as a valid cred signal, kept "EYES" invisible.

My approach was to use `git git grep THUMBS_UP '*.js'`
 and `git grep ThumbsUp '*.js'` to find all the relevant files,
as suggested in #1054

**Test Plan**

1) Inspecting Sourcecred/Mission's UI:
[#13] contains: GOT 🚀 FROM 1 user
@BrianLitwin contains: REACTED 🚀 TO 1 issue
@BrianLitwin contains: REACTED 🚀 TO #13

2) Yarn Test passes

3) `github/edges.test` includes a snapshot test to verify
that we can create an edge using ROCKET

4) @wchargin also noted that:

```sh
diff -u <(git grep -c 'THUMBS_UP' '*.js') <(git grep -c 'ROCKET' '*.js')
diff -u <(git grep -c 'ThumbsUp' '*.js') <(git grep -c 'Rocket' '*.js')
```

passes.

`graphql/mirror.test` now includes "ROCKET" and "EYES" in the  example
GithubSchema, but their inclusion has no effect
on any tests.

**Screenshots**
1.
<img width="378" alt="screenshot 2019-01-22 09 02 12" src="https://user-images.githubusercontent.com/26695477/51540428-6c87b600-1e24-11e9-8334-1d9d993dce01.png">
2.
<img width="525" alt="screenshot 2019-01-22 09 02 41" src="https://user-images.githubusercontent.com/26695477/51540472-84f7d080-1e24-11e9-8847-245c0c09ddd6.png">
<br>
Shoutout to [this comment], which saved me an untold amount of head-scratching,
and also @Decentralion's help debugging in the Issue thread.

[#13]: https://github.com/sourcecred/mission/issues/13
[this comment]: e0762303d4/src/plugins/github/graphqlTypes.test.js (L13-L15)
2019-01-24 06:24:22 -05:00
Ana Noemi e0762303d4 Add descriptions for NodeTypes (#1044)
* Add descriptions for NodeTypes

As highlighted by @decentralion in issue #807, we need descriptions for Node and
Edge types in the UI to explain to users what each Node and Edge type does. This
PR modifies the type definition for `NodeType` and adds a `+description: string`
field, then updates all NodeTypes throughout the codebase with descriptions.

Test plan:

Verify that all tests pass and the descriptions makes sense.
2019-01-21 16:16:56 -08:00
Dandelion Mané 5c2f232017
Expose the Graph's modification count (#1055)
This commit adds a new `modificationCount` method to `Graph`, which
exposes's that graph's modification count. This enables clients to write
cached data structures on top of Graph, knowing that they can
programatically detect when the cache has been invalidated.

Test plan: Unit tests have been addded; `yarn test` passes.

This commit is motivated by work on #1020.
2019-01-21 10:08:27 -08:00
Dandelion Mané e92f247305
Rename "AppAdapter" -> "ExplorerAdapter" (#1052)
There are two kinds of plugin adapters: adapters for doing cred
analysis, called "analysis adapters", and adapters for the cred
explorer, which are confusingly called "app adapters".

This commit decreases the confusion by renaming app adapters to explorer
adapters across the codebase. In a future commit, I will add
documentation to the adapter interfaces so that it is clearer to a
newcomer to the codebase why these interfaces exist.

Thanks to @BrianLitwin, who asked a question during [office hours]
that surfaced this issue.

[office hours]: https://github.com/sourcecred/mission/issues/12

Test plan: `yarn test` passes, suggests that this rename went off
without a hitch. Code review as a sanity check.

Also: grepping for `AppAdapter` returns 0 results:
```
$ git grep AppAdapter | wc -l
0
```

Note: After producing this commit, I can confirm that the word "adapter"
starts to look like utter gibberish after you type it often enough.
2019-01-19 17:02:31 -08:00
Dandelion Mané 2d8a25afc8
Add documentation for `NodeType` and `EdgeType` (#1043)
This commit adds some docstrings for the concepts of NodeType and
EdgeType. I also swapped the order so that `NodeType` comes first,
which is more consistent with usage across the codebase.

This commit makes no changes to the actual code; the only effects
are re-organization and documentation.

Test plan: `yarn test` && human inspection
2019-01-16 18:02:39 -08:00
William Chargin 989d1f359f
homepage: remove misleading CSS import (#1045)
Summary:
We use Aphrodite, not CSS imports, for styling. We do have a small
`index.css` file that is included during server-side rendering, and is
only referenced from `src/homepage/server.js`. But our `index.js` file
also has a superfluous `import "./style.css"`, which might suggest that
we support CSS imports more generally. This patch removes that import.

Thanks to @brianlitwin on Discord for pointing out that this might be
confusing.

Test Plan:
Verified that, under both `yarn start` and `yarn build`, the appearance
is the same, and the document still includes a `<style>` element with
the contents of `index.css` (which is included by `server.js`).

wchargin-branch: remove-css-import
2019-01-09 23:22:20 -08:00
Dandelion Mané 6a010291df
Add documentation to the Graph module (#1025)
* Add documentation to the Graph module

This commit adds a module-level docstring that gives an overview of the
Graph class and its importance to SourceCred, as well as adding
docstrings to specific methods.

Test plan:
In addition to review by the SourceCred maintainers, this should be
reviewed by at least one person who is not familiar with the codebase,
so that we can verify that it's actually working as documentation. :)

* Incorporate @wchargin's many suggestions.

Test plan: Human review.
2019-01-07 18:35:49 -08:00
Dandelion Mané 24895b3c7d
Make `yarn test` more quiet (#1037)
This commit adds a new runOption for execDependencyGraph, namely
`printVerboseResults`. If this flag is true, then execDependencyGraph
will print a "Full Results" section along with the standard error and
standard out of every task, regardless of whether it failed or
succeeded. (Note, this is the existing behavior for all invocations
prior to this commit).

If the flag is not true, then execDependencyGraph will not print a full
results section, and stdout/stderr will be logged only for tasks that
fail.

This commit also modifies `yarn test` to use the new flag so that it
prints verbose tests only when the `--full` option is provided. This is
consistent with our sharness behavior: we print the full sharness logs
only when `--full` was provided.

This fixes #1035, and ensures that running `yarn test` has a high signal
to noise ratio (i.e. it only shows an enumeration of top level tasks).
This improves the developer ergonomics of SourceCred by not having a
super commonly used and core script spam the user with mostly irrelevant
information.

Test plan:

Run `yarn test` when all tests are passing, and observe that the output
has much less noise:

```
yarn run v1.12.3
$ node ./config/test.js
tmpdir for backend output: /tmp/sourcecred-test-6337SZ9smvWsWvqE

Starting tasks
  GO   ensure-flow-typing
  GO   check-stopships
  GO   check-pretty
  GO   lint
  GO   flow
  GO   unit
  GO   backend
 PASS  check-stopships
 PASS  ensure-flow-typing
 PASS  flow
 PASS  backend
  GO   sharness
 PASS  sharness
 PASS  check-pretty
 PASS  lint
 PASS  unit

Overview
Final result:  SUCCESS
Done in 11.66s.
```

Run `yarn test` when there is a real failure (e.g. a unit test failure)
and observe that full details on the failure, including the output from
stdout/stderr, is still provided.

Run `yarn test --full` and observe that full, verbose logs are provided.
2019-01-05 18:16:29 -08:00
Brian Litwin 2b9cef66ed Add project title to explorer page (#1032)
Resolves #1027

Using `repoId.owner/repoId.name` for the project title
because that is how projects are identified on `PrototypePage`.

Created a `<ProjectDetail />` component inside `<App />`  that consumes a `RepoId`
and renders a title.

**Test Plan:**

Added two unit tests:

The first verifies that the parent `<App />` component
instantiates a `<ProjectDetai />` component with the correct props.
The current correct prop is a `RepoId` object.

The second test verifies that the `<ProjectDetail />` component renders
the title correctly given the `RepoId`, ie as a `<p>` element
with `repoId.owner/repoId.name` for text.

Visual tests verify that the title is above the Analyze Cred
button, and that clicking from one project to another renders
the appropriate title for separate projects.

Attaching a screenshot as a comment at #1032
for reference:

<img width="1253" alt="screenshot 2019-01-04 13 40 03" src="https://user-images.githubusercontent.com/26695477/50706562-34aeff00-102c-11e9-9c1c-6c1e3fa6c415.png">
2019-01-04 12:56:38 -08:00
Dandelion Mané 7c7fa2d83d
Graph: move invariant checker to bottom of class (#1026)
This moves the invariant checking code from the top of the Graph class
to the bottom. Most readers of this file will probably be more
interested in seeing the API, and reading the invariant checker first
is likely to be confusing and off-putting.

Test plan: `yarn test` suffices. No semantic change.
2019-01-03 14:15:40 -08:00
Dandelion Mané bbe773bb67
Elide assertValid & assertValidParts in production (#1017)
This commit substantially improves SourceCred's performance in
production.

Measurement methodology: I create a new tab in Chrome, navigate to my local
prototypes, and select go-ipfs. I then turn on profiling, and click the
analyze button, and then turn off profiling when analysis is done. I
then go to the "bottom-up" tab in the JS analysis box on the bottom and
sort by "Total Time".

__Before this commit:__

|        fn        | total time | time as % |
|:---------------- | ----------:| ---------:|
| assertValid      |      815ms |      8.6% |
| assertValidParts |      261ms |      2.7% |

__After this commit:__

|        fn        | total time | time as % |
|:---------------- | ----------:| ---------:|
| assertValid      |       21ms |      0.2% |
| assertValidParts |       23ms |      0.3% |

Test plan: `yarn test`, also performance measurement as described above.

Fixes #1011.
2018-12-01 17:33:44 -08:00
Dandelion Mané 973a72fe46
Update the blacklisted object ids (#1018)
This adds a blacklisted id for @greenkeeper, a bot which used to be a
user. This is a temporary fix until we solve #998.

Test plan: `yarn test` passes. Before this commit, attempting to load
`probot/probot` fails. After this commit, it succeeds.
2018-11-28 12:39:19 -08:00
Dandelion Mané 794b93e397
Improve performance of pagerank `decompose` (#1007)
When I implemented this function, I incorrectly assumed that
`lodash.sortBy` only calls subsequent accessor functions if there is a
tie from the first accessor. Actually, it calls it every time. We can
avoid lots of wasteful JSON.serialization by just grabbing the exact
properties of interest.

Test plan:

For correctness: `yarn test` suffices, as this functionality is already
tested.

For performance improvement: I ran the full load+analyze workflow, in
Chrome, on twbs/bootstrap. Before this change, decompose took 6.9s;
after this change, it takes 1.3s, for a 5.3x speedup.

Close #943.
2018-11-16 22:26:55 -08:00
William Chargin 80b458d719
core: allow repo ID registry to store metadata (#1003)
Summary:
Our registry was defined to simply be a list of IDs. This is
insufficiently flexible; we want to be able to annotate these IDs with,
e.g., last-updated times (#989). This commit wraps the entries in a
simple object, updating clients appropriately.

Test Plan:

  - Run `node ./bin/sourcecred.js load sourcecred/example-github` with a
    repository registry in the old format, and note that it errors
    appropriately.
  - Run `yarn build` with a repository registry in the old format, and
    note that it errors (“Compat mismatch”).
  - Delete the old registry and re-run the `load` command. Note that it
    runs successfully and outputs a registry. Run `yarn build`; note
    that this works.
  - Load data for two repositories. Run `yarn start`. Note that the list
    of prototypes still works, and that you can navigate to and render
    attributions for individual project pages.
  - Verify that `yarn test --full` passes.

wchargin-branch: repo-id-registry-metadata
2018-11-09 17:28:39 -08:00
William Chargin 332e776317
deps: upgrade `flow-bin@^0.86.0` (#1002)
Summary:
There have been some breaking changes that require new type annotations,
which is a good thing: these prevent `any`-leakage.

Test Plan:
Run `yarn flow`.

wchargin-branch: flow-v0.86.0
2018-11-09 09:24:40 -08:00
William Chargin 0a6eca7d79
link: verify that routes have trailing slash (#1001)
Summary:
This serves as a regression test for #1000.

Test Plan:
Note that `yarn unit` passes with this patch but fails if the change to
the code is reverted, or if the patch in #1000 is reverted. Note that
`yarn build` also passes but fails if the patch in #1000 is reverted.
Note also that `yarn test --full` passes.

wchargin-branch: link-verify-trailing-slash
2018-11-08 20:53:30 -08:00
William Chargin 24c1873dca
site: fix homepage link to prototypes page (#1000)
Summary:
Prior to this commit, clicking the in-copy link to the prototypes page
would raise a console error:

> Warning: [react-router] Location "/prototype" did not match any routes

Test Plan:
Run `yarn start` and click the link.

wchargin-branch: site-fix-homepage-prototype-link
2018-11-08 20:40:57 -08:00
William Chargin 897ba78d5c
site: fix prototypes page dimensions (#999)
Summary:
Prior to this commit, the prototypes page, which lists just a handful of
repositories, was rendered with a vertical scrollbar: you had to scroll
200px to see the version info. This is silly.

The `height: 100%` is necessary not to get it to fill up the whole page,
but to get it to _not_ fill up ~30 extra pixels. I have no idea why.

Test Plan:
Run `yarn start` and note that `/prototypes/` now renders without a
scrollbar, and with the version info in the bottom-right corner.

wchargin-branch: site-fix-prototypes-page-dimensions
2018-11-08 20:39:23 -08:00
Dandelion Mané 8666f9ac1a
cleanup: remove unused field on ScoredConnection (#994)
This resolves an outstanding TODO in pagerankNodeDecomposition to remove
the unused sourceScore field.

I have removed it, and it was indeed unused.

Test plan: `yarn test` passes.
2018-11-01 18:55:32 -07:00
William Chargin beccac822f
MapUtil: provide exact output from `toObject` (#993)
Summary:
The `MapUtil` map–object conversion functions used inexact objects for
both input and output. They are in fact stronger than that: they can
accept arbitrary inexact objects and return arbitrary exact outputs.
(Recall that exact objects are subtypes of their inexact counterparts,
so this is the maximally permissive combination.)

Test Plan:
Unit tests added. The “can return an exact object” test fails Flow
before this change. The other tests would have passed already.

wchargin-branch: maputil-exact-output
2018-11-01 18:55:14 -07:00
Dandelion Mané 252d8d5c99
Move repoIdRegistry to core (#992)
RepoIdRegistry is used across the project, but not in the explorer. So
it makes very little sense that it live in the explorer module. It's now
moved to core.

Test plan: `yarn test --full` passes
2018-11-01 18:11:48 -07:00
Dandelion Mané 6b8cb66013
Remove cred feedback url configurability (#991)
We added a configurable cred feedback url on the theory that we would
create a separate discourse post to collect feedback for each project in
particular.

We've now realized that no one is using this, so it's just vestigial
complexity now. So I'm removing the logic for configuring the feedback
url on a per-project basis.

Instead, we will always link to a Google form for collecting feedback.

Test plan: `yarn test --full` passes, and I manually checked the links.
2018-11-01 17:43:37 -07:00
Dandelion Mané 29065f44d6
Remove the repository select from explorer/ (#988)
Historically, a single cred explorer instance could load many different
repositories. This turned out to be an anti-feature: we'd rather have a
particular url hardlink to exploring the cred for a particular project.

This commit removes the repository select from the explorer, and instead
mandates that the explorer always has the RepoId passed down from above.
Besides providing a better UX, this also greatly simplifies the logic
for the explorer, since we no longer have an "initializing state" that
doesn't have any RepoId.

This builds on the work in #984, and swaps out the old "prototype" page
(which has been rendered non-functional by this change) for the new
"prototypes" page. Note that it stays at the same route, so links to
sourcecred.io/prototype will continue to function.

Test plan: Ran `yarn test --full`, and verified that `yarn start`
produces a working site.
2018-11-01 16:10:01 -07:00
William Chargin 738853cd02
homepage: render project-specific prototype pages (#984)
Summary:
Currently, we render simply render a placeholder. Soon, we’ll remove the
repository selector dropdown from the cred explorer, and render
project-specific cred attributions.

Test Plan:
Run `yarn start`. Navigate to `/prototypes/` and observe:

![Screenshot of `/prototypes/`](https://user-images.githubusercontent.com/4317806/47877810-03227900-ddda-11e8-9a17-28398d83059f.png)

Note that the links point to URLs like
`/prototypes/sourcecred/example-github`:

![Screenshot of a project page](https://user-images.githubusercontent.com/4317806/47877888-35cc7180-ddda-11e8-95db-9f5099e146a8.png)

Then, check that `yarn test --full` passes.

wchargin-branch: homepage-project-pages
2018-11-01 15:19:52 -07:00
William Chargin 665bb67e33
homepage: add prototypes listing (#983)
Test Plan:
Apply the following patch:

```diff
diff --git a/src/homepage/routeData.js b/src/homepage/routeData.js
index 32d3eb65..aac7fc9a 100644
--- a/src/homepage/routeData.js
+++ b/src/homepage/routeData.js
@@ -38,7 +38,10 @@ const routeData /*: $ReadOnlyArray<RouteDatum> */ = [
     path: "/prototypes/",
     contents: {
       type: "PAGE",
-      component: () => require("./PrototypesPage").default([]),
+      component: () =>
+        require("./PrototypesPage").default([
+          {owner: "sourcecred", name: "example-github"},
+        ]),
     },
     title: "SourceCred prototypes",
     navTitle: null, // for now
```

Then, load <http://localhost:8080/prototypes/> and see that there is an
entry in the list, and that it links to
<http://localhost:8080/prototypes/sourcecred/example-github/>. Note that
clicking the link raises a console error because there is no such route.

wchargin-branch: homepage-prototypes-page
2018-11-01 13:30:36 -07:00
Dandelion Mané a9db2b0919
webpack: expose repo registry at build time (#981)
Summary:
We want to remove the repository selector dropdown on the cred explorer
homepage and instead render a separate web page for each project. To do
this, we need to know which pages to render statically. We choose to
ingest this information from the state of the repository registry at
build time.

This commit adds an environment variable `REPO_REGISTRY` whose contents
are the stringified version of the repository registry, or `null` if
SourceCred has been built for the backend. This variable is defined with
Webpack’s `DefinePlugin`, so any code bundled by Webpack can refer to it
via `process.env.REPO_REGISTRY` both on the server and in the browser.

Paired with @wchargin.

Test Plan:
Sharness tests modified; running `yarn test --full` suffices.
2018-11-01 12:38:18 -07:00
Dandelion Mané 244c01d764
Move plugin choice from explorer to homepage (#979)
The explorer no longer ships with a set of default plugins. (This made
an inappropriate dependency from explorer/ to plugins/, and complicated
explorer's contract as a generic component.) Instead, the homepage
module is responsible for choosing the plugins to display on the
homepage.

Test plan: `yarn test --full` passes, and `yarn start` reveals a
functioning homepage and prototype.
2018-11-01 11:39:07 -07:00
Dandelion Mané 0ad1e0557f
Move `version.js` to core (#977)
Currently version is located in `homepage/`, which doesn't make much
sense, since it's versioning the whole project.

We move it to core.

Test plan: `yarn test --full`
2018-11-01 11:33:03 -07:00
William Chargin 64500f53cb
mirror: remove "demo" module (#978)
Summary:
This was used for ad hoc testing of the Mirror module before it was
integrated into SourceCred. We haven’t kept it up to date with schema
changes, and it is no longer needed: you can just run `sourcecred load`.

This was also the only untested code in the `graphql/` package, so it is
nice to remove it.

Test Plan:
Running `yarn test --full` passes.

wchargin-branch: remove-mirror-demo
2018-11-01 11:29:57 -07:00
William Chargin d19227c268
github: use blacklists to unblock twbs/bootstrap (#973)
Summary:
This adds object IDs to the GitHub GraphQL blacklist such that the
`twbs/bootstrap` repository can be loaded.

Ingesting the Mirror-extracted data into the RelationalView yields the
warnings

```
IssueComment[MDEyOklzc3VlQ29tbWVudDEwNTI4Mzk4Ng==].reactions: unexpected null value
IssueComment[MDEyOklzc3VlQ29tbWVudDI0NTQ3OTM3OA==].reactions: unexpected null value
IssueComment[MDEyOklzc3VlQ29tbWVudDMwNDE4NzIzMg==].reactions: unexpected null value
```

because we have nulled out these `Reaction`s in their enclosing
connections. This is expected.

Test Plan:
Run `yarn backend` and `node ./bin/sourcecred.js load twbs/bootstrap`.
Run `yarn start` and note that the cred attribution renders properly.

(Loading the GitHub data may take an hour or two. The resulting SQLite3
database is 172MB. Ingesting it into the `RelationalView` still takes
just a few seconds, and the cred attribution is rendered quickly.)

wchargin-branch: github-use-blacklists
2018-11-01 11:08:17 -07:00
William Chargin fe50ca83f6
mirror: allow blacklisting objects by ID (#972)
Summary:
This enables us to deal with GraphQL remotes that violate their contract
guarantees and provide a node of the wrong type. An instance in which
the GitHub GraphQL API does this is documented here:
<https://gist.github.com/wchargin/a2b8561b81bcc932c84e493d2485ea8a>

A Mirror cache is only valid for a fixed set of blacklisted IDs. This is
necessary to ensure consistency. If the set of blacklisted IDs changes,
simply remove the existing database and download again from scratch.

Test Plan:
Unit tests added, with full coverage.

wchargin-branch: mirror-blacklist
2018-11-01 11:04:49 -07:00
Dandelion Mané 69989256f6
Rename `app/` to `homepage/` (#974)
Now that we've moved the explorer out of app, it is more concisely
described as the homepage.

Test plan: Rename only. Run `yarn test`.
2018-11-01 10:19:51 -07:00
Dandelion Mané 604db14879
Pull `credExplorer` into its own top-level module (#971)
Currently, the cred explorer is a submodule of `app`. This is somewhat
confusing, as `app` is essentially our homepage, and the explorer is a
standalone React application which happens to get embedded in our
homepage. This commit pulls the explorer from `app/credExplorer/` into
`explorer/`, which is a better organization.

The `app/adapters` were actually only used by the cred explorer, so
those files have been moved to `explorer/adapters`. We should rename
them from "App Adapters" to "Explorer Adapters", but I didn't do that in
this commit so as to minimize the (already substantial) size of the
change.

Also, we should rename `app/` to `homepage/` in a subsequent commit.

I encountered a nasty Flow bug, which I fixed with help from @wchargin.
The result is extra annotations on the demo and fallback dynamic
adapters (so that the `static()` method is type annotated).

Test plan: This change is massive, but it's just a rename. `yarn test`
suffices.
2018-11-01 10:16:42 -07:00
Dandelion Mané c997f4e1ec
Collect web-related utilities in `webutil/` (#970)
I'm planning to pull `credExplorer` out of `app` and into its own
top-level module. This is a bit awkward, as `credExplorer` depends on
a lot of little modules that are currently collected in `app/`.

To resolve this, I pull all of these little utility modules into
`webutil/`. It's not a totally principled grouping, but it's quite
convenient and keeps these rarely changing modules out of the way.

Test plan: It's a file move, `yarn test` suffices.
2018-10-31 21:24:25 -07:00
Dandelion Mané b077bd8179
Move `weightsToEdgeEvaluator` to `analysis` (#969)
The logic for converting weights into an edge evaluator should not be
coupled to the frontend application.

Progress towards #967.

Test plan: Very straightforward rename; `yarn test` suffices.
2018-10-31 20:14:30 -07:00
Dandelion Mané 48a66c8118
Declare the fallback plugin in analysis (#968)
Now that the `analysis` module owns the Node and Edge types, it should
own the "fallback plugin" too. (Note that it's not actually a plugin,
though it somewhat acts like one.)

We now declare the fallback type in `analysis`, along with a fallback
analysis adapter. `app/adapters` then declares a fallback app adapter.

Test plan: `yarn test`

Progress towards #967.
2018-10-31 20:02:38 -07:00
Dandelion Mané f3ddb84cbd
Move weight logic to analysis (#966)
There's a folder called `app/credExplorer/weights` which contains the
type specification for weights (for PageRank configurability), and also
contains frontend code for specifying those weights. This commit creates
a `weights` module under `analysis` which will contain just the logic
for specifying and using the weights, without any frontend
consideration.

It's mostly a port of the existing logic in `credExplorer/weights`, with
the caveat that app adapter related concepts have been removed, in favor
of referencing the declaration instead.

We then remove the duplicated logic and re-route imports.

Test plan: `yarn test`
2018-10-31 13:27:03 -07:00
Dandelion Mané 86a5b532f8
Add the demo plugin (#965)
* Add the demo plugin

This ports the ad-hoc demo adapter defined in
`src/app/adapters/demoAdapters.js` into its own demo plugin.

This has the benefit that the demo plugin can now be depended on outside
the app module, e.g. for the analysis module as well. Correspondingly,
I've added a demo analysis adapter.

Test plan: `yarn test`. Note that no unit tests were added, as the demo
plugin is trivial.

* Delete `src/app/adapters/demoAdapters.js`

Now that we have an explicit demo plugin at `src/plugins/demo/`, we can
remove the legacy declaration of that plugin within the `app` module.

This commit deletes the old version, and re-writes all references to
point to the standalone plugin.

Test plan: `yarn test`
2018-10-31 13:23:46 -07:00
William Chargin 6b789d61d6
github: remove legacy continuations code (#964)
Summary:
It is time. (Replaced with #622.)

Test Plan:
Running `yarn flow` suffices. Running `yarn test --full` also passes.

wchargin-branch: remove-legacy-graphql
2018-10-31 12:45:59 -07:00
William Chargin 2e0b17cef7
mentionsAuthorReference: remove legacy GraphQL dep (#963)
Summary:
This test has data in the old format, and uses the `RelationalView`
method that automatically translates it. As we prepare to delete that
code, we upgrade the underlying format of this test data. The end code
is nicer to read, too (e.g., we don’t need the `connection` helper
function).

Recommend reviewing with `git show -b`.

Test Plan:
Running `yarn test` suffices.

wchargin-branch: mentionsAuthorReference-remove-legacy-graphql
2018-10-31 12:36:48 -07:00
William Chargin b77db72c1d
github: remove some deps on github/graphql.js (#962)
Summary:
A number of modules depended on the legacy `github/graphql.js` module
solely to get at the `Reactions` enum object. As of #961, that object is
exposed from the much lighter-weight `graphqlTypes.js`. This patch
switches over the relevant imports, reducing our dependencies on this
legacy module and its large bundle size.

Test Plan:
It suffices to run `yarn flow` and verify that the two values being
imported are identical.

wchargin-branch: github-use-generated-enums
2018-10-31 12:24:06 -07:00
William Chargin 2377f1980f
schema: generate runtime constants for enum values (#961)
Summary:
We have a `const Reactions` convenience enum in `github/graphql.js`.
That value is useful, but that module is slated to die. This commit
extends our Flow type generation script to include these values.

Test Plan:
Existing unit tests suffice.

wchargin-branch: schema-generate-enums
2018-10-31 12:22:58 -07:00
Dandelion Mané 9bccb7661d
Change the GitHub default TTL to one week (#960)
While we wait for explicit configurability, one week is a better
default for the many SourceCred demos I maintain.

Test plan: n/a
2018-10-31 12:21:08 -07:00
Dandelion Mané b86b0b32ec
Add `analysisAdapter` (#950)
For #704, we're adding plugin adapters that are specific to the needs of
the analysis module. They have a simple scope: they just provide a way
to get the declaration, and to load the corresponding graph.

Adapters for the `git` and `github` plugins have been implemented, along
with unit tests.

Test plan: `yarn test` suffices.
2018-10-31 11:36:30 -07:00
William Chargin 8706fa9771
git: don’t warn when rendering unknown commits (#957)
Summary:
Fixes #953. See that issue for context.

Test Plan:
Unit tests updated. To see the change in action, load the SourceCred
data and expand @decentralion’s commits-authored to find commits that
were merged into non-`master` branches. Note that these commits are
rendered correctly (in the same way that they were before this patch),
and that there is no console error (new as of this patch).

![Screenshot](https://user-images.githubusercontent.com/4317806/47805669-1f98b580-dcf5-11e8-8683-8ee91f7f478a.png)

wchargin-branch: git-no-warn-on-unknown-commit
2018-10-31 10:45:25 -07:00
William Chargin f9bb75ef71
release: v0.2.0 (#952)
Test Plan:
Remove the SourceCred output directory, run `yarn backend`, and load
data for `sourcecred/example-github` and `sourcecred/sourcecred`. Then,
run `yarn start` and note that the cred explorer still works. Finally,
note that `yarn test --full` passes.

wchargin-branch: release-v0.2.0
2018-10-30 15:18:19 -07:00
Dandelion Mané c4e2ec8839
Rename `PluginAdapter` to `AppAdapter` (#948)
Now that we're planning to add adapters for the `analysis` module, we
should rename the `PluginAdapter` to make it clear that it's scoped for
`app`.

Test plan: `yarn test` suffices
2018-10-30 00:26:22 +00:00
Dandelion Mané cb30023a02
Factor out plugin declarations (#947)
The plugin adapters are specific to `app/` and have logic for fetching
data from the backend, producing React nodes for descriptions, et
cetera.

However, they also have information that is generic to the plugin
itself: its name, its node/edge prefixes, and its types.

This method factors out the generic info into a `PluginDeclaration`,
which is a type (rather than an interface). Then, the plugin adapter has
a `declaration` method which returns the declaration.

Current users of the plugin adapters get additional mechanical
complexity because they need to call `.declaration().property` rather
than `.property()`, but this is not too significant.

The main benefit is that #704 is unblocked, as the cli `analyze` command
will be able to get necessary information from the declaration. As an
added benefit, the organization of plugin code is somewhat improved.

Test plan: `yarn test` sufficies, but I also ran `yarn start` and
checked the UI behavior to be safe.
2018-10-30 00:13:11 +00:00
Dandelion Mané 5f2cc56172
Move `{Node,Edge}Type` to src/analysis/types.js (#946)
Test plan: `yarn test`

Part of ongoing work on #704
2018-10-29 23:49:53 +00:00
Dandelion Mané 917b793aca
Move some files from core/attribution/ to analysis/ (#944)
The `core/attribution/` folder has some code that really is "core" in
that it deals with very basic concepts around converting graphs to
markov chains and running PageRank on them, and some code that is less
"core", like for normalizing scores and doing analysis on them.

To make progresson #704, we need an intermediary directory that has
analysis-related code that is e.g. aware of Node and Edge types, and
weights on those types, and can use them to run weight-informed
PageRank. That code shouldn't live in the app directory (since it is not
coupled to the frontend rendering), but also shouldn't live in core
(since "core" is basically finalized code with fully baked abstractions,
and per #710, this is not true of the node/edge type system).

Thus, I've decided to create the `analysis` directory. To get that
directory started, I've moved the non-core code in `core/attribution/`
to `analysis/`.

Test plan: `yarn test` passes, which is all we need, since this is a
straightforward file rename.
2018-10-29 22:54:15 +00:00
Dandelion Mané 542e2f9723
Add skeleton of `sourcecred analyze` (#942)
The `analyze` command is the first step towards #704 and #703. When
fully implemented, it will run PageRank for a loaded repository,
generating a complete graph and cred attribution.

For now, this just adds a scaffold. It does basic argument parsing, and
has help text, but the actual command is not yet implemented.

Test plan:
Unit tests verify that the analyze command is hooked into `sourcecred`
and `sourcecred help`, and that it responds to the `--help` command and
parses its arguments appropriately.
2018-10-29 22:27:06 +00:00
William Chargin 08219f98bf
fetchGithubRepo: use Mirror pipeline (#937)
Summary:
As of this commit, `node ./bin/sourcecred.js load` uses the Mirror code,
and the legacy continuation-fetching code is not included in the
`sourcecred.js` bundle.

We do not yet perform the commit prefetching described in #923. The code
should be plenty fast for repositories that merge pull requests at least
occasionally.

Test Plan:
Running `yarn test --full` passes. Loading `sourcecred/sourcecred` works
and generates a reasonable credit attribution. Loading it again
completes immediately.

wchargin-branch: fetchGithubRepo-mirror
2018-10-28 12:03:06 -07:00
William Chargin e2c99c418b
relationalView: use new data format (#934)
Summary:
This makes significant progress toward #923. As of this commit, it is
possible to use the Mirror module for the whole loading pipeline. This
process may be slow for repositories that do not use pull requests at
all (more precisely, that have large connected commit subgraphs none of
whose nodes is the merge commit of a pull request; see #920 for details)
so it is not yet the default codepath.

Test Plan:
Existing unit tests should suffice. For extra testing, I’ve added a
script that fetches a repository both via the old continuations logic
and the new Mirror logic, then constructs relational views and checks
whether the data is the same. For `example-github`, the views are
identical. For `sourcecred`, they are not: the old continuations logic
erroneously omits two commits, which the Mirror logic includes.

You can run the test like this:

```
$ node ./bin/testContinuations.js \
> sourcecred sourcecred MDEwOlJlcG9zaXRvcnkxMjAxNDU1NzA= \
> /tmp/continuations.json /tmp/mirror.json \
> 2> >(jq . >&2)
{
  "child": "0d38dde23a6de831315f3643a7d2bc15e8df7678",
  "parent": "cb8ba0eaa1abc1f921e7165bb19e29b40723ce65",
  "type": "UNKNOWN_PARENT_OID"
}
{
  "child": "d152f48ce4c2ed1d046bf6ed4f139e7e393ea660",
  "parent": "de7a8723963d9cd0437ef34f5942a071b850c0e7",
  "type": "UNKNOWN_PARENT_OID"
}
Different. Saving to disk...
```

Use `diff -u <(jq . /tmp/continuations.json) <(jq . /tmp/mirror.json)`
to inspect the differences, and note that exactly the two missing
commits have been added and that there are no other changes. (The diff
is small: just 51 lines of nicely formatted JSON.) The full log is here:
<https://gist.github.com/wchargin/e159cac9dcf3cc3b1efbd54f59e24e0b>

I also generated the `sourcecred/sourcecred` cred attribution and viewed
it with `yarn start`, which seems to work fine.

wchargin-branch: relationalview-new-data-format
2018-10-23 16:42:49 -07:00
William Chargin 58e98124ac
relationalView: make snapshots order-invariant (#933)
Summary:
An upcoming commit will happen to change the order in which commits are
ingested. This is not an observable change, and should not cause a
snapshot failure.

Test Plan:
Inspection.

wchargin-branch: relationalview-snapshots-order-invariant
2018-10-23 10:50:18 -07:00
William Chargin 993de9303a
github: translate old format to structured format (#930)
Summary:
This implements the translation module described in #923. See that issue
for context.

Test Plan:
This is a mostly straightforward translation from one strongly typed
data structure to another, so Flow handles most of it.

As a check on the snapshot, run:

```
$ grep -e oid -e target -e mergeCommit \
> src/plugins/github/__snapshots__/translateContinuations.test.js.snap
      "target": Object {
        "oid": "6bd1b4c0b719c22c688a74863be07a699b7b9b34",
            "oid": "c430bd74455105f77215ece51945094ceeee6c86",
                "oid": "6d5b3aa31ebb68a06ceb46bbd6cf49b6ccd6f5e6",
                    "oid": "0a223346b4e6dec0127b1e6aa892c4ee0424b66a",
                        "oid": "ec91adb718a6045b492303f00d8e8beb957dc780",
                        "oid": "ecc889dc94cf6da17ae6eab5bb7b7155f577519d",
                            "oid": "ec91adb718a6045b492303f00d8e8beb957dc780",
        "mergeCommit": Object {
          "oid": "0a223346b4e6dec0127b1e6aa892c4ee0424b66a",
              "oid": "ec91adb718a6045b492303f00d8e8beb957dc780",
              "oid": "ecc889dc94cf6da17ae6eab5bb7b7155f577519d",
                  "oid": "ec91adb718a6045b492303f00d8e8beb957dc780",
        "mergeCommit": Object {
          "oid": "6d5b3aa31ebb68a06ceb46bbd6cf49b6ccd6f5e6",
              "oid": "0a223346b4e6dec0127b1e6aa892c4ee0424b66a",
                  "oid": "ec91adb718a6045b492303f00d8e8beb957dc780",
                  "oid": "ecc889dc94cf6da17ae6eab5bb7b7155f577519d",
                      "oid": "ec91adb718a6045b492303f00d8e8beb957dc780",
        "mergeCommit": null,
```

Cross-check this against [the example-github commits][commits] thus:

  - Note that commit `6bd1b4c` is the head commit, and is thus the root
    commit of the `target` chain.
  - Note that commits `0a22334` and `6d5b3aa`, which were merged via
    pull request, appear twice each: once in the history from head, and
    once as the merge commit of a pull request.
  - Note that commit `0a22334` has two parents at each occurrence.
  - Note that the unmerged pull request’s merge commit is `null`.

[commits]: https://github.com/sourcecred/example-github/commits/master

To run this on real-world data, apply the following patch:

```diff
diff --git a/src/plugins/github/fetchGithubRepo.js b/src/plugins/github/fetchGithubRepo.js
index 6ac201af..b14ca760 100644
--- a/src/plugins/github/fetchGithubRepo.js
+++ b/src/plugins/github/fetchGithubRepo.js
@@ -11,6 +11,7 @@ import {stringify, inlineLayout, type Body} from "../../graphql/queries";
 import {createQuery, createVariables, postQueryExhaustive} from "./graphql";
 import type {GithubResponseJSON} from "./graphql";
 import type {RepoId} from "../../core/repoId";
+import translateContinuations from "./translateContinuations";

 /**
  * Scrape data from a GitHub repo using the GitHub API.
@@ -44,6 +45,11 @@ export default function fetchGithubRepo(
     payload
   ).then((x: GithubResponseJSON) => {
     ensureNoMorePages(x);
+    console.warn("Translating continuations...");
+    for (const w of translateContinuations(x).warnings) {
+      console.warn(w);
+    }
+    console.warn("Done.");
     return x;
   });
 }
```

Then run:

```
$ yarn backend >/dev/null 2>/dev/null; echo $?
0
$ node ./bin/sourcecred.js load sourcecred/sourcecred --plugin github 2>&1 |
> ts -s '%.s'
55.015740 Translating continuations...
55.037217 { type: 'UNKNOWN_PARENT_OID',
55.037273   child: '0d38dde23a6de831315f3643a7d2bc15e8df7678',
55.037290   parent: 'cb8ba0eaa1abc1f921e7165bb19e29b40723ce65' }
55.037309 { type: 'UNKNOWN_PARENT_OID',
55.037336   child: 'd152f48ce4c2ed1d046bf6ed4f139e7e393ea660',
55.037359   parent: 'de7a8723963d9cd0437ef34f5942a071b850c0e7' }
55.037383 Done.
```

Note that the two commits in question were each merged into a non-master
branch, in #28 and #329 respectively. Note also that translating these
continuations took just 22 milliseconds.

wchargin-branch: github-translate-continuations
2018-10-22 10:01:49 -07:00
William Chargin 6499df6b6b
github: fix misc. errors in old GraphQL system (#929)
Summary:
This fixes the following issues:

  - Pull request reviews actually do not have reactions.
  - We must fetch the `id` of a `Ref`.
  - We must fetch the `id` of a `Commit`, `Tree`, `Blob`, or `Tag`, and
    should also fetch its `oid`.
  - Repository owners cannot be bots.
  - Commit and reaction authors cannot be bots, organizations, or
    `undefined`.

Test Plan:
Running `yarn test --full` passes, and the snapshot diff is clearly
correct.

wchargin-branch: github-fix-up-continuations
2018-10-22 09:50:24 -07:00
William Chargin 889febb7f6
github: add GraphQL schema and Flow types (#928)
Summary:
The included schema is forked from the one in `graphql/demo.js`.
Primitive types have been added, and the `parents` connection has been
added to commit objects per #920. (We do not include this in the demo
script because without prefetching it would take a long time to load.)

Test Plan:
Unit tests added; run `yarn unit`. Then run `yarn backend` and verify
that `node ./bin/generateGithubGraphqlFlowTypes.js` generates exactly
the same output as in the types file:

```
$ node ./bin/generateGithubGraphqlFlowTypes.js |
> diff -u - ./src/plugins/github/graphqlTypes.js
$ echo $?
0
```

Change the `graphqlTypes.js` file and verify that `yarn unit` fails.

As the build config has been changed, a `yarn test --full` is warranted.
It passes.

Finally, I have manually verified that the schema is consistent with the
documentation at <https://developer.github.com/v4/object/repository/>
and related pages.

wchargin-branch: github-schema-flow-types
2018-10-19 09:04:54 -07:00
William Chargin 04f7e9ea8c
graphql: generate Flow types from a schema (#927)
Summary:
Generating Flow types from a structured schema is both straightforward
and terribly useful. This commit implements it.

Test Plan:
Inspect the snapshot for correctness manually. Then, copy it into a new
file, remove backslash-escapes, and verify that it passes Flow.
A subsequent commit will generate types for the actual GitHub schema.

wchargin-branch: graphql-generate-flow-types
2018-10-19 09:02:49 -07:00
William Chargin e787db53c4
schema: allow annotating primitive field types (#926)
Summary:
Prior to this change, primitive fields were un\[i\]typed. This commit
allows adding type annotations. Such annotations do not change the
semantics at all, but we will be able to use them to generate Flow types
corresponding to a schema.

This commit also strengthens the validation on schemata to catch some
errors that would previously have gone unnoticed at schema construction
time: e.g., a node reference to a type that does not exist.

Test Plan:
Unit tests updated, retaining full coverage. The demo script continues
to work when loading `example-github` or `sourcecred`.

wchargin-branch: schema-annotated-primitives
2018-10-19 09:00:52 -07:00
William Chargin ee4900616b
github: fetch commit parent oids (#924)
Summary:
To ease the transition from manual continuation resolution to the Mirror
API, we update the old system to fetch commit parent OIDs, as described
in #923.

Test Plan:
To check that the continuations are wired correctly, apply the following
patch to force continuations to be followed at every step:

```diff
diff --git a/src/plugins/github/graphql.js b/src/plugins/github/graphql.js
index 05761ca..a21a364 100644
--- a/src/plugins/github/graphql.js
+++ b/src/plugins/github/graphql.js
@@ -53,7 +53,7 @@ const PAGE_SIZE_COMMENTS = 20;
 const PAGE_SIZE_REVIEWS = 5;
 const PAGE_SIZE_REVIEW_COMMENTS = 10;
 const PAGE_SIZE_COMMIT_HISTORY = 100;
-const PAGE_SIZE_COMMIT_PARENTS = 5;
+const PAGE_SIZE_COMMIT_PARENTS = 0;
 const PAGE_SIZE_REACTIONS = 5;

 /**
@@ -358,6 +358,7 @@ function* continuationsFromCommit(
 ) {
   const b = build;
   if (result.parents && result.parents.pageInfo.hasNextPage) {
+    console.warn(result.parents.pageInfo);
     yield {
       enclosingNodeType: "COMMIT",
       enclosingNodeId: nodeId,
@@ -366,7 +367,7 @@ function* continuationsFromCommit(
           b.field(
             "parents",
             {
-              first: b.literal(PAGE_LIMIT),
+              first: b.literal(1),
               after: b.literal(result.parents.pageInfo.endCursor),
             },
             [b.fragmentSpread("commitParents")]
```

(It is important that the initial page limit be `0` and not (say) `1`,
because the `defaultBranchRef` is likely to have just one parent; by
using `0`, we test its continuations as long as it has at least one
parent.)

Then run `./src/plugins/github/fetchGithubRepoTest.sh` and note that the
test passes and the output is

```
{ hasNextPage: true, endCursor: null }
{ hasNextPage: true, endCursor: null }
{ hasNextPage: true, endCursor: null }
{ hasNextPage: true, endCursor: null }
{ hasNextPage: true, endCursor: null }
{ hasNextPage: true, endCursor: null }
{ hasNextPage: true, endCursor: null }
{ hasNextPage: true, endCursor: 'MQ==' }
{ hasNextPage: true, endCursor: 'MQ==' }
```

Note that the test output (as updated in this commit) includes commits
with a unique parent, a commit with no parents, and a commit with two
parents.

I also ran `node ./bin/sourcecred.js load` on sourcecred/sourcecred and
ipfs/js-ipfs. Each worked, and the resulting credit attributions loaded
fine.

wchargin-branch: github-commit-parent-oids
2018-10-18 19:16:44 -07:00
William Chargin 7c5923959e
github: fetch dates from commits (#919)
Summary:
This has two benefits:

  - The dates on commits are data that we will probably want when we add
    timestamps to authorship edges to accommodate time-weighted cred.

  - Once the mirror module is integrated with the GitHub plugin, we’ll
    want to fetch dates on commits, because this is the only real-world
    test case for a nested field that contains a primitive field (as
    opposed to a node reference), so it’ll be nice to be continually
    exercising that somewhat-edge case.

Date strings are in commit-local time and do not depend on the time zone
of the requester (in contrast to [cursors]). For example, on SourceCred:

```shell
$ time node ./bin/fetchAndPrintGithubRepo.js \
> sourcecred sourcecred "${GITHUB_TOKEN}" |
> jq -rc '
>     .repository.defaultBranchRef.target.history.nodes[]
>     .author?.date[-6:]
> ' | sort | uniq -c
      1 +03:00
      6 -04:00
    717 -07:00
     58 -08:00
```

[cursors]: <https://github.com/sourcecred/sourcecred/pull/129#issuecomment-382970474>

Test Plan:
The snapshot contains 8 instances of `oid` and 8 instances of `date`,
which is good (each of these properties appears exactly once on each
commit, and nowhere else). Running `yarn test --full` passes.

wchargin-branch: github-commit-dates
2018-10-16 22:54:39 -07:00
William Chargin 1155c439b9
mirror: add support for shallow-nested fields (#918)
Summary:
This commit follows up on the previous two pull requests by drawing the
rest of the owl.

Resolves #915.

Test Plan:
Unit tests included.

To verify the snapshot change, open the snapshot file, and copy
everything from `query TestUpdate {` through the matching `}`, not
including the enclosing quotes. Strip all backslashes (Jest adds them).
Post the resulting query to GitHub and verify that it completes
successfully and that the result contains a commit with an `author`.

In other words, `xsel -ob | tr -d '\\' | ghquery | jq .` with [ghquery].

[ghquery]: https://gist.github.com/wchargin/630e03e66fa084b7b2297189615326d1

The demo entry point has also been updated. For an end-to-end test, you
can run the following command to see a commit with a `null` author (with
the current state of the repository) and a commit with a non-`null`
author:

```
$ node bin/mirror.js /tmp/mirror-example.db \
>     Repository MDEwOlJlcG9zaXRvcnkxMjMyNTUwMDY= \
>     3600 2>/dev/null |
> jq '(.defaultBranchRef.target, .pullRequests[0].mergeCommit) | {url, author}'
{
  "url": "6bd1b4c0b7",
  "author": {
    "date": "2018-09-12T19:48:21-07:00",
    "user": null
  }
}
{
  "url": "0a223346b4",
  "author": {
    "date": "2018-02-28T00:43:47-08:00",
    "user": {
      "id": "MDQ6VXNlcjE0MDAwMjM=",
      "__typename": "User",
      "url": "https://github.com/decentralion",
      "login": "decentralion"
    }
  }
}
```

You can also check that it is possible to fetch the whole SourceCred
repository (ID: `MDEwOlJlcG9zaXRvcnkxMjAxNDU1NzA=`).

wchargin-branch: mirror-shallow
2018-10-04 16:00:07 -07:00
William Chargin 49f0803a7a
mirror: reflect nested fields in schema info (#917)
Summary:
See #915 for context. This adds nested field data to the “useful info”
data structure added in #857.

Test Plan:
Unit tests for `_buildSchemaInfo` updated.

wchargin-branch: mirror-schemainfo-shallow
2018-10-04 15:30:04 -07:00
William Chargin 3d2206088c
schema: support shallow-nested object fields (#916)
Summary:
See #915 for context. This commit changes the `schema` module only.

I had a hard time picking names that clearly distinguish the top-level
field on the object and the subfields that it contains. @decentralion
and I independently came up with “nest” and “egg”. It’s a bit colorful,
but it’s certainly easy to remember which one is which, and it doesn’t
conflict with existing notions like “parent”/“child”.

Test Plan:
Unit tests expanded slightly, retaining full coverage.

wchargin-branch: schema-shallow
2018-10-04 15:28:58 -07:00
William Chargin 48b68b221a
link: remove `styles` attribute from child (#911)
Summary:
By using `<a {...this.props}>{children}</a>`, we were forwarding the
Aphrodite selectors as `styles`. This caused the static HTML for the
page to include `<a styles="[object Object]">`, which is annoying.

Test Plan:
Unit tests extended: they fail before this change and pass after it.
Also clicked a router link and an external link in the application.

wchargin-branch: link-child-styles
2018-10-03 12:14:07 -07:00
William Chargin 55950f5354
mirror: add an end-to-end `update` function (#909)
Summary:
This completes the minimum viable public API for the `Mirror` class. As
described on the docstring, the typical workflow for a client is:

  - Invoke the constructor to acquire a `Mirror` instance.
  - Invoke `registerObject` to register a root object of interest.
  - Invoke `update` to update all transitive dependencies.
  - Invoke `extract` to retrieve the data in structured form.

It is the third step that is added in this commit.

In this commit, we also include a command-line demo of the Mirror
module, which exercises exactly the workflow above with a hard-coded
GitHub schema. This can be used to test the module’s behavior with
real-world data. I plan to remove this entry point once we integrate
this module into SourceCred.

This commit makes progress toward #622.

Test Plan:
Unit tests included for the core functionality. The imperative shell
does not have automated tests. You can test it as follows.

First, run `yarn backend` to build `bin/mirror.js`. Then, run:

```shell
$ node bin/mirror.js /tmp/mirror-demo.db \
> Repository MDEwOlJlcG9zaXRvcnkxMjMyNTUwMDY= \
> 60
```

Here, the big base64 string is the ID for the sourcecred/example-github
repository. (This is listed in `graphql/demo.js`, alongside the ID for
the SourceCred repository itself.) The value 60 is a TTL in seconds. The
database filename is arbitrary.

This will print out a ton of output to stderr (all intermediate queries
and responses, for debugging purposes), and then the full contents of
the example repository to stdout.

Run the command again, and it should finish instantly. On my machine,
the main function runs faster than the Node startup time (50ms vs 60ms).

Then, re-run the command, changing the TTL from `60` to `1`. Note that
it sends off some queries and then prints the same repository.

It is safe to kill the program at any time, either while waiting for a
response from GitHub or while processing the results, because the mirror
module takes advantage of SQLite’s transaction-safety. Intermediate
updates will be persisted, so you’ll lose just a few seconds of
progress.

You can also of course dive into the generated database yourself to
explore the data. It’s good fun.

wchargin-branch: mirror-e2e-update
2018-10-02 21:06:01 -07:00
William Chargin 23e56f481a
mirror: paginate own-data node updates (#908)
Summary:
GitHub has an undocumented node limit on the number of IDs that can be
provided to the top-level `nodes` connection. This is silly, because we
can just spread the IDs over multiple identical connections. This commit
implements the logic to do so.

Test Plan:
Create some queries that use `nodes(ids: ...)` to fetch varying numbers
of objects:

```shell
id="MDEwOlJlcG9zaXRvcnkxMjAxNDU1NzA="
nodes() {
    n="$1"
    ids="$(yes "$id" | head -n "$n" | jq -R . | jq -sc .)"
    printf 'nodes(ids: %s) { __typename }' "$ids"
}
query() {
    printf '{ '
    for num; do
        printf 'nodes_%s: %s ' "$num" "$(nodes "$num")"
    done
    printf '}'
}
```

Note that the query given by `query 101` results in an error…

```json
{
  "data": null,
  "errors": [
    {
      "message": "You may not provide more than 100 node ids; you provided 101.",
      "type": "ARGUMENT_LIMIT",
      "path": [
        "nodes_101"
      ],
      "locations": [
        {
          "line": 1,
          "column": 3
        }
      ]
    }
  ]
}
```

…but the query given by `query 98 99` happily returns 197 node entries.

wchargin-branch: mirror-paginate-own-data
2018-10-02 20:49:01 -07:00
William Chargin 1b09a7f61b
markdown: ignore references in HTML code elements (#907)
Summary:
Fixes #903. We already ignore Markdown code syntax (backticks), but
prior to this commit we treated the contents of all HTML elements,
including `<code>`, as normal text. As of this commit, `<code>` elements
are stripped entirely. Other HTML elements, like `<em>`, are unaffected.

Test Plan:
Unit tests added. Also, load data for `ipfs/js-ipfs-block-service`, and
observe in the UI that PR `#36` (Update aegir to version 9.0.0) no
longer has any outward references.

wchargin-branch: markdown-html-code
2018-10-02 20:34:49 -07:00
Dandelion Mané 4a374d755e
Hyperlink Git commits to GitHub (#887)
This modifies the `nodeDescription` code for the Git plugin so that when
given a Git commit, it will hyperlink to that commit on GitHub. It does
this by looking up the corresponding `RepoId`s from the newly-added
`commitToRepoId` field in the `Repository` (#884).

Per a [suggestion in review], rather than hardcoding the GitHub url
logic in the Git plugin, we provide them via a `GitGateway`.

[suggestion in review]: https://github.com/sourcecred/sourcecred/pull/887#issuecomment-424059649

When no `RepoId` is found, it errors to console and does not include a
hyperlink. When multiple `RepoId`s are available, it chooses to link to
one arbitrarily. (In the future, we could amend this behavior to add
links to every valid repo). This behavior is tested.

Test plan:
I ran the application on newly-generated data and verified that it sets
up commit hyperlinks appropriately. Also, see unit tests.
2018-09-27 20:32:43 -07:00
William Chargin 65d811fb44
mirror: add helpers for full queries and updates (#898)
Summary:
An update step is now roughly as simple as:

    _updateData(postQuery(_queryFromPlan(_findOutdated())))

(with some option/config parameters thrown in).

This makes progress toward #622.

Test Plan:
Unit tests included. They are light, because these functions are light.
They still retain full coverage.

wchargin-branch: mirror-full-pipeline
2018-09-27 19:12:47 -07:00
William Chargin 9a4c91887b
mirror: include typenames in extracted data (#897)
Summary:
These typenames are often superfluous, but sometimes they are useful.
For instance, we might want to fetch the same data for `User`s, `Bot`s,
and `Organization`s, but still differentiate which kind of node we
fetched from an `Actor` union reference. Similarly, many timeline events
may have similar signatures (like, “issue closed” vs. “issue reopened”).

Test Plan:
Existing unit tests have been updated; run `yarn unit`.

wchargin-branch: mirror-extract-typenames
2018-09-26 21:24:30 -07:00
William Chargin b74f1f3714
mirror: add public method `extract` (#894)
Summary:
The `extract` method lets you get data out of a mirror in a structured
format.

The mirror module now contains all the plumbing needed to provide
meaningful value. Remaining to be implemented are some internal
porcelain and a public method to perform an update step.

This makes progress toward #622.

Test Plan:
Comprehensive unit tests included, with full coverage; run `yarn unit`.

wchargin-branch: mirror-extract
2018-09-26 12:04:10 -07:00
William Chargin 90ace93f91
mirror: add helper to find unused table name (#895)
Summary:
Per <https://github.com/sourcecred/sourcecred/pull/894#discussion_r220406780>.

Test Plan:
Unit tests included; run `yarn unit`.

wchargin-branch: mirror-unused-table-name
2018-09-26 11:37:21 -07:00
William Chargin a5e0707cb9
ui: remove `:visited` color change for nav links (#892)
Test Plan:
Note that the nav links are now a lighter color, except when `:active`
(e.g., when you’re holding down the mouse button).

wchargin-branch: remove-visited
2018-09-25 16:38:46 -07:00
William Chargin a7f29cb057
mirror: add connection object types to query plan (#891)
Summary:
This reestablishes harmony in light of #882.

Test Plan:
Existing unit tests suffice; run `yarn unit`.

wchargin-branch: mirror-query-plan-connection-object-typename
2018-09-25 14:25:11 -07:00
William Chargin 892c498f9c
mirror: query and process own-data updates (#883)
Summary:
This commit adds internal functions to (a) emit a GraphQL query to fetch
data for own-data of an object, and (b) ingest the results of said query
back into the database.

The API and implementation differ from the connection-updating analogues
introduced in #878 in that the query for own data is independent of an
object’s ID: it depends only on the object’s type. This affords us more
flexibility in composing queries.

As described in a internal documentation comment, values are stored in
the database in JSON-stringified form: we cannot use the obvious raw SQL
values, because there is no native encoding of booleans (`0`/`1` is
conventional), and we need to distinguish them from other data types.
There are other ways to solve this problem. Notably:

 1. We could take inspiration from OCaml: encode stronger static types
    and a simpler runtime representation. That is, we could change the
    schema field types from simply “primitive” to the various specific
    primitive types. Then, when reading data out from the database, we
    could reinterpret the values appropriately.

 2. We could take advantage of the fact that we are not using all of
    SQLite’s data types. In particular, we do not store anything as a
    binary blob, so we could encode `false` as a length-0 zeroblob and
    `true` as a length-1 zeroblob, for instance. Again, when reading
    data out from the database, we would reinterpret the values—but in
    this approach we would not need an explicit schema from the user.

For now, we take the easiest and simplest approach just to get ourselves
off the ground. We can easily move to the second option described above
later.

This commit makes progress toward #622.

Test Plan:
Unit tests included, with full coverage. While these tests check that
the GraphQL queries are as expected, they cannot check that they are
actually valid in production. To check this, follow the instructions in
the added snapshot test.

wchargin-branch: mirror-own-data-updates
2018-09-25 11:58:32 -07:00
William Chargin 2af8566e6a
app: add and use a shared Link component (#890)
Summary:
This will enable us to style links consistently across our application.

Our previous link colors for base and `:visited` were so similar that I
didn’t actually realize that they were different. In this change, I’ve
kept the same base color, and selected a more contrasting `:visited`
color. I also added an `:active` color, which is good for usability
(color chosen via <http://paletton.com/>’s “triad” suggestion).

Example screenshot, with active, visited, and base links:
![Screenshot as in this commit][img-underline]

I also considered implementing the link underlines with `border-bottom`
instead of `text-decoration` (an oft-touted suggestion that has always
smelled fishy to me, but [the W3 does it][w3], so I guess it’s okay).
That would look like this:

![Screenshot with `border-bottom` underlines][img-border]

…but I did not do so ([rationale in a comment on #890][rationale]).

[w3]: https://www.w3.org/TR/WCAG20-TECHS/F73.html
[img-underline]: https://user-images.githubusercontent.com/4317806/45987381-f154f580-c025-11e8-8b0f-63c1e1ddce02.png
[img-border]: https://user-images.githubusercontent.com/4317806/45926176-a081b780-bed4-11e8-96f2-d0d24d11c8f7.png
[rationale]: https://github.com/sourcecred/sourcecred/pull/890#issuecomment-424146773

We can certainly change these decisions later—that’s one of the purposes
of having this abstraction—so I’m not inclined to bikeshed on them too
much in this commit.

Implementation adapted from:
<80263b190e/src/components/Link.js>

Test Plan:
Check that `<a>` elements and React Router link elements are used only
in `Link` and snapshots:

```
$ git grep --name-only -Fw '<a'
src/app/Link.js
src/assets/logo/discourse_512.png
src/plugins/github/__snapshots__/render.test.js.snap
$ git grep '"react-router"' | grep 'Link'
src/app/Link.js:import {Link as RouterLink} from "react-router";
src/app/Link.test.js:import {Link as RouterLink} from "react-router";
src/app/createRelativeHistory.test.js:import {Router, Route, Link} from "react-router";
src/app/withAssets.test.js:import {IndexRoute, Link, Router, Route} from "react-router";
```

Check that the primary color now appears in just one spot:

```
$ git grep -i 0872a2
src/app/Link.js:    ...colorAttributes("#0872A2"),
```

Then, run `yarn start` and click all the links. Note in particular that
the SVG icons in the header have the correct colors in the active state
as well as the base state.

wchargin-branch: app-link
2018-09-24 18:26:52 -07:00
William Chargin 3257df63fe
mirror: add helper to register nullable node results (#889)
Summary:
As <https://github.com/sourcecred/sourcecred/pull/883/files#r219648511>.
It is somewhat unfortunate that this mixes a command with a query, but
the concession is acceptable in this instance, I think.

Test Plan:
Existing unit tests suffice, retaining full coverage.

wchargin-branch: mirror-register-node-field-results
2018-09-24 18:20:28 -07:00
William Chargin 28c4e497fb
mirror: factor out `_makeSingleUpdateFunction` (#888)
Summary:
This helpful utility is already used in some test code, and will shortly
be used in main code. @decentralion suggested factoring it out in
<https://github.com/sourcecred/sourcecred/pull/883#discussion_r219647781>.

Test Plan:
Unit tests included, with full coverage; run `yarn unit`.

wchargin-branch: mirror-make-update-helper
2018-09-24 18:06:14 -07:00
Dandelion Mané 3b962eacea
Git: track the repositories containing each commit (#884)
This modifies the Git `Repository` data structure so that for every
commit, we track the `RepoId`s of repos containing that commit. This way
we will be able to do things like hyperlink to the right url for that
commit.

`loadRepository` has been modified to set the initial `repoId`.
`mergeRepository` has been updated to ensure that it concatenates the
`repoId`s properly.
Tests were added for both cases.

The example-git snapshot has been updated accordingly.

Test plan: `yarn test --full`
2018-09-21 17:06:14 -07:00
Dandelion Mané b506d40efd
Add the `RepoIdString` type (#885)
This modifies `core/repoId` so that `repoIdToString` returns not a
`string`, but an opaque subtype of `string` called `RepoIdString`.

This allows us to store stringified `RepoId`s (which is useful whenever
we want value-not-reference semantics, like for use as a map key)
while still maintaining a type assertion that the strings, in fact,
represent valid `RepoId`s.

Test plan: A unit test verifies that it's a flow error to cast a string
to a `RepoIdString`.
2018-09-21 16:54:20 -07:00
William Chargin 838092194b
mirror: add support for connections of union types (#882)
Summary:
Almost every GitHub connection has nodes of an object type, like `User`
or `IssueComment`. But a few have nodes of union type, including
`IssueTimelineItemConnection` (which we will likely want to query), and
those require special handling. This commit adds susupport for such
connections.

Analysis to determine which connections have non-object elements:
<https://gist.github.com/wchargin/647fa7ed8d6d17ae2e204bd098104407>

Test Plan:
Unit tests modified appropriately, retaining full coverage.

The easiest way to verify the snapshot is probably to copy the raw
contents (everything inside the quotes) into `/tmp/snapshot`, then run:

```shell
$ sed -e 's/\\//g' </tmp/snapshot >/tmp/query  # Jest adds backslashes
$ jq -csR '{query: ., variables: {}}' </tmp/query >/tmp/payload
$ ENDPOINT='https://api.github.com/graphql'
$ AUTH="Authorization: bearer ${SOURCECRED_GITHUB_TOKEN}"
$ curl "$ENDPOINT" -X POST -H "$AUTH" -d @- </tmp/payload >/tmp/result
```

and then execute the JQ program mentioned in the comment in the test
case, and verify that it prints `true`.

wchargin-branch: connection-of-union
2018-09-21 16:20:58 -07:00
Dandelion Mané 23ae7e2f08
Rename the core `Repo` type to `RepoId` (#881)
We have a core type called `Repo`, but it really is an identifier to a
repo, rather than being a repo itself. This is confusing since we have a
data type called `Repository` which actually represents the data in a
repository. I've renamed `Repo` to `RepoId` for clarity.

Test plan: `yarn test --full` passes. Running the frontend passes after
wholly regenerating the sourcecred data directory.
2018-09-21 14:44:29 -07:00
Dandelion Mané 1e5f728e29
Cred explorer: display commit short hash + summary (#879)
This modifies how commits are displayed in the cred explorer. Rather
than printing the full hash, we now print a short hash followed by the
summary.

Test plan:
Snapshot is updated, also I tested it by running SourceCred on a real
repository.
2018-09-21 13:24:28 -07:00
William Chargin 09ed51ed6e
mirror: align test schema more with GitHub schema (#880)
Summary:
This commit changes the `Issue` type of the schema used in the `mirror`
tests to have fields a faithful subset of those in the actual GitHub
schema. The tests are self-contained, so this is not strictly required.
However, it is convenient, because it means that we can snapshot a query
that can actually be posted to GitHub.

Test Plan:
Running `yarn unit mirror` suffices for the code change. The GitHub
schema docs at <https://developer.github.com/v4/object/issue/> indicate
that each of `id`, `url`, `author`, `repository`, `title`, and
`comments` is a valid field.

wchargin-branch: mirror-test-schema
2018-09-20 17:17:27 -07:00
Dandelion Mané 0b3e2e7f7f
Load commits' short hash and summary (#876)
This modifies the Git Commit type to includea short hash and a oneline
summary, and modifies `loadRepository` so that we actually get that
data.

The example-git repository has been updated to include a commit with
leading whitespace and a pipe in the summary, to ensure that these are
respected.

Test plan: Observe that the snapshot is updated, and the updates are
correct. `yarn test --full` passes.
2018-09-20 15:51:58 -07:00
William Chargin 6ae5c56624
mirror: query and process connection updates (#878)
Summary:
This commit adds internal functions to (a) emit a GraphQL query to fetch
data for a particular connection, and (b) ingest the results of said
query back into the database.

This commit makes progress toward #622.

Test Plan:
Unit tests included, with full coverage. While these tests check that
the GraphQL queries are as expected, they cannot check that they are
actually valid in production. To check this, follow the instructions in
the added snapshot test.

wchargin-branch: mirror-connection-updates
2018-09-20 15:46:03 -07:00
Dandelion Mané 5348fe68bf
Remove git adresses for trees, blobs, and entries (#877)
In #873 I removed the data types for trees, blobs, and entries, but
neglected to remove the address related code. This commit corrects that
mistake. Some test cases in other modules have been removed because the
failure is now structurally impossible, e.g. it is not possible that we
would provide a non-commit address to the GitHub plugin, because
non-commit addresses do not exist.

Test plan: `yarn test --full` passes.
2018-09-20 15:18:01 -07:00
William Chargin 1dd8b7bcb7
mirror: add internal method `_findOutdated` (#875)
Summary:
This function finds all objects whose own data has not been updated
since a given time, and all connections whose entries have not been
updated since that time.

Note that this is scoped to the entirety of the database. In #622,
I discussed using a recursive common table expression to identify only
those transitive dependencies of the root. I think that this is overkill
for the `_findOutdated` method: you’ll usually want to update everything
in the database. Don’t worry—the cool recursive query will still be used
in the `extract` function. :-)

This commit makes progress toward #622.

Test Plan:
Unit tests added, with full coverage; run `yarn unit`.

wchargin-branch: mirror-findoutdated
2018-09-20 14:19:47 -07:00
Dandelion Mané e3f04c5079
Git plugin serializes the repository and graph (#874)
This modifies the behavior when loading the Git plugin so that it
serializes the Repository as well as the graph. This will allow us to
get extra information, like the commit headline, to the Git plugin in
the frontend.

As an added bonus, we can now refactor `loadRepositoryTest` to depend on
`sourcecred.js load` rather than `loadAndPrintRepository`. As this was
the only use for `loadAndPrintRepository`, we can safely delete it. This
improves our test quality because it means we are also testing the
actual CLI behavior.

Note that the switch from using `stringify` to `json.tool` for
pretty-printing has resulted in a trivial diff in the snapshot.

Test plan: `yarn test --full` passes.
2018-09-20 14:07:58 -07:00
Dandelion Mané 5b8ec53b13
Remove all git tree related code (#873)
In #627, I made a case for removing all trees and blobs from the cred
graph. The issue was that the data was bloated and noisy, and did not
provide much value in its current form. This commit follows on that by
actually removing the code from the codebase (rather than keeping it
unused).

I want to delete this code because I believe:
1. It is unlikely to see further use in its current form (because
collecting the entire Git tree structure is just too noisy for our
purposes)
2. In the event that we do need it, reviving it will not be too
difficult (because it is all quite locally scoped to the Git plugin).
3. Keeping unused code increases ongoing maintenance + development
costs, and I'd like to bias towards keeping the codebase simple and
lean.

In the event that a future contributor is reviving this code and finds
it a pain, I pre-emptively apologize to you.

Test plan:
`yarn test --full` passees.
2018-09-20 13:50:27 -07:00
William Chargin ab5b6ecb68
mirror: add public method `registerObject` (#870)
Summary:
This function informs the GraphQL mirror of the existence of an object,
specified by its global ID and its concrete typename (“concrete” meaning
“object type”—like `User`, not `Actor`).

The function will be called extensively internally as more objects are
discovered while traversing the graph, but also needs to be exposed as a
public entry point: a client needs to call this function at least once
to register the root node of interest. A typical client workflow, once
all of #622 is implemented, might be:

 1. Issue a standalone GraphQL query to find the ID of a root node, like
    a GitHub repository: `repository(owner: "foo", name: "bar") { id }`.
 2. Call `registerObject` with the ID found in the previous step.
 3. Instruct the mirror to recursively update all dependencies.
 4. Extract data from the mirror.

As of this commit, steps (1) and (2) are possible.

This commit makes progress toward #622.

Test Plan:
Unit tests included, with full coverage; run `yarn unit`.

wchargin-branch: mirror-registerobject
2018-09-20 13:03:06 -07:00
Dandelion Mané 12aa5b7439
Add `mergeRepository` for merging Git repositories (#871)
This commit adds a utility method, `mergeRepository`, which can merge
multiple Git repository data structures. `loadGitData` has been updated
to create a merged repository and then subsequently generate a graph
from it.

Test plan:
New unit tests were added. `yarn test --full` passes. Loading a project
and viewing its git data in the cred explorer works.
2018-09-20 12:57:57 -07:00
William Chargin e572551cd8
mirror: add internal method `_createUpdate` (#868)
Summary:
It’s useful to add this simple function now because the rest of the
commits required to implement #622 will want to use it extensively in
test code. Actual clients of the API will not need to use it, because
the concept of “updates” is an implementation detail: clients will
always provide simple timestamps.

Test Plan:
Unit tests included, with full coverage; run `yarn unit`.

wchargin-branch: mirror-createupdate
2018-09-20 11:12:21 -07:00