{"action":"created","comment":{"url":"https://api.github.com/repos/letsencrypt/boulder/pulls/comments/70537111","id":70537111,"diff_hunk":"@@ -43,40 +46,20 @@ func (c contactExporter) findContacts() ([]string, error) {\n \t\treturn nil, err\n \t}\n \n-\tcontactMap := make(map[string]struct{}, len(contactsJSON))\n-\tfor _, contactRaw := range contactsJSON {\n-\t\tvar contactList []string\n-\t\terr := json.Unmarshal(contactRaw, &contactList)\n-\t\tif err != nil {\n-\t\t\tc.log.AuditErr(\n-\t\t\t\tfmt.Sprintf(\"couldn't unmarshal contact JSON %#v: %s\\n\",\n-\t\t\t\t\tcontactRaw, err))\n-\t\t\tcontinue\n-\t\t}\n-\t\tfor _, entry := range contactList {\n-\t\t\t// Only include email addresses\n-\t\t\tif strings.HasPrefix(entry, \"mailto:\") {\n-\t\t\t\taddress := strings.TrimPrefix(entry, \"mailto:\")\n-\t\t\t\t// Using the contactMap to deduplicate addresses\n-\t\t\t\tcontactMap[address] = struct{}{}\n-\t\t\t}\n-\t\t}\n-\t}\n-\n-\t// Convert the de-dupe'd map back to a slice, sort it\n-\tvar contacts []string\n-\tfor contact := range contactMap {\n-\t\tcontacts = append(contacts, contact)\n-\t}\n-\tsort.Strings(contacts)\n-\treturn contacts, nil\n+\treturn contactsList, nil\n }\n \n-func writeContacts(contacts []string, outFile string) error {\n-\tdata := []byte(strings.Join(contacts, \"\\n\") + \"\\n\")\n+// The `writeContacts` function produces a file containing JSON serialized\n+// contact objects\n+func writeContacts(contactsList []contact, outfile string) error {\n+\tdata, err := json.Marshal(contactsList)\n+\tif err != nil {\n+\t\treturn err\n+\t}\n+\tdata = append(data, '\\n')","path":"cmd/contact-exporter/main.go","position":73,"original_position":73,"commit_id":"016eda8b61a78a6156953dcc0c83120861f90a37","original_commit_id":"bc568ce07341b19a03e0fe7b2fdf20a1e3fbd3a8","user":{"login":"jsha","id":220205,"avatar_url":"https://avatars.githubusercontent.com/u/220205?v=3","gravatar_id":"","url":"https://api.github.com/users/jsha","html_url":"https://github.com/jsha","followers_url":"https://api.github.com/users/jsha/followers","following_url":"https://api.github.com/users/jsha/following{/other_user}","gists_url":"https://api.github.com/users/jsha/gists{/gist_id}","starred_url":"https://api.github.com/users/jsha/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/jsha/subscriptions","organizations_url":"https://api.github.com/users/jsha/orgs","repos_url":"https://api.github.com/users/jsha/repos","events_url":"https://api.github.com/users/jsha/events{/privacy}","received_events_url":"https://api.github.com/users/jsha/received_events","type":"User","site_admin":false},"body":"I wondered the same thing when I saw this, but decided it's fine. Another small example why it's nice: If you cat a file, the closing brace winds up above your prompt rather than right before it. For instance if you run `curl https://acme-v01.api.letsencrypt.org/directory` you'll see this behavior. So I'm a weak +1 for ending files with newlines.","created_at":"2016-07-12T22:51:52Z","updated_at":"2016-07-12T22:51:52Z","html_url":"https://github.com/letsencrypt/boulder/pull/1958#discussion_r70537111","pull_request_url":"https://api.github.com/repos/letsencrypt/boulder/pulls/1958","_links":{"self":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/comments/70537111"},"html":{"href":"https://github.com/letsencrypt/boulder/pull/1958#discussion_r70537111"},"pull_request":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/1958"}}},"pull_request":{"url":"https://api.github.com/repos/letsencrypt/boulder/pulls/1958","id":74812496,"html_url":"https://github.com/letsencrypt/boulder/pull/1958","diff_url":"https://github.com/letsencrypt/boulder/pull/1958.diff","patch_url":"https://github.com/letsencrypt/boulder/pull/1958.patch","issue_url":"https://api.github.com/repos/letsencrypt/boulder/issues/1958","number":1958,"state":"open","locked":false,"title":"Support Reg ID intermediate form for notify mails","user":{"login":"ccppuu","id":292650,"avatar_url":"https://avatars.githubusercontent.com/u/292650?v=3","gravatar_id":"","url":"https://api.github.com/users/ccppuu","html_url":"https://github.com/ccppuu","followers_url":"https://api.github.com/users/ccppuu/followers","following_url":"https://api.github.com/users/ccppuu/following{/other_user}","gists_url":"https://api.github.com/users/ccppuu/gists{/gist_id}","starred_url":"https://api.github.com/users/ccppuu/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ccppuu/subscriptions","organizations_url":"https://api.github.com/users/ccppuu/orgs","repos_url":"https://api.github.com/users/ccppuu/repos","events_url":"https://api.github.com/users/ccppuu/events{/privacy}","received_events_url":"https://api.github.com/users/ccppuu/received_events","type":"User","site_admin":false},"body":"Presently the `contact-exporter` dumps a list of email addresses to an intermediate file. That file can be provided as input to `notify-mailer` to send messages to the listed email addresses. This has the downside that if a user updates their registration contact address between the time the export is run and the notification emails are sent the message will go to the wrong address.\r\n\r\nThis PR addresses this by adding a new default output mode to the `contact-exporter` that writes JSON serialized objects containing both a registration ID and an email address to an intermediate file. The `notify-mailer` is updated to support reading this file, deserializing the JSON, and resolving the reg IDs to fresh email addresses before sending messages.\r\n\r\nThe \"classic\" behaviour of using bare email addresses as the intermediate form is supported with both the `contact-exporter` and the `notify-mailer` by providing the `--emails` bool flag at the command line.\r\n\r\nResolves #1951","created_at":"2016-06-22T16:09:52Z","updated_at":"2016-07-12T22:51:52Z","closed_at":null,"merged_at":null,"merge_commit_sha":"fec5c0b3ab37d5458b6fff520626f6045473ed94","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/letsencrypt/boulder/pulls/1958/commits","review_comments_url":"https://api.github.com/repos/letsencrypt/boulder/pulls/1958/comments","review_comment_url":"https://api.github.com/repos/letsencrypt/boulder/pulls/comments{/number}","comments_url":"https://api.github.com/repos/letsencrypt/boulder/issues/1958/comments","statuses_url":"https://api.github.com/repos/letsencrypt/boulder/statuses/016eda8b61a78a6156953dcc0c83120861f90a37","head":{"label":"letsencrypt:mailer-regids","ref":"mailer-regids","sha":"016eda8b61a78a6156953dcc0c83120861f90a37","user":{"login":"letsencrypt","id":9289019,"avatar_url":"https://avatars.githubusercontent.com/u/9289019?v=3","gravatar_id":"","url":"https://api.github.com/users/letsencrypt","html_url":"https://github.com/letsencrypt","followers_url":"https://api.github.com/users/letsencrypt/followers","following_url":"https://api.github.com/users/letsencrypt/following{/other_user}","gists_url":"https://api.github.com/users/letsencrypt/gists{/gist_id}","starred_url":"https://api.github.com/users/letsencrypt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/letsencrypt/subscriptions","organizations_url":"https://api.github.com/users/letsencrypt/orgs","repos_url":"https://api.github.com/users/letsencrypt/repos","events_url":"https://api.github.com/users/letsencrypt/events{/privacy}","received_events_url":"https://api.github.com/users/letsencrypt/received_events","type":"Organization","site_admin":false},"repo":{"id":28283593,"name":"boulder","full_name":"letsencrypt/boulder","owner":{"login":"letsencrypt","id":9289019,"avatar_url":"https://avatars.githubusercontent.com/u/9289019?v=3","gravatar_id":"","url":"https://api.github.com/users/letsencrypt","html_url":"https://github.com/letsencrypt","followers_url":"https://api.github.com/users/letsencrypt/followers","following_url":"https://api.github.com/users/letsencrypt/following{/other_user}","gists_url":"https://api.github.com/users/letsencrypt/gists{/gist_id}","starred_url":"https://api.github.com/users/letsencrypt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/letsencrypt/subscriptions","organizations_url":"https://api.github.com/users/letsencrypt/orgs","repos_url":"https://api.github.com/users/letsencrypt/repos","events_url":"https://api.github.com/users/letsencrypt/events{/privacy}","received_events_url":"https://api.github.com/users/letsencrypt/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/letsencrypt/boulder","description":"An ACME-based CA, written in Go.","fork":false,"url":"https://api.github.com/repos/letsencrypt/boulder","forks_url":"https://api.github.com/repos/letsencrypt/boulder/forks","keys_url":"https://api.github.com/repos/letsencrypt/boulder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/letsencrypt/boulder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/letsencrypt/boulder/teams","hooks_url":"https://api.github.com/repos/letsencrypt/boulder/hooks","issue_events_url":"https://api.github.com/repos/letsencrypt/boulder/issues/events{/number}","events_url":"https://api.github.com/repos/letsencrypt/boulder/events","assignees_url":"https://api.github.com/repos/letsencrypt/boulder/assignees{/user}","branches_url":"https://api.github.com/repos/letsencrypt/boulder/branches{/branch}","tags_url":"https://api.github.com/repos/letsencrypt/boulder/tags","blobs_url":"https://api.github.com/repos/letsencrypt/boulder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/letsencrypt/boulder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/letsencrypt/boulder/git/refs{/sha}","trees_url":"https://api.github.com/repos/letsencrypt/boulder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/letsencrypt/boulder/statuses/{sha}","languages_url":"https://api.github.com/repos/letsencrypt/boulder/languages","stargazers_url":"https://api.github.com/repos/letsencrypt/boulder/stargazers","contributors_url":"https://api.github.com/repos/letsencrypt/boulder/contributors","subscribers_url":"https://api.github.com/repos/letsencrypt/boulder/subscribers","subscription_url":"https://api.github.com/repos/letsencrypt/boulder/subscription","commits_url":"https://api.github.com/repos/letsencrypt/boulder/commits{/sha}","git_commits_url":"https://api.github.com/repos/letsencrypt/boulder/git/commits{/sha}","comments_url":"https://api.github.com/repos/letsencrypt/boulder/comments{/number}","issue_comment_url":"https://api.github.com/repos/letsencrypt/boulder/issues/comments{/number}","contents_url":"https://api.github.com/repos/letsencrypt/boulder/contents/{+path}","compare_url":"https://api.github.com/repos/letsencrypt/boulder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/letsencrypt/boulder/merges","archive_url":"https://api.github.com/repos/letsencrypt/boulder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/letsencrypt/boulder/downloads","issues_url":"https://api.github.com/repos/letsencrypt/boulder/issues{/number}","pulls_url":"https://api.github.com/repos/letsencrypt/boulder/pulls{/number}","milestones_url":"https://api.github.com/repos/letsencrypt/boulder/milestones{/number}","notifications_url":"https://api.github.com/repos/letsencrypt/boulder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/letsencrypt/boulder/labels{/name}","releases_url":"https://api.github.com/repos/letsencrypt/boulder/releases{/id}","deployments_url":"https://api.github.com/repos/letsencrypt/boulder/deployments","created_at":"2014-12-21T00:29:54Z","updated_at":"2016-07-12T11:27:22Z","pushed_at":"2016-07-12T22:40:41Z","git_url":"git://github.com/letsencrypt/boulder.git","ssh_url":"git@github.com:letsencrypt/boulder.git","clone_url":"https://github.com/letsencrypt/boulder.git","svn_url":"https://github.com/letsencrypt/boulder","homepage":null,"size":22628,"stargazers_count":1276,"watchers_count":1276,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":160,"mirror_url":null,"open_issues_count":179,"forks":160,"open_issues":179,"watchers":1276,"default_branch":"master"}},"base":{"label":"letsencrypt:master","ref":"master","sha":"0e2ef748b42f6334b60fa242ff821a6ebceed614","user":{"login":"letsencrypt","id":9289019,"avatar_url":"https://avatars.githubusercontent.com/u/9289019?v=3","gravatar_id":"","url":"https://api.github.com/users/letsencrypt","html_url":"https://github.com/letsencrypt","followers_url":"https://api.github.com/users/letsencrypt/followers","following_url":"https://api.github.com/users/letsencrypt/following{/other_user}","gists_url":"https://api.github.com/users/letsencrypt/gists{/gist_id}","starred_url":"https://api.github.com/users/letsencrypt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/letsencrypt/subscriptions","organizations_url":"https://api.github.com/users/letsencrypt/orgs","repos_url":"https://api.github.com/users/letsencrypt/repos","events_url":"https://api.github.com/users/letsencrypt/events{/privacy}","received_events_url":"https://api.github.com/users/letsencrypt/received_events","type":"Organization","site_admin":false},"repo":{"id":28283593,"name":"boulder","full_name":"letsencrypt/boulder","owner":{"login":"letsencrypt","id":9289019,"avatar_url":"https://avatars.githubusercontent.com/u/9289019?v=3","gravatar_id":"","url":"https://api.github.com/users/letsencrypt","html_url":"https://github.com/letsencrypt","followers_url":"https://api.github.com/users/letsencrypt/followers","following_url":"https://api.github.com/users/letsencrypt/following{/other_user}","gists_url":"https://api.github.com/users/letsencrypt/gists{/gist_id}","starred_url":"https://api.github.com/users/letsencrypt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/letsencrypt/subscriptions","organizations_url":"https://api.github.com/users/letsencrypt/orgs","repos_url":"https://api.github.com/users/letsencrypt/repos","events_url":"https://api.github.com/users/letsencrypt/events{/privacy}","received_events_url":"https://api.github.com/users/letsencrypt/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/letsencrypt/boulder","description":"An ACME-based CA, written in Go.","fork":false,"url":"https://api.github.com/repos/letsencrypt/boulder","forks_url":"https://api.github.com/repos/letsencrypt/boulder/forks","keys_url":"https://api.github.com/repos/letsencrypt/boulder/keys{/key_id}","collaborators_url":"https://api.github.com/repos/letsencrypt/boulder/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/letsencrypt/boulder/teams","hooks_url":"https://api.github.com/repos/letsencrypt/boulder/hooks","issue_events_url":"https://api.github.com/repos/letsencrypt/boulder/issues/events{/number}","events_url":"https://api.github.com/repos/letsencrypt/boulder/events","assignees_url":"https://api.github.com/repos/letsencrypt/boulder/assignees{/user}","branches_url":"https://api.github.com/repos/letsencrypt/boulder/branches{/branch}","tags_url":"https://api.github.com/repos/letsencrypt/boulder/tags","blobs_url":"https://api.github.com/repos/letsencrypt/boulder/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/letsencrypt/boulder/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/letsencrypt/boulder/git/refs{/sha}","trees_url":"https://api.github.com/repos/letsencrypt/boulder/git/trees{/sha}","statuses_url":"https://api.github.com/repos/letsencrypt/boulder/statuses/{sha}","languages_url":"https://api.github.com/repos/letsencrypt/boulder/languages","stargazers_url":"https://api.github.com/repos/letsencrypt/boulder/stargazers","contributors_url":"https://api.github.com/repos/letsencrypt/boulder/contributors","subscribers_url":"https://api.github.com/repos/letsencrypt/boulder/subscribers","subscription_url":"https://api.github.com/repos/letsencrypt/boulder/subscription","commits_url":"https://api.github.com/repos/letsencrypt/boulder/commits{/sha}","git_commits_url":"https://api.github.com/repos/letsencrypt/boulder/git/commits{/sha}","comments_url":"https://api.github.com/repos/letsencrypt/boulder/comments{/number}","issue_comment_url":"https://api.github.com/repos/letsencrypt/boulder/issues/comments{/number}","contents_url":"https://api.github.com/repos/letsencrypt/boulder/contents/{+path}","compare_url":"https://api.github.com/repos/letsencrypt/boulder/compare/{base}...{head}","merges_url":"https://api.github.com/repos/letsencrypt/boulder/merges","archive_url":"https://api.github.com/repos/letsencrypt/boulder/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/letsencrypt/boulder/downloads","issues_url":"https://api.github.com/repos/letsencrypt/boulder/issues{/number}","pulls_url":"https://api.github.com/repos/letsencrypt/boulder/pulls{/number}","milestones_url":"https://api.github.com/repos/letsencrypt/boulder/milestones{/number}","notifications_url":"https://api.github.com/repos/letsencrypt/boulder/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/letsencrypt/boulder/labels{/name}","releases_url":"https://api.github.com/repos/letsencrypt/boulder/releases{/id}","deployments_url":"https://api.github.com/repos/letsencrypt/boulder/deployments","created_at":"2014-12-21T00:29:54Z","updated_at":"2016-07-12T11:27:22Z","pushed_at":"2016-07-12T22:40:41Z","git_url":"git://github.com/letsencrypt/boulder.git","ssh_url":"git@github.com:letsencrypt/boulder.git","clone_url":"https://github.com/letsencrypt/boulder.git","svn_url":"https://github.com/letsencrypt/boulder","homepage":null,"size":22628,"stargazers_count":1276,"watchers_count":1276,"language":"Go","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":160,"mirror_url":null,"open_issues_count":179,"forks":160,"open_issues":179,"watchers":1276,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/1958"},"html":{"href":"https://github.com/letsencrypt/boulder/pull/1958"},"issue":{"href":"https://api.github.com/repos/letsencrypt/boulder/issues/1958"},"comments":{"href":"https://api.github.com/repos/letsencrypt/boulder/issues/1958/comments"},"review_comments":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/1958/comments"},"review_comment":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/letsencrypt/boulder/pulls/1958/commits"},"statuses":{"href":"https://api.github.com/repos/letsencrypt/boulder/statuses/016eda8b61a78a6156953dcc0c83120861f90a37"}}}}
{"actor":{"display_login":"jsha"}}