// MarkRepositoryNotificationsRead marks all notifications up to lastRead in
// the specified repository as read.
//
// GitHub API docs: https://developer.github.com/v3/activity/notifications/#mark-notifications-as-read-in-a-repository
768328
func (s *ActivityService) MarkRepositoryNotificationsRead(ctx context.Context, owner, repo string, lastRead time.Time) (*Response, error) {
	opts := &markReadOptions{
		LastReadAt: lastRead,
	}
	u := fmt.Sprintf("repos/%v/%v/notifications", owner, repo)
	req, err := s.client.NewRequest("PUT", u, opts)
	if err != nil {
		return nil, err
	}

	return s.client.Do(ctx, req, nil)
}
1348248
func GetGitHubUpdates(ctx context.Context, client *http.Client, pushedAfter string) (maxPushedAt string, names []string, err error) {
	c := httpClient{client: client, header: gitHubPreviewHeader}

	if pushedAfter == "" {
		pushedAfter = time.Now().Add(-24 * time.Hour).UTC().Format("2006-01-02T15:04:05Z")
	}
	u := "https://api.github.com/search/repositories?order=asc&sort=updated&q=fork:true+language:Go+pushed:>" + pushedAfter
	var updates struct {
		Items []struct {
			FullName string `json:"full_name"`
			PushedAt string `json:"pushed_at"`
		}
	}
	_, err = c.getJSON(ctx, u, &updates)
	if err != nil {
		return pushedAfter, nil, err
	}

	maxPushedAt = pushedAfter
	for _, item := range updates.Items {
		names = append(names, item.FullName)
		if item.PushedAt > maxPushedAt {
			maxPushedAt = item.PushedAt
		}
	}
	return maxPushedAt, names, nil
}
1190593
func Notify(appName string, title string, text string, iconPath string) {
	note := notification(appName, title, text, iconPath)
	if err := note.Push(); err != nil {
		log.Println("ERROR:", err)
	}
}
143280
func (b *BlockChain) sendNotification(typ NotificationType, data interface{}) {
	// Generate and send the notification.
	n := Notification{Type: typ, Data: data}
	b.notificationsLock.RLock()
	for _, callback := range b.notifications {
		callback(&n)
	}
	b.notificationsLock.RUnlock()
}
512440
func MarkAndSweep(ctx context.Context, storageDriver driver.StorageDriver, registry distribution.Namespace, opts GCOpts) error {
	repositoryEnumerator, ok := registry.(distribution.RepositoryEnumerator)
	if !ok {
		return fmt.Errorf("unable to convert Namespace to RepositoryEnumerator")
	}

	// mark
	markSet := make(map[digest.Digest]struct{})
	manifestArr := make([]ManifestDel, 0)
	err := repositoryEnumerator.Enumerate(ctx, func(repoName string) error {
		emit(repoName)

		var err error
		named, err := reference.WithName(repoName)
		if err != nil {
			return fmt.Errorf("failed to parse repo name %s: %v", repoName, err)
		}
		repository, err := registry.Repository(ctx, named)
		if err != nil {
			return fmt.Errorf("failed to construct repository: %v", err)
		}

		manifestService, err := repository.Manifests(ctx)
		if err != nil {
			return fmt.Errorf("failed to construct manifest service: %v", err)
		}

		manifestEnumerator, ok := manifestService.(distribution.ManifestEnumerator)
		if !ok {
			return fmt.Errorf("unable to convert ManifestService into ManifestEnumerator")
		}

		err = manifestEnumerator.Enumerate(ctx, func(dgst digest.Digest) error {
			if opts.RemoveUntagged {
				// fetch all tags where this manifest is the latest one
				tags, err := repository.Tags(ctx).Lookup(ctx, distribution.Descriptor{Digest: dgst})
				if err != nil {
					return fmt.Errorf("failed to retrieve tags for digest %v: %v", dgst, err)
				}
				if len(tags) == 0 {
					emit("manifest eligible for deletion: %s", dgst)
					// fetch all tags from repository
					// all of these tags could contain manifest in history
					// which means that we need check (and delete) those references when deleting manifest
					allTags, err := repository.Tags(ctx).All(ctx)
					if err != nil {
						return fmt.Errorf("failed to retrieve tags %v", err)
					}
					manifestArr = append(manifestArr, ManifestDel{Name: repoName, Digest: dgst, Tags: allTags})
					return nil
				}
			}
			// Mark the manifest's blob
			emit("%s: marking manifest %s ", repoName, dgst)
			markSet[dgst] = struct{}{}

			manifest, err := manifestService.Get(ctx, dgst)
			if err != nil {
				return fmt.Errorf("failed to retrieve manifest for digest %v: %v", dgst, err)
			}

			descriptors := manifest.References()
			for _, descriptor := range descriptors {
				markSet[descriptor.Digest] = struct{}{}
				emit("%s: marking blob %s", repoName, descriptor.Digest)
			}

			return nil
		})

		// In certain situations such as unfinished uploads, deleting all
		// tags in S3 or removing the _manifests folder manually, this
		// error may be of type PathNotFound.
		//
		// In these cases we can continue marking other manifests safely.
		if _, ok := err.(driver.PathNotFoundError); ok {
			return nil
		}

		return err
	})

	if err != nil {
		return fmt.Errorf("failed to mark: %v", err)
	}

	// sweep
	vacuum := NewVacuum(ctx, storageDriver)
	if !opts.DryRun {
		for _, obj := range manifestArr {
			err = vacuum.RemoveManifest(obj.Name, obj.Digest, obj.Tags)
			if err != nil {
				return fmt.Errorf("failed to delete manifest %s: %v", obj.Digest, err)
			}
		}
	}
	blobService := registry.Blobs()
	deleteSet := make(map[digest.Digest]struct{})
	err = blobService.Enumerate(ctx, func(dgst digest.Digest) error {
		// check if digest is in markSet. If not, delete it!
		if _, ok := markSet[dgst]; !ok {
			deleteSet[dgst] = struct{}{}
		}
		return nil
	})
	if err != nil {
		return fmt.Errorf("error enumerating blobs: %v", err)
	}
	emit("\n%d blobs marked, %d blobs and %d manifests eligible for deletion", len(markSet), len(deleteSet), len(manifestArr))
	for dgst := range deleteSet {
		emit("blob eligible for deletion: %s", dgst)
		if opts.DryRun {
			continue
		}
		err = vacuum.RemoveBlob(string(dgst))
		if err != nil {
			return fmt.Errorf("failed to delete blob %s: %v", dgst, err)
		}
	}

	return err
}
454576
func hookEventFromPostReceive(repo git.Repository, path, postReceivePath string) (*buildapi.GenericWebHookEvent, error) {
	// TODO: support other types of refs
	event := &buildapi.GenericWebHookEvent{
		Git: &buildapi.GitInfo{},
	}

	// attempt to extract a post receive body
	refs := []git.ChangedRef{}
	switch receive := postReceivePath; {
	case receive == "-":
		r, err := git.ParsePostReceive(os.Stdin)
		if err != nil {
			return nil, err
		}
		refs = r
	case len(receive) > 0:
		file, err := os.Open(receive)
		if err != nil {
			return nil, fmt.Errorf("unable to open --git-post-receive argument as a file: %v", err)
		}
		defer file.Close()
		r, err := git.ParsePostReceive(file)
		if err != nil {
			return nil, err
		}
		refs = r
	}
	if len(refs) == 0 {
		return nil, nil
	}
	for _, ref := range refs {
		if len(ref.New) == 0 || ref.New == ref.Old {
			continue
		}
		info, err := gitRefInfo(repo, path, ref.New)
		if err != nil {
			klog.V(4).Infof("Could not retrieve info for %s:%s: %v", ref.Ref, ref.New, err)
		}
		info.Ref = ref.Ref
		info.Commit = ref.New
		event.Git.Refs = append(event.Git.Refs, info)
	}
	return event, nil
}
651700
func (d *Dispatcher) markNodeNotReady(id string, state api.NodeStatus_State, message string) error {
	logLocal := log.G(d.ctx).WithField("method", "(*Dispatcher).markNodeNotReady")

	dctx, err := d.isRunningLocked()
	if err != nil {
		return err
	}

	// Node is down. Add it to down nodes so that we can keep
	// track of tasks assigned to the node.
	var node *api.Node
	d.store.View(func(readTx store.ReadTx) {
		node = store.GetNode(readTx, id)
		if node == nil {
			err = fmt.Errorf("could not find node %s while trying to add to down nodes store", id)
		}
	})
	if err != nil {
		return err
	}

	expireFunc := func() {
		log.G(dctx).Debugf(`worker timed-out %s in "down" state, moving all tasks to "ORPHANED" state`, id)
		if err := d.moveTasksToOrphaned(id); err != nil {
			log.G(dctx).WithError(err).Error(`failed to move all tasks to "ORPHANED" state`)
		}

		d.downNodes.Delete(id)
	}

	d.downNodes.Add(node, expireFunc)
	logLocal.Debugf("added node %s to down nodes list", node.ID)

	status := &api.NodeStatus{
		State:   state,
		Message: message,
	}

	d.nodeUpdatesLock.Lock()
	// pluck the description out of nodeUpdates. this protects against a case
	// where a node is marked ready and a description is added, but then the
	// node is immediately marked not ready. this preserves that description
	d.nodeUpdates[id] = nodeUpdate{status: status, description: d.nodeUpdates[id].description}
	numUpdates := len(d.nodeUpdates)
	d.nodeUpdatesLock.Unlock()

	if numUpdates >= maxBatchItems {
		select {
		case d.processUpdatesTrigger <- struct{}{}:
		case <-dctx.Done():
		}
	}

	if rn := d.nodes.Delete(id); rn == nil {
		return errors.Errorf("node %s is not found in local storage", id)
	}
	logLocal.Debugf("deleted node %s from node store", node.ID)

	return nil
}
677322
func (th *TlfHistory) FlushRevision(rev kbfsmd.Revision) {
	th.lock.Lock()
	defer th.lock.Unlock()
	if th.unflushed == nil {
		return
	}
	lastToKeep := len(th.unflushed.notifications) - 1
	for ; lastToKeep >= 0; lastToKeep-- {
		if th.unflushed.notifications[lastToKeep].Revision > rev {
			break
		}
	}
	if lastToKeep < len(th.unflushed.notifications)-1 {
		th.unflushed.notifications = th.unflushed.notifications[:lastToKeep+1]
		// Invalidate the cached results.
		th.computed = false
		th.cachedLoggedInUser = ""
	}
}
1242228
func (c Client) ListenBucketNotification(bucketName, prefix, suffix string, events []string, doneCh <-chan struct{}) <-chan NotificationInfo {
	notificationInfoCh := make(chan NotificationInfo, 1)
	// Only success, start a routine to start reading line by line.
	go func(notificationInfoCh chan<- NotificationInfo) {
		defer close(notificationInfoCh)

		// Validate the bucket name.
		if err := s3utils.CheckValidBucketName(bucketName); err != nil {
			notificationInfoCh <- NotificationInfo{
				Err: err,
			}
			return
		}

		// Check ARN partition to verify if listening bucket is supported
		if s3utils.IsAmazonEndpoint(*c.endpointURL) || s3utils.IsGoogleEndpoint(*c.endpointURL) {
			notificationInfoCh <- NotificationInfo{
				Err: ErrAPINotSupported("Listening for bucket notification is specific only to `minio` server endpoints"),
			}
			return
		}

		// Continuously run and listen on bucket notification.
		// Create a done channel to control 'ListObjects' go routine.
		retryDoneCh := make(chan struct{}, 1)

		// Indicate to our routine to exit cleanly upon return.
		defer close(retryDoneCh)

		// Wait on the jitter retry loop.
		for range c.newRetryTimerContinous(time.Second, time.Second*30, MaxJitter, retryDoneCh) {
			urlValues := make(url.Values)
			urlValues.Set("prefix", prefix)
			urlValues.Set("suffix", suffix)
			urlValues["events"] = events

			// Execute GET on bucket to list objects.
			resp, err := c.executeMethod(context.Background(), "GET", requestMetadata{
				bucketName:       bucketName,
				queryValues:      urlValues,
				contentSHA256Hex: emptySHA256Hex,
			})
			if err != nil {
				notificationInfoCh <- NotificationInfo{
					Err: err,
				}
				return
			}

			// Validate http response, upon error return quickly.
			if resp.StatusCode != http.StatusOK {
				errResponse := httpRespToErrorResponse(resp, bucketName, "")
				notificationInfoCh <- NotificationInfo{
					Err: errResponse,
				}
				return
			}

			// Initialize a new bufio scanner, to read line by line.
			bio := bufio.NewScanner(resp.Body)

			// Close the response body.
			defer resp.Body.Close()

			// Unmarshal each line, returns marshalled values.
			for bio.Scan() {
				var notificationInfo NotificationInfo
				if err = json.Unmarshal(bio.Bytes(), &notificationInfo); err != nil {
					continue
				}
				// Send notificationInfo
				select {
				case notificationInfoCh <- notificationInfo:
				case <-doneCh:
					return
				}
			}
			// Look for any underlying errors.
			if err = bio.Err(); err != nil {
				// For an unexpected connection drop from server, we close the body
				// and re-connect.
				if err == io.ErrUnexpectedEOF {
					resp.Body.Close()
				}
			}
		}
	}(notificationInfoCh)

	// Returns the notification info channel, for caller to start reading from.
	return notificationInfoCh
}
649989
func (u *UpgradeSeriesAPI) WatchUpgradeSeriesNotifications() (watcher.NotifyWatcher, error) {
	var results params.NotifyWatchResults
	args := params.Entities{
		Entities: []params.Entity{{Tag: u.tag.String()}},
	}
	err := u.facade.FacadeCall("WatchUpgradeSeriesNotifications", args, &results)
	if err != nil {
		return nil, err
	}
	if len(results.Results) != 1 {
		return nil, errors.Errorf("expected 1 result, got %d", len(results.Results))
	}
	result := results.Results[0]
	if result.Error != nil {
		return nil, result.Error
	}
	w := apiwatcher.NewNotifyWatcher(u.facade.RawAPICaller(), result)
	return w, nil
}
1180015
func NewNotification(body *bytes.Buffer) *http.Response {
	resp := new(http.Response)
	resp.Status = "200 OK"
	resp.StatusCode = http.StatusOK
	resp.ProtoMajor = 1
	resp.ProtoMinor = 0
	resp.Body = ioutil.NopCloser(body)
	resp.ContentLength = int64(body.Len())
	resp.Header = map[string][]string{}
	resp.Header.Set("Content-Type", HTTPContentTypeHAPJson)

	// Will be ignored unfortunately and won't be fixed https://github.com/golang/go/issues/9304
	// Make sure to call FixProtocolSpecifier() instead
	resp.Proto = "EVENT/1.0"

	return resp
}
898904
func checkStatefulSetReadiness(obj runtime.Object) (bool, bool, error) {
	var (
		isSynced         bool
		hasReplicasReady bool
	)

	switch s := obj.(type) {
	case *kappsv1.StatefulSet:
		isSynced = s.Status.ObservedGeneration == s.Generation
		hasReplicasReady = s.Spec.Replicas != nil && s.Status.ReadyReplicas == *s.Spec.Replicas
	case *kappsv1beta1.StatefulSet:
		isSynced = s.Status.ObservedGeneration != nil && *s.Status.ObservedGeneration == s.Generation
		hasReplicasReady = s.Spec.Replicas != nil && s.Status.ReadyReplicas == *s.Spec.Replicas
	case *kappsv1beta2.StatefulSet:
		isSynced = s.Status.ObservedGeneration == s.Generation
		hasReplicasReady = s.Spec.Replicas != nil && s.Status.ReadyReplicas == *s.Spec.Replicas
	default:
		return false, false, fmt.Errorf("unsupported statefulset version: %T", s)
	}

	return isSynced && hasReplicasReady, false, nil
}
1304197
func NewRelease(gitRepo *git.Repository, r *Release, uuids []string) error {
	isExist, err := IsReleaseExist(r.RepoID, r.TagName)
	if err != nil {
		return err
	} else if isExist {
		return ErrReleaseAlreadyExist{r.TagName}
	}

	if err = createTag(gitRepo, r); err != nil {
		return err
	}
	r.LowerTagName = strings.ToLower(r.TagName)

	sess := x.NewSession()
	defer sess.Close()
	if err = sess.Begin(); err != nil {
		return err
	}

	if _, err = sess.Insert(r); err != nil {
		return fmt.Errorf("Insert: %v", err)
	}

	if len(uuids) > 0 {
		if _, err = sess.In("uuid", uuids).Cols("release_id").Update(&Attachment{ReleaseID: r.ID}); err != nil {
			return fmt.Errorf("link attachments: %v", err)
		}
	}

	if err = sess.Commit(); err != nil {
		return fmt.Errorf("Commit: %v", err)
	}

	// Only send webhook when actually published, skip drafts
	if r.IsDraft {
		return nil
	}
	r, err = GetReleaseByID(r.ID)
	if err != nil {
		return fmt.Errorf("GetReleaseByID: %v", err)
	}
	r.preparePublishWebhooks()
	return nil
}
671023
func (c *ApiController) TriggerGithubPushHook() {
	log.Info("Trigger github push hook")

	/*
		{
		  "zen": "Mind your words, they are important.",
		  "hook_id": 5371014,
		  "hook": {
			"url": "https://api.github.com/repos/ArchCI/success-test/hooks/5371014",
			"test_url": "https://api.github.com/repos/ArchCI/success-test/hooks/5371014/test",
			"ping_url": "https://api.github.com/repos/ArchCI/success-test/hooks/5371014/pings",
			"id": 5371014,
			"name": "web",
			"active": true,
			"events": [
			  "push"
			],
			"config": {
			  "url": "http://192.168.1.113:10010/v1/hook/github/push",
			  "content_type": "json",
			  "insecure_ssl": "0",
			  "secret": "********"
			},
			"last_response": {
			  "code": null,
			  "status": "unused",
			  "message": null
			},
			"updated_at": "2015-07-22T14:48:22Z",
			"created_at": "2015-07-22T14:48:22Z"
		  },
		  "repository": {
			"id": 39022734,
			"name": "success-test",
			"full_name": "ArchCI/success-test",
			"owner": {
			  "login": "ArchCI",
			  "id": 12673804,
			  "avatar_url": "https://avatars.githubusercontent.com/u/12673804?v=3",
			  "gravatar_id": "",
			  "url": "https://api.github.com/users/ArchCI",
			  "html_url": "https://github.com/ArchCI",
			  "followers_url": "https://api.github.com/users/ArchCI/followers",
			  "following_url": "https://api.github.com/users/ArchCI/following{/other_user}",
			  "gists_url": "https://api.github.com/users/ArchCI/gists{/gist_id}",
			  "starred_url": "https://api.github.com/users/ArchCI/starred{/owner}{/repo}",
			  "subscriptions_url": "https://api.github.com/users/ArchCI/subscriptions",
			  "organizations_url": "https://api.github.com/users/ArchCI/orgs",
			  "repos_url": "https://api.github.com/users/ArchCI/repos",
			  "events_url": "https://api.github.com/users/ArchCI/events{/privacy}",
			  "received_events_url": "https://api.github.com/users/ArchCI/received_events",
			  "type": "Organization",
			  "site_admin": false
			},
			"private": false,
			"html_url": "https://github.com/ArchCI/success-test",
			"description": "Success test project for ArchCI",
			"fork": false,
			"url": "https://api.github.com/repos/ArchCI/success-test",
			"forks_url": "https://api.github.com/repos/ArchCI/success-test/forks",
			"keys_url": "https://api.github.com/repos/ArchCI/success-test/keys{/key_id}",
			"collaborators_url": "https://api.github.com/repos/ArchCI/success-test/collaborators{/collaborator}",
			"teams_url": "https://api.github.com/repos/ArchCI/success-test/teams",
			"hooks_url": "https://api.github.com/repos/ArchCI/success-test/hooks",
			"issue_events_url": "https://api.github.com/repos/ArchCI/success-test/issues/events{/number}",
			"events_url": "https://api.github.com/repos/ArchCI/success-test/events",
			"assignees_url": "https://api.github.com/repos/ArchCI/success-test/assignees{/user}",
			"branches_url": "https://api.github.com/repos/ArchCI/success-test/branches{/branch}",
			"tags_url": "https://api.github.com/repos/ArchCI/success-test/tags",
			"blobs_url": "https://api.github.com/repos/ArchCI/success-test/git/blobs{/sha}",
			"git_tags_url": "https://api.github.com/repos/ArchCI/success-test/git/tags{/sha}",
			"git_refs_url": "https://api.github.com/repos/ArchCI/success-test/git/refs{/sha}",
			"trees_url": "https://api.github.com/repos/ArchCI/success-test/git/trees{/sha}",
			"statuses_url": "https://api.github.com/repos/ArchCI/success-test/statuses/{sha}",
			"languages_url": "https://api.github.com/repos/ArchCI/success-test/languages",
			"stargazers_url": "https://api.github.com/repos/ArchCI/success-test/stargazers",
			"contributors_url": "https://api.github.com/repos/ArchCI/success-test/contributors",
			"subscribers_url": "https://api.github.com/repos/ArchCI/success-test/subscribers",
			"subscription_url": "https://api.github.com/repos/ArchCI/success-test/subscription",
			"commits_url": "https://api.github.com/repos/ArchCI/success-test/commits{/sha}",
			"git_commits_url": "https://api.github.com/repos/ArchCI/success-test/git/commits{/sha}",
			"comments_url": "https://api.github.com/repos/ArchCI/success-test/comments{/number}",
			"issue_comment_url": "https://api.github.com/repos/ArchCI/success-test/issues/comments{/number}",
			"contents_url": "https://api.github.com/repos/ArchCI/success-test/contents/{+path}",
			"compare_url": "https://api.github.com/repos/ArchCI/success-test/compare/{base}...{head}",
			"merges_url": "https://api.github.com/repos/ArchCI/success-test/merges",
			"archive_url": "https://api.github.com/repos/ArchCI/success-test/{archive_format}{/ref}",
			"downloads_url": "https://api.github.com/repos/ArchCI/success-test/downloads",
			"issues_url": "https://api.github.com/repos/ArchCI/success-test/issues{/number}",
			"pulls_url": "https://api.github.com/repos/ArchCI/success-test/pulls{/number}",
			"milestones_url": "https://api.github.com/repos/ArchCI/success-test/milestones{/number}",
			"notifications_url": "https://api.github.com/repos/ArchCI/success-test/notifications{?since,all,participating}",
			"labels_url": "https://api.github.com/repos/ArchCI/success-test/labels{/name}",
			"releases_url": "https://api.github.com/repos/ArchCI/success-test/releases{/id}",
			"created_at": "2015-07-13T16:06:28Z",
			"updated_at": "2015-07-22T02:12:02Z",
			"pushed_at": "2015-07-22T02:12:02Z",
			"git_url": "git://github.com/ArchCI/success-test.git",
			"ssh_url": "git@github.com:ArchCI/success-test.git",
			"clone_url": "https://github.com/ArchCI/success-test.git",
			"svn_url": "https://github.com/ArchCI/success-test",
			"homepage": null,
			"size": 120,
			"stargazers_count": 0,
			"watchers_count": 0,
			"language": "Go",
			"has_issues": true,
			"has_downloads": true,
			"has_wiki": true,
			"has_pages": false,
			"forks_count": 0,
			"mirror_url": null,
			"open_issues_count": 0,
			"forks": 0,
			"open_issues": 0,
			"watchers": 0,
			"default_branch": "master"
		  },
		  "sender": {
			"login": "tobegit3hub",
			"id": 2715000,
			"avatar_url": "https://avatars.githubusercontent.com/u/2715000?v=3",
			"gravatar_id": "",
			"url": "https://api.github.com/users/tobegit3hub",
			"html_url": "https://github.com/tobegit3hub",
			"followers_url": "https://api.github.com/users/tobegit3hub/followers",
			"following_url": "https://api.github.com/users/tobegit3hub/following{/other_user}",
			"gists_url": "https://api.github.com/users/tobegit3hub/gists{/gist_id}",
			"starred_url": "https://api.github.com/users/tobegit3hub/starred{/owner}{/repo}",
			"subscriptions_url": "https://api.github.com/users/tobegit3hub/subscriptions",
			"organizations_url": "https://api.github.com/users/tobegit3hub/orgs",
			"repos_url": "https://api.github.com/users/tobegit3hub/repos",
			"events_url": "https://api.github.com/users/tobegit3hub/events{/privacy}",
			"received_events_url": "https://api.github.com/users/tobegit3hub/received_events",
			"type": "User",
			"site_admin": false
		  }
		}
	*/

	hook := githubutil.GithubPushHook{}

	if err := json.Unmarshal(c.Ctx.Input.RequestBody, &hook); err != nil {
		c.Ctx.Output.SetStatus(400)
		c.Ctx.Output.Body([]byte("empty title"))
		fmt.Println(err)
	}

	projectId, _ := models.ReadOrCreateProject(hook.Repository.Owner.Login, hook.Repository.Name, hook.Repository.URL)

	models.AddGithubBuild(projectId, hook)

	return

}
109942
func (s *peerRESTServer) PutBucketNotificationHandler(w http.ResponseWriter, r *http.Request) {
	if !s.IsValid(w, r) {
		s.writeErrorResponse(w, errors.New("Invalid request"))
		return
	}

	vars := mux.Vars(r)
	bucketName := vars[peerRESTBucket]
	if bucketName == "" {
		s.writeErrorResponse(w, errors.New("Bucket name is missing"))
		return
	}

	var rulesMap event.RulesMap
	if r.ContentLength < 0 {
		s.writeErrorResponse(w, errInvalidArgument)
		return
	}

	err := gob.NewDecoder(r.Body).Decode(&rulesMap)
	if err != nil {
		s.writeErrorResponse(w, err)
		return
	}

	globalNotificationSys.AddRulesMap(bucketName, rulesMap)
	w.(http.Flusher).Flush()
}
297177
func (client *peerRESTClient) ListenBucketNotification(bucket string, eventNames []event.Name,
	pattern string, targetID event.TargetID, addr xnet.Host) error {
	args := listenBucketNotificationReq{
		EventNames: eventNames,
		Pattern:    pattern,
		TargetID:   targetID,
		Addr:       addr,
	}

	values := make(url.Values)
	values.Set(peerRESTBucket, bucket)

	var reader bytes.Buffer
	err := gob.NewEncoder(&reader).Encode(args)
	if err != nil {
		return err
	}

	respBody, err := client.call(peerRESTMethodBucketNotificationListen, values, &reader, -1)
	if err != nil {
		return err
	}

	defer http.DrainBody(respBody)
	return nil
}
709569
func (s *Server) ringSubscribersNotify() {
	for change := range s.subsChangeChan {
		s.ringSubs.RLock()
		ring := &pb.Ring{
			Ring:    *change.rb,
			Version: change.v,
		}
		for id, ch := range s.ringSubs.subs {
			go func(id string, ch chan *pb.Ring, ring *pb.Ring) {
				ch <- ring
			}(id, ch, ring)
		}
		s.ringSubs.RUnlock()
	}
}