GitHub PullRequestReviewCommentEvent at 2014-09-12 14:25:02
Repository: charmstore
Actor: frankban
Payload: {"action":"created","comment":{"url":"https://api.github.com/repos/juju/charmstore/pulls/comments/17481109","id":17481109,"diff_hunk":"@@ -0,0 +1,250 @@\n+package main\n+\n+import (\n+\t\"bytes\"\n+\t\"crypto/sha512\"\n+\n+\t\"encoding/base64\"\n+\t\"flag\"\n+\t\"fmt\"\n+\t\"io\"\n+\t\"io/ioutil\"\n+\t\"net/http\"\n+\t\"os\"\n+\t\"os/exec\"\n+\t\"path/filepath\"\n+\t\"strings\"\n+\t\"time\"\n+\n+\t\"github.com/juju/loggo\"\n+\t\"gopkg.in/juju/charm.v3\"\n+\n+\t\"launchpad.net/lpad\"\n+)\n+\n+var logger = loggo.GetLogger(\"charmload\")\n+\n+func main() {\n+\terr := load()\n+\tif err != nil {\n+\t\tfmt.Fprintf(os.Stderr, \"%v\\n\", err)\n+\t\tos.Exit(1)\n+\t}\n+}\n+\n+func load() error {\n+\tflags := flag.NewFlagSet(os.Args[0], flag.ExitOnError)\n+\tstaging := flags.Bool(\"staging\", false, \"use the launchpad staging server\")\n+\tstoreURL := flags.String(\"storeurl\", \"http://localhost:8080/v4/\", \"the URL of the charmstore\")\n+\tloggingConfig := flags.String(\"logging-config\", \"\", \"specify log levels for modules e.g. <root>=TRACE\")\n+\tshowLog := flags.Bool(\"show-log\", false, \"if set, write log messages to stderr\")\n+\tstoreUser := flags.String(\"user\", \"admin:example-passwd\", \"the colon separated user:password for charmstore\")\n+\terr := flags.Parse(os.Args[1:])\n+\tif flag.ErrHelp == err {\n+\t\tflag.Usage()\n+\t}\n+\tserver := lpad.Production\n+\tif *staging {\n+\t\tserver = lpad.Staging\n+\t}\n+\tif *loggingConfig != \"\" {\n+\t\tloggo.ConfigureLoggers(*loggingConfig)\n+\t}\n+\tif *showLog {\n+\t\twriter := loggo.NewSimpleWriter(os.Stderr, &loggo.DefaultFormatter{})\n+\t\t_, err := loggo.ReplaceDefaultWriter(writer)\n+\t\tif err != nil {\n+\t\t\treturn err\n+\t\t}\n+\t}\n+\toauth := &lpad.OAuth{Anonymous: true, Consumer: \"juju\"}\n+\troot, err := lpad.Login(server, oauth)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\n+\tcharmsDistro, err := root.Distro(\"charms\")\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\ttips, err := charmsDistro.BranchTips(time.Time{})\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tfor _, tip := range tips {\n+\t\tif !strings.HasSuffix(tip.UniqueName, \"/trunk\") {\n+\t\t\tcontinue\n+\t\t}\n+\t\tlogger.Tracef(\"getting uniqueNameURLs for %v\", tip.UniqueName)\n+\t\tbranchURL, charmURL, err := uniqueNameURLs(tip.UniqueName)\n+\t\tif err != nil {\n+\t\t\tlogger.Infof(\"could not get uniqueNameURLs for %v: %v\", tip.UniqueName, err)\n+\t\t\tcontinue\n+\t\t}\n+\t\tif tip.Revision == \"\" {\n+\t\t\tlogger.Tracef(\"skipping %v no revision\", tip.UniqueName)\n+\t\t\tcontinue\n+\t\t} else {\n+\t\t\tlogger.Tracef(\"found %v with revision %v\", tip.UniqueName, tip.Revision)\n+\t\t}\n+\t\tURLs := []*charm.URL{charmURL}\n+\t\tschema, name := charmURL.Schema, charmURL.Name\n+\t\tfor _, series := range tip.OfficialSeries {\n+\t\t\tnextCharmURL := &charm.URL{\n+\t\t\t\tSchema:   schema,\n+\t\t\t\tName:     name,\n+\t\t\t\tRevision: -1,\n+\t\t\t\tSeries:   series,\n+\t\t\t}\n+\t\t\tURLs = append(URLs, nextCharmURL)\n+\t\t\tlogger.Debugf(\"added URL %v to URLs list for %v\", nextCharmURL, tip.UniqueName)\n+\t\t}\n+\t\terr = publishBazaarBranch(*storeURL, *storeUser, URLs, branchURL, tip.Revision)\n+\t\tif err != nil {\n+\t\t\tlogger.Errorf(\"publishing branch %v to charmstore: %v\", branchURL, err)\n+\t\t}\n+\t\tif _, ok := err.(*UnauthorizedError); ok {\n+\t\t\treturn err\n+\t\t}\n+\n+\t}\n+\treturn nil\n+}\n+\n+// uniqueNameURLs returns the branch URL and the charm URL for the\n+// provided Launchpad branch unique name. The unique name must be\n+// in the form:\n+//\n+//     ~<user>/charms/<series>/<charm name>/trunk\n+//\n+// For testing purposes, if name has a prefix preceding a string in\n+// this format, the prefix is stripped out for computing the charm\n+// URL, and the unique name is returned unchanged as the branch URL.\n+func uniqueNameURLs(name string) (branchURL string, charmURL *charm.URL, err error) {\n+\tu := strings.Split(name, \"/\")\n+\tif len(u) > 5 {\n+\t\tu = u[len(u)-5:]\n+\t\tbranchURL = name\n+\t} else {\n+\t\tbranchURL = \"lp:\" + name\n+\t}\n+\tif len(u) < 5 || u[1] != \"charms\" || u[4] != \"trunk\" || len(u[0]) == 0 || u[0][0] != '~' {\n+\t\treturn \"\", nil, fmt.Errorf(\"unsupported branch name: %s\", name)\n+\t}\n+\tcharmURL, err = charm.ParseURL(fmt.Sprintf(\"cs:%s/%s/%s\", u[0], u[2], u[3]))\n+\tif err != nil {\n+\t\treturn \"\", nil, err\n+\t}\n+\treturn branchURL, charmURL, nil\n+}\n+\n+func publishBazaarBranch(storeURL string, storeUser string, URLs []*charm.URL, branchURL string, digest string) error {\n+\n+\t// Retrieve the branch with a lightweight checkout, so that it\n+\t// builds a working tree as cheaply as possible. History\n+\t// doesn't matter here.\n+\ttempDir, err := ioutil.TempDir(\"\", \"publish-branch-\")\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tdefer os.RemoveAll(tempDir)\n+\tbranchDir := filepath.Join(tempDir, \"branch\")\n+\tlogger.Debugf(\"running bzr checkout ... %v\", branchURL)\n+\toutput, err := exec.Command(\"bzr\", \"checkout\", \"--lightweight\", branchURL, branchDir).CombinedOutput()\n+\tif err != nil {\n+\t\treturn outputErr(output, err)\n+\t}\n+\n+\ttipDigest, err := bzrRevisionId(branchDir)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tif tipDigest != digest {\n+\t\tdigest = tipDigest\n+\t\tlogger.Warningf(\"tipDigest %v != digest %v\", digest, tipDigest)\n+\t}\n+\n+\tthischarm, err := charm.ReadCharmDir(branchDir)\n+\tlogger.Tracef(\"read CharmDir from branchDir %v\", thischarm, branchDir)\n+\tif err == nil {\n+\t\treader, writer := io.Pipe()\n+\t\thash1 := sha512.New384()\n+\t\tvar counter Counter\n+\t\tmwriter := io.MultiWriter(hash1, &counter)\n+\t\tthischarm.ArchiveTo(mwriter)\n+\t\thash1str := fmt.Sprintf(\"%x\", hash1.Sum(nil))\n+\t\tgo func() {","path":"cmd/charmload/main.go","position":180,"original_position":176,"commit_id":"d621c22a997968cd08b11a2661b191d6a92833b6","original_commit_id":"889d47e7cd4d07f9dbb1008d2a84c9b8040b90c5","user":{"login":"frankban","id":1408172,"avatar_url":"https://avatars.githubusercontent.com/u/1408172?v=2","gravatar_id":"0624f29cc29fb11d86e11ce07f0353e9","url":"https://api.github.com/users/frankban","html_url":"https://github.com/frankban","followers_url":"https://api.github.com/users/frankban/followers","following_url":"https://api.github.com/users/frankban/following{/other_user}","gists_url":"https://api.github.com/users/frankban/gists{/gist_id}","starred_url":"https://api.github.com/users/frankban/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/frankban/subscriptions","organizations_url":"https://api.github.com/users/frankban/orgs","repos_url":"https://api.github.com/users/frankban/repos","events_url":"https://api.github.com/users/frankban/events{/privacy}","received_events_url":"https://api.github.com/users/frankban/received_events","type":"User","site_admin":false},"body":"I think I understood why we need this goroutine here (together with the io.Pipe above), but making it explicit with a comment would really help future readers.","created_at":"2014-09-12T14:25:02Z","updated_at":"2014-09-12T14:25:02Z","html_url":"https://github.com/juju/charmstore/pull/95#discussion_r17481109","pull_request_url":"https://api.github.com/repos/juju/charmstore/pulls/95","_links":{"self":{"href":"https://api.github.com/repos/juju/charmstore/pulls/comments/17481109"},"html":{"href":"https://github.com/juju/charmstore/pull/95#discussion_r17481109"},"pull_request":{"href":"https://api.github.com/repos/juju/charmstore/pulls/95"}}},"pull_request":{"url":"https://api.github.com/repos/juju/charmstore/pulls/95","id":20917236,"html_url":"https://github.com/juju/charmstore/pull/95","diff_url":"https://github.com/juju/charmstore/pull/95.diff","patch_url":"https://github.com/juju/charmstore/pull/95.patch","issue_url":"https://api.github.com/repos/juju/charmstore/issues/95","number":95,"state":"open","locked":false,"title":"Launchpad ingestion to archive endpoint","user":{"login":"jrwren","id":106443,"avatar_url":"https://avatars.githubusercontent.com/u/106443?v=2","gravatar_id":"f200b43dd7a12345e2d46d7256b4cfe6","url":"https://api.github.com/users/jrwren","html_url":"https://github.com/jrwren","followers_url":"https://api.github.com/users/jrwren/followers","following_url":"https://api.github.com/users/jrwren/following{/other_user}","gists_url":"https://api.github.com/users/jrwren/gists{/gist_id}","starred_url":"https://api.github.com/users/jrwren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jrwren/subscriptions","organizations_url":"https://api.github.com/users/jrwren/orgs","repos_url":"https://api.github.com/users/jrwren/repos","events_url":"https://api.github.com/users/jrwren/events{/privacy}","received_events_url":"https://api.github.com/users/jrwren/received_events","type":"User","site_admin":false},"body":"Wire up launchpad ingestion to charmstore filling out new api/models.\r\n\r\nUPDATE\r\n\r\nQA instructions:\r\n\r\n1. Make sure your dependencies are up to date, run make reps\r\n2. Run mongodb. I use system mongodb\r\n3. Run charmd using go run: go run cmd/charmd/main.go cmd/charmd/config.yaml &\r\n4. Run charmload using go run: go run cmd/charmload/main.go --staging=true --show-log --logging-config='&lt;root&gt;=TRACE'\r\n5. Optionally omit the --staging=true option to use production launchpad.\r\n\r\nAnd, when I follow these instructions on a clean utopic system, I get same errors mentioned by @bac and @urosj so I'm keeping this blocked until I resolve them.  No idea, yet, why it WFM on a different system.","created_at":"2014-09-08T20:56:24Z","updated_at":"2014-09-12T14:25:02Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4d506d2327119aca133b005f084819ef902ccaa6","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/juju/charmstore/pulls/95/commits","review_comments_url":"https://api.github.com/repos/juju/charmstore/pulls/95/comments","review_comment_url":"https://api.github.com/repos/juju/charmstore/pulls/comments/{number}","comments_url":"https://api.github.com/repos/juju/charmstore/issues/95/comments","statuses_url":"https://api.github.com/repos/juju/charmstore/statuses/d621c22a997968cd08b11a2661b191d6a92833b6","head":{"label":"jrwren:launchpad-ingestion","ref":"launchpad-ingestion","sha":"d621c22a997968cd08b11a2661b191d6a92833b6","user":{"login":"jrwren","id":106443,"avatar_url":"https://avatars.githubusercontent.com/u/106443?v=2","gravatar_id":"f200b43dd7a12345e2d46d7256b4cfe6","url":"https://api.github.com/users/jrwren","html_url":"https://github.com/jrwren","followers_url":"https://api.github.com/users/jrwren/followers","following_url":"https://api.github.com/users/jrwren/following{/other_user}","gists_url":"https://api.github.com/users/jrwren/gists{/gist_id}","starred_url":"https://api.github.com/users/jrwren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jrwren/subscriptions","organizations_url":"https://api.github.com/users/jrwren/orgs","repos_url":"https://api.github.com/users/jrwren/repos","events_url":"https://api.github.com/users/jrwren/events{/privacy}","received_events_url":"https://api.github.com/users/jrwren/received_events","type":"User","site_admin":false},"repo":{"id":22686186,"name":"charmstore","full_name":"jrwren/charmstore","owner":{"login":"jrwren","id":106443,"avatar_url":"https://avatars.githubusercontent.com/u/106443?v=2","gravatar_id":"f200b43dd7a12345e2d46d7256b4cfe6","url":"https://api.github.com/users/jrwren","html_url":"https://github.com/jrwren","followers_url":"https://api.github.com/users/jrwren/followers","following_url":"https://api.github.com/users/jrwren/following{/other_user}","gists_url":"https://api.github.com/users/jrwren/gists{/gist_id}","starred_url":"https://api.github.com/users/jrwren/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jrwren/subscriptions","organizations_url":"https://api.github.com/users/jrwren/orgs","repos_url":"https://api.github.com/users/jrwren/repos","events_url":"https://api.github.com/users/jrwren/events{/privacy}","received_events_url":"https://api.github.com/users/jrwren/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/jrwren/charmstore","description":"The charm store server.","fork":true,"url":"https://api.github.com/repos/jrwren/charmstore","forks_url":"https://api.github.com/repos/jrwren/charmstore/forks","keys_url":"https://api.github.com/repos/jrwren/charmstore/keys{/key_id}","collaborators_url":"https://api.github.com/repos/jrwren/charmstore/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/jrwren/charmstore/teams","hooks_url":"https://api.github.com/repos/jrwren/charmstore/hooks","issue_events_url":"https://api.github.com/repos/jrwren/charmstore/issues/events{/number}","events_url":"https://api.github.com/repos/jrwren/charmstore/events","assignees_url":"https://api.github.com/repos/jrwren/charmstore/assignees{/user}","branches_url":"https://api.github.com/repos/jrwren/charmstore/branches{/branch}","tags_url":"https://api.github.com/repos/jrwren/charmstore/tags","blobs_url":"https://api.github.com/repos/jrwren/charmstore/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/jrwren/charmstore/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/jrwren/charmstore/git/refs{/sha}","trees_url":"https://api.github.com/repos/jrwren/charmstore/git/trees{/sha}","statuses_url":"https://api.github.com/repos/jrwren/charmstore/statuses/{sha}","languages_url":"https://api.github.com/repos/jrwren/charmstore/languages","stargazers_url":"https://api.github.com/repos/jrwren/charmstore/stargazers","contributors_url":"https://api.github.com/repos/jrwren/charmstore/contributors","subscribers_url":"https://api.github.com/repos/jrwren/charmstore/subscribers","subscription_url":"https://api.github.com/repos/jrwren/charmstore/subscription","commits_url":"https://api.github.com/repos/jrwren/charmstore/commits{/sha}","git_commits_url":"https://api.github.com/repos/jrwren/charmstore/git/commits{/sha}","comments_url":"https://api.github.com/repos/jrwren/charmstore/comments{/number}","issue_comment_url":"https://api.github.com/repos/jrwren/charmstore/issues/comments/{number}","contents_url":"https://api.github.com/repos/jrwren/charmstore/contents/{+path}","compare_url":"https://api.github.com/repos/jrwren/charmstore/compare/{base}...{head}","merges_url":"https://api.github.com/repos/jrwren/charmstore/merges","archive_url":"https://api.github.com/repos/jrwren/charmstore/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/jrwren/charmstore/downloads","issues_url":"https://api.github.com/repos/jrwren/charmstore/issues{/number}","pulls_url":"https://api.github.com/repos/jrwren/charmstore/pulls{/number}","milestones_url":"https://api.github.com/repos/jrwren/charmstore/milestones{/number}","notifications_url":"https://api.github.com/repos/jrwren/charmstore/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/jrwren/charmstore/labels{/name}","releases_url":"https://api.github.com/repos/jrwren/charmstore/releases{/id}","created_at":"2014-08-06T14:45:49Z","updated_at":"2014-07-31T13:05:56Z","pushed_at":"2014-09-12T14:08:33Z","git_url":"git://github.com/jrwren/charmstore.git","ssh_url":"git@github.com:jrwren/charmstore.git","clone_url":"https://github.com/jrwren/charmstore.git","svn_url":"https://github.com/jrwren/charmstore","homepage":null,"size":839,"stargazers_count":0,"watchers_count":0,"language":null,"has_issues":false,"has_downloads":true,"has_wiki":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"juju:v4","ref":"v4","sha":"693615915b48f0ff3d70dce5cf5251ecd838f5bb","user":{"login":"juju","id":4604548,"avatar_url":"https://avatars.githubusercontent.com/u/4604548?v=2","gravatar_id":"b095d1e26e5705abe0ad2de7d87aac2e","url":"https://api.github.com/users/juju","html_url":"https://github.com/juju","followers_url":"https://api.github.com/users/juju/followers","following_url":"https://api.github.com/users/juju/following{/other_user}","gists_url":"https://api.github.com/users/juju/gists{/gist_id}","starred_url":"https://api.github.com/users/juju/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/juju/subscriptions","organizations_url":"https://api.github.com/users/juju/orgs","repos_url":"https://api.github.com/users/juju/repos","events_url":"https://api.github.com/users/juju/events{/privacy}","received_events_url":"https://api.github.com/users/juju/received_events","type":"Organization","site_admin":false},"repo":{"id":20720417,"name":"charmstore","full_name":"juju/charmstore","owner":{"login":"juju","id":4604548,"avatar_url":"https://avatars.githubusercontent.com/u/4604548?v=2","gravatar_id":"b095d1e26e5705abe0ad2de7d87aac2e","url":"https://api.github.com/users/juju","html_url":"https://github.com/juju","followers_url":"https://api.github.com/users/juju/followers","following_url":"https://api.github.com/users/juju/following{/other_user}","gists_url":"https://api.github.com/users/juju/gists{/gist_id}","starred_url":"https://api.github.com/users/juju/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/juju/subscriptions","organizations_url":"https://api.github.com/users/juju/orgs","repos_url":"https://api.github.com/users/juju/repos","events_url":"https://api.github.com/users/juju/events{/privacy}","received_events_url":"https://api.github.com/users/juju/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/juju/charmstore","description":"The charm store server.","fork":false,"url":"https://api.github.com/repos/juju/charmstore","forks_url":"https://api.github.com/repos/juju/charmstore/forks","keys_url":"https://api.github.com/repos/juju/charmstore/keys{/key_id}","collaborators_url":"https://api.github.com/repos/juju/charmstore/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/juju/charmstore/teams","hooks_url":"https://api.github.com/repos/juju/charmstore/hooks","issue_events_url":"https://api.github.com/repos/juju/charmstore/issues/events{/number}","events_url":"https://api.github.com/repos/juju/charmstore/events","assignees_url":"https://api.github.com/repos/juju/charmstore/assignees{/user}","branches_url":"https://api.github.com/repos/juju/charmstore/branches{/branch}","tags_url":"https://api.github.com/repos/juju/charmstore/tags","blobs_url":"https://api.github.com/repos/juju/charmstore/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/juju/charmstore/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/juju/charmstore/git/refs{/sha}","trees_url":"https://api.github.com/repos/juju/charmstore/git/trees{/sha}","statuses_url":"https://api.github.com/repos/juju/charmstore/statuses/{sha}","languages_url":"https://api.github.com/repos/juju/charmstore/languages","stargazers_url":"https://api.github.com/repos/juju/charmstore/stargazers","contributors_url":"https://api.github.com/repos/juju/charmstore/contributors","subscribers_url":"https://api.github.com/repos/juju/charmstore/subscribers","subscription_url":"https://api.github.com/repos/juju/charmstore/subscription","commits_url":"https://api.github.com/repos/juju/charmstore/commits{/sha}","git_commits_url":"https://api.github.com/repos/juju/charmstore/git/commits{/sha}","comments_url":"https://api.github.com/repos/juju/charmstore/comments{/number}","issue_comment_url":"https://api.github.com/repos/juju/charmstore/issues/comments/{number}","contents_url":"https://api.github.com/repos/juju/charmstore/contents/{+path}","compare_url":"https://api.github.com/repos/juju/charmstore/compare/{base}...{head}","merges_url":"https://api.github.com/repos/juju/charmstore/merges","archive_url":"https://api.github.com/repos/juju/charmstore/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/juju/charmstore/downloads","issues_url":"https://api.github.com/repos/juju/charmstore/issues{/number}","pulls_url":"https://api.github.com/repos/juju/charmstore/pulls{/number}","milestones_url":"https://api.github.com/repos/juju/charmstore/milestones{/number}","notifications_url":"https://api.github.com/repos/juju/charmstore/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/juju/charmstore/labels{/name}","releases_url":"https://api.github.com/repos/juju/charmstore/releases{/id}","created_at":"2014-06-11T09:53:37Z","updated_at":"2014-09-02T14:35:19Z","pushed_at":"2014-09-12T13:08:35Z","git_url":"git://github.com/juju/charmstore.git","ssh_url":"git@github.com:juju/charmstore.git","clone_url":"https://github.com/juju/charmstore.git","svn_url":"https://github.com/juju/charmstore","homepage":null,"size":2347,"stargazers_count":3,"watchers_count":3,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"forks_count":9,"mirror_url":null,"open_issues_count":4,"forks":9,"open_issues":4,"watchers":3,"default_branch":"v4"}},"_links":{"self":{"href":"https://api.github.com/repos/juju/charmstore/pulls/95"},"html":{"href":"https://github.com/juju/charmstore/pull/95"},"issue":{"href":"https://api.github.com/repos/juju/charmstore/issues/95"},"comments":{"href":"https://api.github.com/repos/juju/charmstore/issues/95/comments"},"review_comments":{"href":"https://api.github.com/repos/juju/charmstore/pulls/95/comments"},"review_comment":{"href":"https://api.github.com/repos/juju/charmstore/pulls/comments/{number}"},"commits":{"href":"https://api.github.com/repos/juju/charmstore/pulls/95/commits"},"statuses":{"href":"https://api.github.com/repos/juju/charmstore/statuses/d621c22a997968cd08b11a2661b191d6a92833b6"}}}}