func ExtractStoryChangelog()

in backend/plugins/tapd/tasks/story_changelog_extractor.go [39:137]


func ExtractStoryChangelog(taskCtx plugin.SubTaskContext) errors.Error {
	logger := taskCtx.GetLogger()
	rawDataSubTaskArgs, data := CreateRawDataSubTaskArgs(taskCtx, RAW_STORY_CHANGELOG_TABLE)
	extractor, err := api.NewApiExtractor(api.ApiExtractorArgs{
		RawDataSubTaskArgs: *rawDataSubTaskArgs,
		Extract: func(row *api.RawData) ([]interface{}, errors.Error) {
			var storyChangelogBody struct {
				WorkitemChange models.TapdStoryChangelog
			}
			results := make([]interface{}, 0, 2)

			err := errors.Convert(json.Unmarshal(row.Data, &storyChangelogBody))
			if err != nil {
				return nil, err
			}
			storyChangelog := storyChangelogBody.WorkitemChange

			storyChangelog.ConnectionId = data.Options.ConnectionId
			for _, fc := range storyChangelog.FieldChanges {
				if fc.IsStepChange {
					// ignore step change
					// https://github.com/apache/incubator-devlake/issues/8355#issuecomment-2756726463
					continue
				}
				var item models.TapdStoryChangelogItem
				var valueAfterMap interface{}
				var valueBeforeMap interface{}
				if fc.ValueAfterParsed == nil {
					if err = errors.Convert(json.Unmarshal(fc.ValueAfter, &valueAfterMap)); err != nil {
						return nil, err
					}
				} else {
					if err = errors.Convert(json.Unmarshal(fc.ValueAfterParsed, &valueAfterMap)); err != nil {
						return nil, err
					}
				}
				if fc.ValueBeforeParsed == nil {
					if err = errors.Convert(json.Unmarshal(fc.ValueBefore, &valueBeforeMap)); err != nil {
						return nil, err
					}
				} else {
					if err = errors.Convert(json.Unmarshal(fc.ValueBeforeParsed, &valueBeforeMap)); err != nil {
						return nil, err
					}
				}
				switch valueAfterMap.(type) {
				case map[string]interface{}:
					for k, v := range valueAfterMap.(map[string]interface{}) {
						item.ConnectionId = data.Options.ConnectionId
						item.ChangelogId = storyChangelog.Id
						item.Field = k
						item.ValueAfterParsed = cast.ToString(v)
						switch v := valueBeforeMap.(type) {
						case map[string]interface{}:
							value := v[k]
							item.ValueBeforeParsed = cast.ToString(value)
						default:
							item.ValueBeforeParsed = cast.ToString(valueBeforeMap)
						}
						err = convertUnicode(&item)
						if err != nil {
							logger.Error(err, "convert unicode: %s, err: %s", item, err)
						}
						results = append(results, &item)
					}
				default:
					item.ConnectionId = data.Options.ConnectionId
					item.ChangelogId = storyChangelog.Id
					item.Field = fc.Field
					item.ValueAfterParsed = cast.ToString(valueAfterMap)
					// as ValueAfterParsed is string, valueBeforeMap is always string
					item.ValueBeforeParsed = cast.ToString(valueBeforeMap)
				}
				err = convertUnicode(&item)
				if err != nil {
					logger.Error(err, "convert unicode: %s, err: %s", item, err)
				}
				if item.Field == "iteration_id" {
					// some users' tapd will not return iteration_id_from/iteration_id_to
					iterationFrom, iterationTo, err := parseIterationChangelog(taskCtx, item.ValueBeforeParsed, item.ValueAfterParsed)
					if err != nil {
						return nil, err
					}
					item.IterationIdFrom = iterationFrom
					item.IterationIdTo = iterationTo
				}
				results = append(results, &item)
			}
			results = append(results, &storyChangelog)
			return results, nil
		},
	})

	if err != nil {
		return err
	}

	return extractor.Execute()
}