Skip to content
This repository has been archived by the owner on Feb 21, 2024. It is now read-only.

Commit

Permalink
Tags can be changed
Browse files Browse the repository at this point in the history
  • Loading branch information
falconandy committed Jul 14, 2018
1 parent 93cc017 commit c4cefd5
Show file tree
Hide file tree
Showing 9 changed files with 172 additions and 4 deletions.
12 changes: 12 additions & 0 deletions backlog/backlog_item.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,18 @@ func (item *BacklogItem) ClearTimeline(tag string) {
item.markdown.RemoveMetadata(fmt.Sprintf("Timeline %s", tag))
}

func (item *BacklogItem) ChangeTimelineTag(oldTag, newTag string) {
oldKey := fmt.Sprintf("Timeline %s", oldTag)
newKey := fmt.Sprintf("Timeline %s", newTag)

if item.markdown.MetadataValue(newKey) != "" {
item.ClearTimeline(oldTag)
} else {
item.markdown.RemoveMetadata(newKey)
item.markdown.ReplaceMetadataKey(oldKey, newKey)
}
}

func (item *BacklogItem) SetDescription(description string) {
if description != "" {
description = "\n" + description
Expand Down
6 changes: 6 additions & 0 deletions backlog/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,12 @@ func (content *MarkdownContent) SetMetadataValue(key, value string) {
}
}

func (content *MarkdownContent) ReplaceMetadataKey(oldKey, newKey string) {
if content.metadata.ReplaceKey(oldKey, newKey) {
content.markDirty()
}
}

func (content *MarkdownContent) RemoveMetadata(key string) {
if content.metadata.Remove(key) {
content.markDirty()
Expand Down
10 changes: 10 additions & 0 deletions backlog/markdown_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ func (m *MarkdownMetadata) SetValue(key, value string) bool {
return true
}

func (m *MarkdownMetadata) ReplaceKey(oldKey, newKey string) bool {
for _, item := range m.items {
if strings.ToLower(item.key) == strings.ToLower(oldKey) {
item.key = newKey
return true
}
}
return false
}

func (m *MarkdownMetadata) Remove(key string) bool {
for i, item := range m.items {
if strings.ToLower(item.key) == strings.ToLower(key) {
Expand Down
13 changes: 13 additions & 0 deletions backlog/timeline.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,16 @@ func (tg *TimelineGenerator) sortTimelineItems(items []*timelineItem) {
return items[i].item.Name() < items[j].item.Name()
})
}

func (tg *TimelineGenerator) RenameTimeline(oldTag, newTag string) error {
timelineDirectory := filepath.Join(tg.rootDir, TimelineDirectoryName)
oldPngPath := filepath.Join(timelineDirectory, fmt.Sprintf("%s.png", oldTag))
newPngPath := filepath.Join(timelineDirectory, fmt.Sprintf("%s.png", newTag))
return os.Rename(oldPngPath, newPngPath)
}

func (tg *TimelineGenerator) RemoveTimeline(tag string) error {
timelineDirectory := filepath.Join(tg.rootDir, TimelineDirectoryName)
pngPath := filepath.Join(timelineDirectory, fmt.Sprintf("%s.png", tag))
return os.Remove(pngPath)
}
70 changes: 70 additions & 0 deletions commands/change_tag_command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package commands

import (
"fmt"
"github.com/mreider/agilemarkdown/backlog"
"github.com/mreider/agilemarkdown/utils"
"gopkg.in/urfave/cli.v1"
"path/filepath"
"strings"
)

var ChangeTagCommand = cli.Command{
Name: "change-tag",
Usage: "Change a tag",
ArgsUsage: "OLD_TAG NEW_TAG",
Action: func(c *cli.Context) error {
if c.NArg() != 2 {
fmt.Println("old and new tags should be specified")
return nil
}

rootDir, _ := filepath.Abs(".")
if err := checkIsBacklogDirectory(); err == nil {
rootDir = filepath.Dir(rootDir)
} else if err := checkIsRootDirectory("."); err != nil {
return err
}

oldTag := strings.ToLower(c.Args()[0])
newTag := strings.ToLower(c.Args()[1])

if oldTag == newTag {
fmt.Println("Old and new tags are equal")
return nil
}

allTags, itemsTags, ideasTags, _, err := backlog.ItemsAndIdeasTags(rootDir)
if err != nil {
return err
}

if _, ok := allTags[oldTag]; !ok {
fmt.Printf("Tag '%s' not found.\n", oldTag)
return nil
}

tagItems := itemsTags[oldTag]
for _, item := range tagItems {
itemTags := item.Tags()
itemTags = utils.RenameItemIgnoreCase(itemTags, oldTag, newTag)
item.SetTags(itemTags)
item.ChangeTimelineTag(oldTag, newTag)
item.Save()
}

tagIdeas := ideasTags[oldTag]
for _, idea := range tagIdeas {
ideaTags := idea.Tags()
ideaTags = utils.RenameItemIgnoreCase(ideaTags, oldTag, newTag)
idea.SetTags(ideaTags)
idea.Save()
}

backlog.NewTimelineGenerator(rootDir).RenameTimeline(oldTag, newTag)

fmt.Printf("Tag '%s' changed to '%s'. Sync to regenerate files.\n", oldTag, newTag)

return nil
},
}
25 changes: 21 additions & 4 deletions commands/sync_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -663,14 +663,31 @@ func (a *SyncAction) updateItemsFileNames(rootDir string) error {
}

func (a *SyncAction) updateTimeline(rootDir string) error {
timelineDir := filepath.Join(rootDir, backlog.TimelineDirectoryName)
items, err := ioutil.ReadDir(timelineDir)
allTags, itemsTags, _, _, err := backlog.ItemsAndIdeasTags(rootDir)
if err != nil {
return err
}

allTags, _, _, _, err := backlog.ItemsAndIdeasTags(rootDir)
if err != nil {
timelineGenerator := backlog.NewTimelineGenerator(rootDir)
for tag, tagItems := range itemsTags {
hasTimeline := false
for _, item := range tagItems {
startDate, endDate := item.Timeline(tag)
if !startDate.IsZero() && !endDate.IsZero() {
hasTimeline = true
break
}
}
if hasTimeline {
timelineGenerator.ExecuteForTag(tag)
} else {
timelineGenerator.RemoveTimeline(tag)
}
}

timelineDir := filepath.Join(rootDir, backlog.TimelineDirectoryName)
items, err := ioutil.ReadDir(timelineDir)
if err != nil && !os.IsNotExist(err) {
return err
}

Expand Down
1 change: 1 addition & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ func main() {
commands.CreateUserCommand,
commands.TimelineCommand,
commands.DeleteTagCommand,
commands.ChangeTagCommand,
}

err = app.Run(os.Args)
Expand Down
9 changes: 9 additions & 0 deletions tests/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,15 @@ func TestRemoveItemIgnoreCase(t *testing.T) {
assert.Equal(t, []string{"b", "c"}, utils.RemoveItemIgnoreCase([]string{"A", "b", "c"}, "a"))
}

func TestRenameItemIgnoreCase(t *testing.T) {
assert.Equal(t, []string(nil), utils.RenameItemIgnoreCase(nil, "a", "b"))
assert.Equal(t, []string{}, utils.RenameItemIgnoreCase([]string{}, "a", "b"))
assert.Equal(t, []string{"A", "D", "C"}, utils.RenameItemIgnoreCase([]string{"A", "B", "C"}, "b", "D"))
assert.Equal(t, []string{"A", "C", "d"}, utils.RenameItemIgnoreCase([]string{"A", "B", "C", "d"}, "b", "D"))
assert.Equal(t, []string{"A", "B", "C", "d"}, utils.RenameItemIgnoreCase([]string{"A", "B", "C", "d"}, "e", "D"))
assert.Equal(t, []string{"A", "B", "C", "d"}, utils.RenameItemIgnoreCase([]string{"A", "B", "C", "d"}, "d", "D"))
}

func createDate(year int, month time.Month, day int) time.Time {
return time.Date(year, month, day, 0, 0, 0, 0, time.Local)
}
30 changes: 30 additions & 0 deletions utils/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,33 @@ func RemoveItemIgnoreCase(items []string, item string) []string {
}
return result
}

func RenameItemIgnoreCase(items []string, oldItem, newItem string) []string {
if len(items) == 0 {
return items
}

if strings.ToLower(oldItem) == strings.ToLower(newItem) {
return items
}

newItemExists := false
for _, it := range items {
if strings.ToLower(it) == strings.ToLower(newItem) {
newItemExists = true
break
}
}

oldItem = strings.ToLower(oldItem)
result := make([]string, 0, len(items))
for _, it := range items {
if strings.ToLower(it) != oldItem {
result = append(result, it)
} else if !newItemExists {
result = append(result, newItem)
newItemExists = true
}
}
return result
}

0 comments on commit c4cefd5

Please sign in to comment.