jira: admittedly biased go styling

Michael Muré created

Change summary

bridge/jira/client.go | 175 ++++++++++++++++++++------------------------
bridge/jira/export.go |  79 ++++++++-----------
bridge/jira/import.go |  98 ++++++++++--------------
3 files changed, 154 insertions(+), 198 deletions(-)

Detailed changes

bridge/jira/client.go 🔗

@@ -315,21 +315,19 @@ type ClientTransport struct {
 }
 
 // RoundTrip overrides the default by adding the content-type header
-func (self *ClientTransport) RoundTrip(
-	req *http.Request) (*http.Response, error) {
+func (ct *ClientTransport) RoundTrip(req *http.Request) (*http.Response, error) {
 	req.Header.Add("Content-Type", "application/json")
-	if self.basicAuthString != "" {
+	if ct.basicAuthString != "" {
 		req.Header.Add("Authorization",
-			fmt.Sprintf("Basic %s", self.basicAuthString))
+			fmt.Sprintf("Basic %s", ct.basicAuthString))
 	}
 
-	return self.underlyingTransport.RoundTrip(req)
+	return ct.underlyingTransport.RoundTrip(req)
 }
 
-func (self *ClientTransport) SetCredentials(
-	username string, token string) {
+func (ct *ClientTransport) SetCredentials(username string, token string) {
 	credString := fmt.Sprintf("%s:%s", username, token)
-	self.basicAuthString = base64.StdEncoding.EncodeToString([]byte(credString))
+	ct.basicAuthString = base64.StdEncoding.EncodeToString([]byte(credString))
 }
 
 // Client Thin wrapper around the http.Client providing jira-specific methods
@@ -490,8 +488,7 @@ func (client *Client) RefreshSessionTokenRaw(credentialsJSON []byte) error {
 
 // Search Perform an issue a JQL search on the /search endpoint
 // https://docs.atlassian.com/software/jira/docs/api/REST/8.2.6/#api/2/search
-func (client *Client) Search(jql string, maxResults int, startAt int) (
-	*SearchResult, error) {
+func (client *Client) Search(jql string, maxResults int, startAt int) (*SearchResult, error) {
 	url := fmt.Sprintf("%s/rest/api/2/search", client.serverURL)
 
 	requestBody, err := json.Marshal(SearchRequest{
@@ -558,52 +555,51 @@ type SearchIterator struct {
 }
 
 // HasError returns true if the iterator is holding an error
-func (self *SearchIterator) HasError() bool {
-	if self.Err == errDone {
+func (si *SearchIterator) HasError() bool {
+	if si.Err == errDone {
 		return false
 	}
-	if self.Err == nil {
+	if si.Err == nil {
 		return false
 	}
 	return true
 }
 
 // HasNext returns true if there is another item available in the result set
-func (self *SearchIterator) HasNext() bool {
-	return self.Err == nil && self.itemIdx < len(self.searchResult.Issues)
+func (si *SearchIterator) HasNext() bool {
+	return si.Err == nil && si.itemIdx < len(si.searchResult.Issues)
 }
 
 // Next Return the next item in the result set and advance the iterator.
 // Advancing the iterator may require fetching a new page.
-func (self *SearchIterator) Next() *Issue {
-	if self.Err != nil {
+func (si *SearchIterator) Next() *Issue {
+	if si.Err != nil {
 		return nil
 	}
 
-	issue := self.searchResult.Issues[self.itemIdx]
-	if self.itemIdx+1 < len(self.searchResult.Issues) {
+	issue := si.searchResult.Issues[si.itemIdx]
+	if si.itemIdx+1 < len(si.searchResult.Issues) {
 		// We still have an item left in the currently cached page
-		self.itemIdx++
+		si.itemIdx++
 	} else {
-		if self.searchResult.IsLastPage() {
-			self.Err = errDone
+		if si.searchResult.IsLastPage() {
+			si.Err = errDone
 		} else {
 			// There are still more pages to fetch, so fetch the next page and
 			// cache it
-			self.searchResult, self.Err = self.client.Search(
-				self.jql, self.pageSize, self.searchResult.NextStartAt())
+			si.searchResult, si.Err = si.client.Search(
+				si.jql, si.pageSize, si.searchResult.NextStartAt())
 			// NOTE(josh): we don't deal with the error now, we just cache it.
 			// HasNext() will return false and the caller can check the error
 			// afterward.
-			self.itemIdx = 0
+			si.itemIdx = 0
 		}
 	}
 	return &issue
 }
 
 // IterSearch return an iterator over paginated results for a JQL search
-func (client *Client) IterSearch(
-	jql string, pageSize int) *SearchIterator {
+func (client *Client) IterSearch(jql string, pageSize int) *SearchIterator {
 	result, err := client.Search(jql, pageSize, 0)
 
 	iter := &SearchIterator{
@@ -620,9 +616,9 @@ func (client *Client) IterSearch(
 
 // GetIssue fetches an issue object via the /issue/{IssueIdOrKey} endpoint
 // https://docs.atlassian.com/software/jira/docs/api/REST/8.2.6/#api/2/issue
-func (client *Client) GetIssue(
-	idOrKey string, fields []string, expand []string,
+func (client *Client) GetIssue(idOrKey string, fields []string, expand []string,
 	properties []string) (*Issue, error) {
+
 	url := fmt.Sprintf("%s/rest/api/2/issue/%s", client.serverURL, idOrKey)
 
 	request, err := http.NewRequest("GET", url, nil)
@@ -678,8 +674,7 @@ func (client *Client) GetIssue(
 // GetComments returns a page of comments via the issue/{IssueIdOrKey}/comment
 // endpoint
 // https://docs.atlassian.com/software/jira/docs/api/REST/8.2.6/#api/2/issue-getComment
-func (client *Client) GetComments(
-	idOrKey string, maxResults int, startAt int) (*CommentPage, error) {
+func (client *Client) GetComments(idOrKey string, maxResults int, startAt int) (*CommentPage, error) {
 	url := fmt.Sprintf(
 		"%s/rest/api/2/issue/%s/comment", client.serverURL, idOrKey)
 
@@ -742,52 +737,51 @@ type CommentIterator struct {
 }
 
 // HasError returns true if the iterator is holding an error
-func (self *CommentIterator) HasError() bool {
-	if self.Err == errDone {
+func (ci *CommentIterator) HasError() bool {
+	if ci.Err == errDone {
 		return false
 	}
-	if self.Err == nil {
+	if ci.Err == nil {
 		return false
 	}
 	return true
 }
 
 // HasNext returns true if there is another item available in the result set
-func (self *CommentIterator) HasNext() bool {
-	return self.Err == nil && self.itemIdx < len(self.message.Comments)
+func (ci *CommentIterator) HasNext() bool {
+	return ci.Err == nil && ci.itemIdx < len(ci.message.Comments)
 }
 
 // Next Return the next item in the result set and advance the iterator.
 // Advancing the iterator may require fetching a new page.
-func (self *CommentIterator) Next() *Comment {
-	if self.Err != nil {
+func (ci *CommentIterator) Next() *Comment {
+	if ci.Err != nil {
 		return nil
 	}
 
-	comment := self.message.Comments[self.itemIdx]
-	if self.itemIdx+1 < len(self.message.Comments) {
+	comment := ci.message.Comments[ci.itemIdx]
+	if ci.itemIdx+1 < len(ci.message.Comments) {
 		// We still have an item left in the currently cached page
-		self.itemIdx++
+		ci.itemIdx++
 	} else {
-		if self.message.IsLastPage() {
-			self.Err = errDone
+		if ci.message.IsLastPage() {
+			ci.Err = errDone
 		} else {
 			// There are still more pages to fetch, so fetch the next page and
 			// cache it
-			self.message, self.Err = self.client.GetComments(
-				self.idOrKey, self.pageSize, self.message.NextStartAt())
+			ci.message, ci.Err = ci.client.GetComments(
+				ci.idOrKey, ci.pageSize, ci.message.NextStartAt())
 			// NOTE(josh): we don't deal with the error now, we just cache it.
 			// HasNext() will return false and the caller can check the error
 			// afterward.
-			self.itemIdx = 0
+			ci.itemIdx = 0
 		}
 	}
 	return &comment
 }
 
 // IterComments returns an iterator over paginated comments within an issue
-func (client *Client) IterComments(
-	idOrKey string, pageSize int) *CommentIterator {
+func (client *Client) IterComments(idOrKey string, pageSize int) *CommentIterator {
 	message, err := client.GetComments(idOrKey, pageSize, 0)
 
 	iter := &CommentIterator{
@@ -807,8 +801,7 @@ func (client *Client) IterComments(
 // /issue/{IssueIdOrKey} with (fields=*none&expand=changelog)
 // (for JIRA server)
 // https://docs.atlassian.com/software/jira/docs/api/REST/8.2.6/#api/2/issue
-func (client *Client) GetChangeLog(
-	idOrKey string, maxResults int, startAt int) (*ChangeLogPage, error) {
+func (client *Client) GetChangeLog(idOrKey string, maxResults int, startAt int) (*ChangeLogPage, error) {
 	url := fmt.Sprintf(
 		"%s/rest/api/2/issue/%s/changelog", client.serverURL, idOrKey)
 
@@ -892,52 +885,51 @@ type ChangeLogIterator struct {
 }
 
 // HasError returns true if the iterator is holding an error
-func (self *ChangeLogIterator) HasError() bool {
-	if self.Err == errDone {
+func (cli *ChangeLogIterator) HasError() bool {
+	if cli.Err == errDone {
 		return false
 	}
-	if self.Err == nil {
+	if cli.Err == nil {
 		return false
 	}
 	return true
 }
 
 // HasNext returns true if there is another item available in the result set
-func (self *ChangeLogIterator) HasNext() bool {
-	return self.Err == nil && self.itemIdx < len(self.message.Entries)
+func (cli *ChangeLogIterator) HasNext() bool {
+	return cli.Err == nil && cli.itemIdx < len(cli.message.Entries)
 }
 
 // Next Return the next item in the result set and advance the iterator.
 // Advancing the iterator may require fetching a new page.
-func (self *ChangeLogIterator) Next() *ChangeLogEntry {
-	if self.Err != nil {
+func (cli *ChangeLogIterator) Next() *ChangeLogEntry {
+	if cli.Err != nil {
 		return nil
 	}
 
-	item := self.message.Entries[self.itemIdx]
-	if self.itemIdx+1 < len(self.message.Entries) {
+	item := cli.message.Entries[cli.itemIdx]
+	if cli.itemIdx+1 < len(cli.message.Entries) {
 		// We still have an item left in the currently cached page
-		self.itemIdx++
+		cli.itemIdx++
 	} else {
-		if self.message.IsLastPage() {
-			self.Err = errDone
+		if cli.message.IsLastPage() {
+			cli.Err = errDone
 		} else {
 			// There are still more pages to fetch, so fetch the next page and
 			// cache it
-			self.message, self.Err = self.client.GetChangeLog(
-				self.idOrKey, self.pageSize, self.message.NextStartAt())
+			cli.message, cli.Err = cli.client.GetChangeLog(
+				cli.idOrKey, cli.pageSize, cli.message.NextStartAt())
 			// NOTE(josh): we don't deal with the error now, we just cache it.
 			// HasNext() will return false and the caller can check the error
 			// afterward.
-			self.itemIdx = 0
+			cli.itemIdx = 0
 		}
 	}
 	return &item
 }
 
 // IterChangeLog returns an iterator over entries in the changelog for an issue
-func (client *Client) IterChangeLog(
-	idOrKey string, pageSize int) *ChangeLogIterator {
+func (client *Client) IterChangeLog(idOrKey string, pageSize int) *ChangeLogIterator {
 	message, err := client.GetChangeLog(idOrKey, pageSize, 0)
 
 	iter := &ChangeLogIterator{
@@ -994,9 +986,8 @@ func (client *Client) GetProject(projectIDOrKey string) (*Project, error) {
 }
 
 // CreateIssue creates a new JIRA issue and returns it
-func (client *Client) CreateIssue(
-	projectIDOrKey, title, body string, extra map[string]interface{}) (
-	*IssueCreateResult, error) {
+func (client *Client) CreateIssue(projectIDOrKey, title, body string,
+	extra map[string]interface{}) (*IssueCreateResult, error) {
 
 	url := fmt.Sprintf("%s/rest/api/2/issue", client.serverURL)
 
@@ -1063,8 +1054,7 @@ func (client *Client) CreateIssue(
 }
 
 // UpdateIssueTitle changes the "summary" field of a JIRA issue
-func (client *Client) UpdateIssueTitle(
-	issueKeyOrID, title string) (time.Time, error) {
+func (client *Client) UpdateIssueTitle(issueKeyOrID, title string) (time.Time, error) {
 
 	url := fmt.Sprintf(
 		"%s/rest/api/2/issue/%s", client.serverURL, issueKeyOrID)
@@ -1078,9 +1068,9 @@ func (client *Client) UpdateIssueTitle(
 	}
 
 	var buffer bytes.Buffer
-	fmt.Fprintf(&buffer, `{"update":{"summary":[`)
-	fmt.Fprintf(&buffer, `{"set":%s}`, data)
-	fmt.Fprintf(&buffer, `]}}`)
+	_, _ = fmt.Fprintf(&buffer, `{"update":{"summary":[`)
+	_, _ = fmt.Fprintf(&buffer, `{"set":%s}`, data)
+	_, _ = fmt.Fprintf(&buffer, `]}}`)
 
 	data = buffer.Bytes()
 	request, err := http.NewRequest("PUT", url, bytes.NewBuffer(data))
@@ -1119,8 +1109,7 @@ func (client *Client) UpdateIssueTitle(
 }
 
 // UpdateIssueBody changes the "description" field of a JIRA issue
-func (client *Client) UpdateIssueBody(
-	issueKeyOrID, body string) (time.Time, error) {
+func (client *Client) UpdateIssueBody(issueKeyOrID, body string) (time.Time, error) {
 
 	url := fmt.Sprintf(
 		"%s/rest/api/2/issue/%s", client.serverURL, issueKeyOrID)
@@ -1133,9 +1122,9 @@ func (client *Client) UpdateIssueBody(
 	}
 
 	var buffer bytes.Buffer
-	fmt.Fprintf(&buffer, `{"update":{"description":[`)
-	fmt.Fprintf(&buffer, `{"set":%s}`, data)
-	fmt.Fprintf(&buffer, `]}}`)
+	_, _ = fmt.Fprintf(&buffer, `{"update":{"description":[`)
+	_, _ = fmt.Fprintf(&buffer, `{"set":%s}`, data)
+	_, _ = fmt.Fprintf(&buffer, `]}}`)
 
 	data = buffer.Bytes()
 	request, err := http.NewRequest("PUT", url, bytes.NewBuffer(data))
@@ -1279,8 +1268,7 @@ func (client *Client) UpdateComment(issueKeyOrID, commentID, body string) (
 }
 
 // UpdateLabels changes labels for an issue
-func (client *Client) UpdateLabels(
-	issueKeyOrID string, added, removed []bug.Label) (time.Time, error) {
+func (client *Client) UpdateLabels(issueKeyOrID string, added, removed []bug.Label) (time.Time, error) {
 	url := fmt.Sprintf(
 		"%s/rest/api/2/issue/%s/", client.serverURL, issueKeyOrID)
 	var responseTime time.Time
@@ -1288,23 +1276,23 @@ func (client *Client) UpdateLabels(
 	// NOTE(josh): Since updates are a list of heterogeneous objects let's just
 	// manually build the JSON text
 	var buffer bytes.Buffer
-	fmt.Fprintf(&buffer, `{"update":{"labels":[`)
+	_, _ = fmt.Fprintf(&buffer, `{"update":{"labels":[`)
 	first := true
 	for _, label := range added {
 		if !first {
-			fmt.Fprintf(&buffer, ",")
+			_, _ = fmt.Fprintf(&buffer, ",")
 		}
-		fmt.Fprintf(&buffer, `{"add":"%s"}`, label)
+		_, _ = fmt.Fprintf(&buffer, `{"add":"%s"}`, label)
 		first = false
 	}
 	for _, label := range removed {
 		if !first {
-			fmt.Fprintf(&buffer, ",")
+			_, _ = fmt.Fprintf(&buffer, ",")
 		}
-		fmt.Fprintf(&buffer, `{"remove":"%s"}`, label)
+		_, _ = fmt.Fprintf(&buffer, `{"remove":"%s"}`, label)
 		first = false
 	}
-	fmt.Fprintf(&buffer, "]}}")
+	_, _ = fmt.Fprintf(&buffer, "]}}")
 
 	data := buffer.Bytes()
 	request, err := http.NewRequest("PUT", url, bytes.NewBuffer(data))
@@ -1349,8 +1337,7 @@ func (client *Client) UpdateLabels(
 }
 
 // GetTransitions returns a list of available transitions for an issue
-func (client *Client) GetTransitions(issueKeyOrID string) (
-	*TransitionList, error) {
+func (client *Client) GetTransitions(issueKeyOrID string) (*TransitionList, error) {
 
 	url := fmt.Sprintf(
 		"%s/rest/api/2/issue/%s/transitions", client.serverURL, issueKeyOrID)
@@ -1393,8 +1380,7 @@ func (client *Client) GetTransitions(issueKeyOrID string) (
 	return &message, nil
 }
 
-func getTransitionTo(
-	tlist *TransitionList, desiredStateNameOrID string) *Transition {
+func getTransitionTo(tlist *TransitionList, desiredStateNameOrID string) *Transition {
 	for _, transition := range tlist.Transitions {
 		if transition.To.ID == desiredStateNameOrID {
 			return &transition
@@ -1406,8 +1392,7 @@ func getTransitionTo(
 }
 
 // DoTransition changes the "status" of an issue
-func (client *Client) DoTransition(
-	issueKeyOrID string, transitionID string) (time.Time, error) {
+func (client *Client) DoTransition(issueKeyOrID string, transitionID string) (time.Time, error) {
 	url := fmt.Sprintf(
 		"%s/rest/api/2/issue/%s/transitions", client.serverURL, issueKeyOrID)
 	var responseTime time.Time
@@ -1417,7 +1402,7 @@ func (client *Client) DoTransition(
 	// *compute* the necessary transitions and prompt for missing metatdata...
 	// but that is complex
 	var buffer bytes.Buffer
-	fmt.Fprintf(&buffer,
+	_, _ = fmt.Fprintf(&buffer,
 		`{"transition":{"id":"%s"}, "resolution": {"name": "Done"}}`,
 		transitionID)
 	request, err := http.NewRequest("POST", url, bytes.NewBuffer(buffer.Bytes()))

bridge/jira/export.go 🔗

@@ -43,47 +43,42 @@ type jiraExporter struct {
 }
 
 // Init .
-func (self *jiraExporter) Init(repo *cache.RepoCache,
-	conf core.Configuration) error {
-	self.conf = conf
-	self.identityClient = make(map[entity.Id]*Client)
-	self.cachedOperationIDs = make(map[entity.Id]string)
-	self.cachedLabels = make(map[string]string)
+func (je *jiraExporter) Init(repo *cache.RepoCache, conf core.Configuration) error {
+	je.conf = conf
+	je.identityClient = make(map[entity.Id]*Client)
+	je.cachedOperationIDs = make(map[entity.Id]string)
+	je.cachedLabels = make(map[string]string)
 	return nil
 }
 
 // getIdentityClient return an API client configured with the credentials
 // of the given identity. If no client were found it will initialize it from
 // the known credentials map and cache it for next use
-func (self *jiraExporter) getIdentityClient(
-	ctx context.Context, id entity.Id) (*Client, error) {
-	client, ok := self.identityClient[id]
+func (je *jiraExporter) getIdentityClient(ctx context.Context, id entity.Id) (*Client, error) {
+	client, ok := je.identityClient[id]
 	if ok {
 		return client, nil
 	}
 
-	client = NewClient(self.conf[keyServer], ctx)
+	client = NewClient(je.conf[keyServer], ctx)
 
 	// NOTE: as a future enhancement, the bridge would ideally be able to generate
 	// a separate session token for each user that we have stored credentials
 	// for. However we currently only support a single user.
-	if id != self.userIdentity {
+	if id != je.userIdentity {
 		return nil, ErrMissingCredentials
 	}
-	err := client.Login(self.conf)
+	err := client.Login(je.conf)
 	if err != nil {
 		return nil, err
 	}
 
-	self.identityClient[id] = client
+	je.identityClient[id] = client
 	return client, nil
 }
 
 // ExportAll export all event made by the current user to Jira
-func (self *jiraExporter) ExportAll(
-	ctx context.Context, repo *cache.RepoCache, since time.Time) (
-	<-chan core.ExportResult, error) {
-
+func (je *jiraExporter) ExportAll(ctx context.Context, repo *cache.RepoCache, since time.Time) (<-chan core.ExportResult, error) {
 	out := make(chan core.ExportResult)
 
 	user, err := repo.GetUserIdentity()
@@ -93,13 +88,13 @@ func (self *jiraExporter) ExportAll(
 
 	// NOTE: this is currently only need to mock the credentials database in
 	// getIdentityClient.
-	self.userIdentity = user.Id()
-	client, err := self.getIdentityClient(ctx, user.Id())
+	je.userIdentity = user.Id()
+	client, err := je.getIdentityClient(ctx, user.Id())
 	if err != nil {
 		return nil, err
 	}
 
-	self.project, err = client.GetProject(self.conf[keyProject])
+	je.project, err = client.GetProject(je.conf[keyProject])
 	if err != nil {
 		return nil, err
 	}
@@ -108,7 +103,7 @@ func (self *jiraExporter) ExportAll(
 		defer close(out)
 
 		var allIdentitiesIds []entity.Id
-		for id := range self.identityClient {
+		for id := range je.identityClient {
 			allIdentitiesIds = append(allIdentitiesIds, id)
 		}
 
@@ -139,7 +134,7 @@ func (self *jiraExporter) ExportAll(
 
 				if snapshot.HasAnyActor(allIdentitiesIds...) {
 					// try to export the bug and it associated events
-					err := self.exportBug(ctx, b, since, out)
+					err := je.exportBug(ctx, b, since, out)
 					if err != nil {
 						out <- core.NewExportError(errors.Wrap(err, "can't export bug"), id)
 						return
@@ -155,9 +150,7 @@ func (self *jiraExporter) ExportAll(
 }
 
 // exportBug publish bugs and related events
-func (self *jiraExporter) exportBug(
-	ctx context.Context, b *cache.BugCache, since time.Time,
-	out chan<- core.ExportResult) error {
+func (je *jiraExporter) exportBug(ctx context.Context, b *cache.BugCache, since time.Time, out chan<- core.ExportResult) error {
 	snapshot := b.Snapshot()
 
 	var bugJiraID string
@@ -182,7 +175,7 @@ func (self *jiraExporter) exportBug(
 	// skip bug if it is a jira bug but is associated with another project
 	// (one bridge per JIRA project)
 	project, ok := snapshot.GetCreateMetadata(keyJiraProject)
-	if ok && !stringInSlice(project, []string{self.project.ID, self.project.Key}) {
+	if ok && !stringInSlice(project, []string{je.project.ID, je.project.Key}) {
 		out <- core.NewExportNothing(
 			b.Id(), fmt.Sprintf("issue tagged with project: %s", project))
 		return nil
@@ -195,7 +188,7 @@ func (self *jiraExporter) exportBug(
 		bugJiraID = jiraID
 	} else {
 		// check that we have credentials for operation author
-		client, err := self.getIdentityClient(ctx, author.Id())
+		client, err := je.getIdentityClient(ctx, author.Id())
 		if err != nil {
 			// if bug is not yet exported and we do not have the author's credentials
 			// then there is nothing we can do, so just skip this bug
@@ -208,7 +201,7 @@ func (self *jiraExporter) exportBug(
 		// Load any custom fields required to create an issue from the git
 		// config file.
 		fields := make(map[string]interface{})
-		defaultFields, hasConf := self.conf[keyCreateDefaults]
+		defaultFields, hasConf := je.conf[keyCreateDefaults]
 		if hasConf {
 			err = json.Unmarshal([]byte(defaultFields), &fields)
 			if err != nil {
@@ -222,7 +215,7 @@ func (self *jiraExporter) exportBug(
 				"id": "10001",
 			}
 		}
-		bugIDField, hasConf := self.conf[keyCreateGitBug]
+		bugIDField, hasConf := je.conf[keyCreateGitBug]
 		if hasConf {
 			// If the git configuration also indicates it, we can assign the git-bug
 			// id to a custom field to assist in integrations
@@ -231,7 +224,7 @@ func (self *jiraExporter) exportBug(
 
 		// create bug
 		result, err := client.CreateIssue(
-			self.project.ID, createOp.Title, createOp.Message, fields)
+			je.project.ID, createOp.Title, createOp.Message, fields)
 		if err != nil {
 			err := errors.Wrap(err, "exporting jira issue")
 			out <- core.NewExportError(err, b.Id())
@@ -242,7 +235,7 @@ func (self *jiraExporter) exportBug(
 		out <- core.NewExportBug(b.Id())
 		// mark bug creation operation as exported
 		err = markOperationAsExported(
-			b, createOp.Id(), id, self.project.Key, time.Time{})
+			b, createOp.Id(), id, je.project.Key, time.Time{})
 		if err != nil {
 			err := errors.Wrap(err, "marking operation as exported")
 			out <- core.NewExportError(err, b.Id())
@@ -262,10 +255,10 @@ func (self *jiraExporter) exportBug(
 	}
 
 	// cache operation jira id
-	self.cachedOperationIDs[createOp.Id()] = bugJiraID
+	je.cachedOperationIDs[createOp.Id()] = bugJiraID
 
 	// lookup the mapping from git-bug "status" to JIRA "status" id
-	statusMap, err := getStatusMap(self.conf)
+	statusMap, err := getStatusMap(je.conf)
 	if err != nil {
 		return err
 	}
@@ -280,12 +273,12 @@ func (self *jiraExporter) exportBug(
 		// cache the ID of already exported or imported issues and events from
 		// Jira
 		if id, ok := op.GetMetadata(keyJiraID); ok {
-			self.cachedOperationIDs[op.Id()] = id
+			je.cachedOperationIDs[op.Id()] = id
 			continue
 		}
 
 		opAuthor := op.GetAuthor()
-		client, err := self.getIdentityClient(ctx, opAuthor.Id())
+		client, err := je.getIdentityClient(ctx, opAuthor.Id())
 		if err != nil {
 			out <- core.NewExportError(
 				fmt.Errorf("missing operation author credentials for user %.8s",
@@ -307,7 +300,7 @@ func (self *jiraExporter) exportBug(
 			out <- core.NewExportComment(op.Id())
 
 			// cache comment id
-			self.cachedOperationIDs[op.Id()] = id
+			je.cachedOperationIDs[op.Id()] = id
 
 		case *bug.EditCommentOperation:
 			if opr.Target == createOp.Id() {
@@ -325,7 +318,7 @@ func (self *jiraExporter) exportBug(
 				// Otherwise it's an edit to an actual comment. A comment cannot be
 				// edited before it was created, so it must be the case that we have
 				// already observed and cached the AddCommentOperation.
-				commentID, ok := self.cachedOperationIDs[opr.Target]
+				commentID, ok := je.cachedOperationIDs[opr.Target]
 				if !ok {
 					// Since an edit has to come after the creation, we expect we would
 					// have cached the creation id.
@@ -392,7 +385,7 @@ func (self *jiraExporter) exportBug(
 
 		// mark operation as exported
 		err = markOperationAsExported(
-			b, op.Id(), id, self.project.Key, exportTime)
+			b, op.Id(), id, je.project.Key, exportTime)
 		if err != nil {
 			err := errors.Wrap(err, "marking operation as exported")
 			out <- core.NewExportError(err, b.Id())
@@ -412,10 +405,7 @@ func (self *jiraExporter) exportBug(
 	return nil
 }
 
-func markOperationAsExported(
-	b *cache.BugCache, target entity.Id, jiraID, jiraProject string,
-	exportTime time.Time) error {
-
+func markOperationAsExported(b *cache.BugCache, target entity.Id, jiraID, jiraProject string, exportTime time.Time) error {
 	newMetadata := map[string]string{
 		keyJiraID:      jiraID,
 		keyJiraProject: jiraProject,
@@ -431,10 +421,7 @@ func markOperationAsExported(
 // UpdateIssueStatus attempts to change the "status" field by finding a
 // transition which achieves the desired state and then performing that
 // transition
-func UpdateIssueStatus(
-	client *Client, issueKeyOrID string, desiredStateNameOrID string) (
-	time.Time, error) {
-
+func UpdateIssueStatus(client *Client, issueKeyOrID string, desiredStateNameOrID string) (time.Time, error) {
 	var responseTime time.Time
 
 	tlist, err := client.GetTransitions(issueKeyOrID)

bridge/jira/import.go 🔗

@@ -35,31 +35,27 @@ type jiraImporter struct {
 }
 
 // Init .
-func (gi *jiraImporter) Init(repo *cache.RepoCache,
-	conf core.Configuration) error {
-	gi.conf = conf
+func (ji *jiraImporter) Init(repo *cache.RepoCache, conf core.Configuration) error {
+	ji.conf = conf
 	return nil
 }
 
 // ImportAll iterate over all the configured repository issues and ensure the
 // creation of the missing issues / timeline items / edits / label events ...
-func (self *jiraImporter) ImportAll(
-	ctx context.Context, repo *cache.RepoCache, since time.Time) (
-	<-chan core.ImportResult, error) {
-
+func (ji *jiraImporter) ImportAll(ctx context.Context, repo *cache.RepoCache, since time.Time) (<-chan core.ImportResult, error) {
 	sinceStr := since.Format("2006-01-02 15:04")
-	serverURL := self.conf[keyServer]
-	project := self.conf[keyProject]
+	serverURL := ji.conf[keyServer]
+	project := ji.conf[keyProject]
 	// TODO(josh)[da52062]: Validate token and if it is expired then prompt for
 	// credentials and generate a new one
 	out := make(chan core.ImportResult)
-	self.out = out
+	ji.out = out
 
 	go func() {
-		defer close(self.out)
+		defer close(ji.out)
 
 		client := NewClient(serverURL, ctx)
-		err := client.Login(self.conf)
+		err := client.Login(ji.conf)
 		if err != nil {
 			out <- core.NewImportError(err, "")
 			return
@@ -79,7 +75,7 @@ func (self *jiraImporter) ImportAll(
 		for searchIter =
 			client.IterSearch(jql, defaultPageSize); searchIter.HasNext(); {
 			issue := searchIter.Next()
-			bug, err := self.ensureIssue(repo, *issue)
+			b, err := ji.ensureIssue(repo, *issue)
 			if err != nil {
 				err := fmt.Errorf("issue creation: %v", err)
 				out <- core.NewImportError(err, "")
@@ -90,7 +86,7 @@ func (self *jiraImporter) ImportAll(
 			for commentIter =
 				client.IterComments(issue.ID, defaultPageSize); commentIter.HasNext(); {
 				comment := commentIter.Next()
-				err := self.ensureComment(repo, bug, *comment)
+				err := ji.ensureComment(repo, b, *comment)
 				if err != nil {
 					out <- core.NewImportError(err, "")
 				}
@@ -99,7 +95,7 @@ func (self *jiraImporter) ImportAll(
 				out <- core.NewImportError(commentIter.Err, "")
 			}
 
-			snapshot := bug.Snapshot()
+			snapshot := b.Snapshot()
 			opIdx := 0
 
 			var changelogIter *ChangeLogIterator
@@ -127,10 +123,9 @@ func (self *jiraImporter) ImportAll(
 					}
 				}
 				if opIdx < len(snapshot.Operations) {
-					err = self.ensureChange(
-						repo, bug, *changelogEntry, snapshot.Operations[opIdx])
+					err = ji.ensureChange(repo, b, *changelogEntry, snapshot.Operations[opIdx])
 				} else {
-					err = self.ensureChange(repo, bug, *changelogEntry, nil)
+					err = ji.ensureChange(repo, b, *changelogEntry, nil)
 				}
 				if err != nil {
 					out <- core.NewImportError(err, "")
@@ -141,9 +136,9 @@ func (self *jiraImporter) ImportAll(
 				out <- core.NewImportError(changelogIter.Err, "")
 			}
 
-			if !bug.NeedCommit() {
-				out <- core.NewImportNothing(bug.Id(), "no imported operation")
-			} else if err := bug.Commit(); err != nil {
+			if !b.NeedCommit() {
+				out <- core.NewImportNothing(b.Id(), "no imported operation")
+			} else if err := b.Commit(); err != nil {
 				err = fmt.Errorf("bug commit: %v", err)
 				out <- core.NewImportError(err, "")
 				return
@@ -158,9 +153,7 @@ func (self *jiraImporter) ImportAll(
 }
 
 // Create a bug.Person from a JIRA user
-func (self *jiraImporter) ensurePerson(
-	repo *cache.RepoCache, user User) (*cache.IdentityCache, error) {
-
+func (ji *jiraImporter) ensurePerson(repo *cache.RepoCache, user User) (*cache.IdentityCache, error) {
 	// Look first in the cache
 	i, err := repo.ResolveIdentityImmutableMetadata(
 		keyJiraUser, string(user.Key))
@@ -184,14 +177,13 @@ func (self *jiraImporter) ensurePerson(
 		return nil, err
 	}
 
-	self.out <- core.NewImportIdentity(i.Id())
+	ji.out <- core.NewImportIdentity(i.Id())
 	return i, nil
 }
 
 // Create a bug.Bug based from a JIRA issue
-func (self *jiraImporter) ensureIssue(
-	repo *cache.RepoCache, issue Issue) (*cache.BugCache, error) {
-	author, err := self.ensurePerson(repo, issue.Fields.Creator)
+func (ji *jiraImporter) ensureIssue(repo *cache.RepoCache, issue Issue) (*cache.BugCache, error) {
+	author, err := ji.ensurePerson(repo, issue.Fields.Creator)
 	if err != nil {
 		return nil, err
 	}
@@ -220,13 +212,13 @@ func (self *jiraImporter) ensureIssue(
 				core.MetaKeyOrigin: target,
 				keyJiraID:          issue.ID,
 				keyJiraKey:         issue.Key,
-				keyJiraProject:     self.conf[keyProject],
+				keyJiraProject:     ji.conf[keyProject],
 			})
 		if err != nil {
 			return nil, err
 		}
 
-		self.out <- core.NewImportBug(b.Id())
+		ji.out <- core.NewImportBug(b.Id())
 	}
 
 	return b, nil
@@ -238,10 +230,9 @@ func getTimeDerivedID(jiraID string, timestamp MyTime) string {
 }
 
 // Create a bug.Comment from a JIRA comment
-func (self *jiraImporter) ensureComment(repo *cache.RepoCache,
-	b *cache.BugCache, item Comment) error {
+func (ji *jiraImporter) ensureComment(repo *cache.RepoCache, b *cache.BugCache, item Comment) error {
 	// ensure person
-	author, err := self.ensurePerson(repo, item.Author)
+	author, err := ji.ensurePerson(repo, item.Author)
 	if err != nil {
 		return err
 	}
@@ -279,7 +270,7 @@ func (self *jiraImporter) ensureComment(repo *cache.RepoCache,
 			return err
 		}
 
-		self.out <- core.NewImportComment(op.Id())
+		ji.out <- core.NewImportComment(op.Id())
 		targetOpID = op.Id()
 	}
 
@@ -293,8 +284,7 @@ func (self *jiraImporter) ensureComment(repo *cache.RepoCache,
 	// timestamp. Note that this must be consistent with the exporter during
 	// export of an EditCommentOperation
 	derivedID := getTimeDerivedID(item.ID, item.Updated)
-	_, err = b.ResolveOperationWithMetadata(
-		keyJiraID, derivedID)
+	_, err = b.ResolveOperationWithMetadata(keyJiraID, derivedID)
 	if err == nil {
 		// Already imported this edition
 		return nil
@@ -305,7 +295,7 @@ func (self *jiraImporter) ensureComment(repo *cache.RepoCache,
 	}
 
 	// ensure editor identity
-	editor, err := self.ensurePerson(repo, item.UpdateAuthor)
+	editor, err := ji.ensurePerson(repo, item.UpdateAuthor)
 	if err != nil {
 		return err
 	}
@@ -329,7 +319,7 @@ func (self *jiraImporter) ensureComment(repo *cache.RepoCache,
 		return err
 	}
 
-	self.out <- core.NewImportCommentEdition(op.Id())
+	ji.out <- core.NewImportCommentEdition(op.Id())
 
 	return nil
 }
@@ -363,9 +353,7 @@ func labelSetsMatch(jiraSet []string, gitbugSet []bug.Label) bool {
 
 // Create a bug.Operation (or a series of operations) from a JIRA changelog
 // entry
-func (self *jiraImporter) ensureChange(
-	repo *cache.RepoCache, b *cache.BugCache, entry ChangeLogEntry,
-	potentialOp bug.Operation) error {
+func (ji *jiraImporter) ensureChange(repo *cache.RepoCache, b *cache.BugCache, entry ChangeLogEntry, potentialOp bug.Operation) error {
 
 	// If we have an operation which is already mapped to the entire changelog
 	// entry then that means this changelog entry was induced by an export
@@ -383,7 +371,7 @@ func (self *jiraImporter) ensureChange(
 	// I don't thing git-bug has a single operation to modify an arbitrary
 	// number of fields in one go, so we break up the single JIRA changelog
 	// entry into individual field updates.
-	author, err := self.ensurePerson(repo, entry.Author)
+	author, err := ji.ensurePerson(repo, entry.Author)
 	if err != nil {
 		return err
 	}
@@ -392,7 +380,7 @@ func (self *jiraImporter) ensureChange(
 		return fmt.Errorf("Received changelog entry with no item! (%s)", entry.ID)
 	}
 
-	statusMap, err := getStatusMapReverse(self.conf)
+	statusMap, err := getStatusMapReverse(ji.conf)
 	if err != nil {
 		return err
 	}
@@ -407,13 +395,10 @@ func (self *jiraImporter) ensureChange(
 		case "labels":
 			fromLabels := removeEmpty(strings.Split(item.FromString, " "))
 			toLabels := removeEmpty(strings.Split(item.ToString, " "))
-			removedLabels, addedLabels, _ := setSymmetricDifference(
-				fromLabels, toLabels)
+			removedLabels, addedLabels, _ := setSymmetricDifference(fromLabels, toLabels)
 
 			opr, isRightType := potentialOp.(*bug.LabelChangeOperation)
-			if isRightType &&
-				labelSetsMatch(addedLabels, opr.Added) &&
-				labelSetsMatch(removedLabels, opr.Removed) {
+			if isRightType && labelSetsMatch(addedLabels, opr.Added) && labelSetsMatch(removedLabels, opr.Removed) {
 				_, err := b.SetMetadata(opr.Id(), map[string]string{
 					keyJiraOperationID: entry.ID,
 				})
@@ -484,8 +469,7 @@ func (self *jiraImporter) ensureChange(
 		case "labels":
 			fromLabels := removeEmpty(strings.Split(item.FromString, " "))
 			toLabels := removeEmpty(strings.Split(item.ToString, " "))
-			removedLabels, addedLabels, _ := setSymmetricDifference(
-				fromLabels, toLabels)
+			removedLabels, addedLabels, _ := setSymmetricDifference(fromLabels, toLabels)
 
 			op, err := b.ForceChangeLabelsRaw(
 				author,
@@ -501,7 +485,7 @@ func (self *jiraImporter) ensureChange(
 				return err
 			}
 
-			self.out <- core.NewImportLabelChange(op.Id())
+			ji.out <- core.NewImportLabelChange(op.Id())
 
 		case "status":
 			statusStr, hasMap := statusMap[item.To]
@@ -519,7 +503,7 @@ func (self *jiraImporter) ensureChange(
 					if err != nil {
 						return err
 					}
-					self.out <- core.NewImportStatusChange(op.Id())
+					ji.out <- core.NewImportStatusChange(op.Id())
 
 				case bug.ClosedStatus.String():
 					op, err := b.CloseRaw(
@@ -533,10 +517,10 @@ func (self *jiraImporter) ensureChange(
 					if err != nil {
 						return err
 					}
-					self.out <- core.NewImportStatusChange(op.Id())
+					ji.out <- core.NewImportStatusChange(op.Id())
 				}
 			} else {
-				self.out <- core.NewImportError(
+				ji.out <- core.NewImportError(
 					fmt.Errorf(
 						"No git-bug status mapped for jira status %s (%s)",
 						item.ToString, item.To), "")
@@ -558,7 +542,7 @@ func (self *jiraImporter) ensureChange(
 				return err
 			}
 
-			self.out <- core.NewImportTitleEdition(op.Id())
+			ji.out <- core.NewImportTitleEdition(op.Id())
 
 		case "description":
 			// NOTE(josh): JIRA calls it "description", which sounds more like the
@@ -576,10 +560,10 @@ func (self *jiraImporter) ensureChange(
 				return err
 			}
 
-			self.out <- core.NewImportCommentEdition(op.Id())
+			ji.out <- core.NewImportCommentEdition(op.Id())
 
 		default:
-			self.out <- core.NewImportWarning(
+			ji.out <- core.NewImportWarning(
 				fmt.Errorf(
 					"Unhandled changelog event %s", item.Field), "")
 		}