Skip to content

Conversation

@yjbanov
Copy link
Contributor

@yjbanov yjbanov commented Jul 13, 2016

This is a basic app made of a Go App Engine server app and an Angular 2 Dart client app to get us going. It can:

  • Fetch commit data from GitHub and store it in datastore
  • Generate a checklist of build tasks
  • Show a build status table
  • Update build status from Travis
  • Provide a simple in-browser CLI for some management tasks (creating/authorizing agents)
  • Provide a basic JSON REST API for both the Angular app and build agents

/cc @skybrian @devoncarew


AuthorInfo([Map<String, dynamic> props]) : super(_serializer, props);

String get login => this['Login'];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indent looks wonky here

Copy link
Contributor Author

@yjbanov yjbanov Jul 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For some reason Atom inserted tabs instead of spaces all over the place in this file. Fixed.

@devoncarew
Copy link
Contributor

lgtm for my part; thanks for the walkthrough yesterday

} else {
task.Status = "Failed"
}
cocoon.PutTask(taskEntity.Key, task)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this transaction does what you think. Since you are only doing a blind "put" inside the transaction, the datastore doesn't see any constraint on the order of the puts and they could be written in any order. Data can be lost.

If you want to safely update one field inside an entity without accidentally modifying any of the entity's other fields, the transaction should do a read-modify-write on the entity, entirely inside the transaction. (That is, doing a Get and a Put.)

(I'm also not sure why a bunch of unrelated tasks need to be updated within a single transaction, since presumably the Travis tasks can complete independently, in any order.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, there's no need for a transaction. Travis build status generally flips once and stays that way. It doesn't matter if we are trying to flip it from "New" to "Succeeded" concurrently. The end result is the same. We might support build reruns in the future, but that will be a separate feature and still very unlikely to cause conflicting concurrent status updates.

db/db.go Outdated
return agent, authToken, nil
}

// CommitInfo contain information about a GitHub commit.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as an organization thing, maybe move all the structs corresponding to datastore entities (or parts of them) to schema.go?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

// independently. Different tasks belonging to the same Checklist can run in
// parallel.
type Task struct {
ChecklistKey *datastore.Key
Copy link

@skybrian skybrian Jul 14, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before going live you might want to consider if you should put the datastore entities into a hierarchy. Maybe something like:
Commit => Checklist => Task

The main advantage is that ancestor queries (under a single root) are atomic, versus other queries which are only eventually consistent. Also, you can do a transaction under a single root without making it a global transaction.

A disadvantage, though, is that each child entity's key is a suffix of the key of its parent. (So keys are longer and this makes URL's longer.) Also I think there's a limit of about 1 transaction/second under each root.

For more see:
https://cloud.google.com/appengine/docs/go/datastore/entities#Go_Ancestor_paths

Ancestor filter on this page:
https://cloud.google.com/appengine/docs/go/datastore/queries

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no Commit records in the database, but Checklist => Task do form a parent-child relationship. If you look at PutTask, the key for Task is created as NewIncompleteKey(c.Ctx, "Task", task.ChecklistKey). While this field is a little redundant, I'd like to keep it because it makes it easy to marshal tasks to clients over JSON RPC. If I send just the encoded task key, the client would have to somehow parse the checklist key out of the task key.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...That said, I should use Ancestor(checklistKey) rather than Filter("ChecklistKey =", checklistKey). Will fix.

@skybrian
Copy link

LGTM

@yjbanov yjbanov merged commit 5ede273 into flutter:master Jul 14, 2016
auto-submit bot pushed a commit that referenced this pull request Aug 30, 2023
…ice class (#3026)

We are getting alert for 500 errors from the /api/github/webhook-branch-subscription endpoint when attempting to insert a commit for a release branch. The issue is with the timestamp presumably being null when we attempt to insert it into the database since it not a field in the return RepositoryCommit in the github lib.

```
"Failed to process Instance of 'PushMessage'. (500) Invalid argument(s): Error while encoding entity (Bad state: Property validation failed for property timestamp while trying to serialize entity of kind Commit. , #0      _ModelDescription._encodeProperty (package:gcloud/src/db/model_db_impl.dart:449:7)
#1      _ModelDescription.encodeModel.<anonymous closure> (package:gcloud/src/db/model_db_impl.dart:429:7)
#2      _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:625:13)
#3      _ModelDescription.encodeModel (package:gcloud/src/db/model_db_impl.dart:428:34)
#4      ModelDBImpl.toDatastoreEntity (package:gcloud/src/db/model_db_impl.dart:121:31)
#5      _commitHelper (package:gcloud/src/db/db.dart:434:38)
#6      Transaction.commit (package:gcloud/src/db/db.dart:118:14)
#7      DatastoreService.insert.<anonymous closure>.<anonymous closure> (package:cocoon_service/src/service/datastore.dart:254:31)
#8      DatastoreDB.withTransaction.<anonymous closure> (package:gcloud/src/db/db.dart:324:32)
#9      _rootRunUnary (dart:async/zone.dart:1407:47)
<asynchronous suspension>
#10     DatastoreService.insert.<anonymous closure> (package:cocoon_service/src/service/datastore.dart:252:11)
<asynchronous suspension>
#11     RetryOptions.retry (package:retry/retry.dart:131:16)
<asynchronous suspension>
#12     DatastoreService.insert (package:cocoon_service/src/service/datastore.dart:250:7)
<asynchronous suspension>
#13     CommitService.handleCreateGithubRequest (package:cocoon_service/src/service/commit_service.dart:42:7)
<asynchronous suspension>
#14     GithubBranchWebhookSubscription.post (package:cocoon_service/src/request_handlers/github/branch_subscription.dart:56:7)
<asynchronous suspension>
#15     RequestHandler.service.<anonymous closure> (package:cocoon_service/src/request_handling/request_handler.dart:53:24)
<asynchronous suspension>
#16     SubscriptionHandler.service (package:cocoon_service/src/request_handling/subscription_handler.dart:138:5)
<asynchronous suspension>
#17     main.<anonymous closure>.<anonymous closure> (file:///app/bin/server.dart:303:11)
<asynchronous suspension>
```

The data returned by the call in the Commit Service looks like this:

```
{
  "sha": "6fd42536b7697eb4bd2a698b19308e0aacac70c7",
  "node_id": "C_kwDOAeUeuNoAKDZmZDQyNTM2Yjc2OTdlYjRiZDJhNjk4YjE5MzA4ZTBhYWNhYzcwYzc",
  "commit": {
    "author": {
      "name": "Xilai Zhang",
      "email": "xilaizhang@google.com",
      "date": "2023-08-30T02:59:02Z"
    },
    "committer": {
      "name": "GitHub",
      "email": "noreply@github.com",
      "date": "2023-08-30T02:59:02Z"
    },
    "message": "[flutter roll] Revert \"Fix `Chip.shape`'s side is not used when provided in Material 3\" (#133615)\n\nReverts flutter/flutter#132941\r\ncontext: b/298110031\r\n\r\nThe rounded rectangle borders don't appear in some of the internal\r\ngolden image tests.",
    "tree": {
      "sha": "e5efe7f39155d9b8fc40ad0a59c72f6a36f8b66d",
      "url": "https://api.github.com/repos/flutter/flutter/git/trees/e5efe7f39155d9b8fc40ad0a59c72f6a36f8b66d"
    },

```

The author field in this case has no createdAt timestamp.

*List which issues are fixed by this PR. You must list at least one issue.*
Fixes flutter/flutter#133707

*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
auto-submit bot pushed a commit that referenced this pull request Jul 24, 2024
See flutter/flutter#152194 where I got befuddling error messages:

```txt
Unhandled exception:
Null check operator used on a null value
#0      DeviceLabTestOwner.getTestOwnership (package:cocoon_service/src/request_handlers/test_ownership.dart:60:59)
#1      getTestOwnership (package:cocoon_service/src/request_handlers/flaky_handler_utils.dart:301:20)
#2      validateOwnership (package:cocoon_service/src/foundation/utils.dart:225:27)
#3      remoteCheck (file:///b/s/w/ir/x/w/cocoon/app_dart/bin/validate_task_ownership.dart:31:40)
<asynchronous suspension>
#4      main (file:///b/s/w/ir/x/w/cocoon/app_dart/bin/validate_task_ownership.dart:63:23)
<asynchronous suspension>
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants