{"id":20924701,"url":"https://github.com/ddddddo/gdag","last_synced_at":"2025-05-13T16:31:26.160Z","repository":{"id":39801734,"uuid":"398355258","full_name":"ddddddO/gdag","owner":"ddddddO","description":"Easily manage 🕸DAG🕷 with Go. DAG is an acronym for Directed Acyclic Graph. Output is in PlantUML or Mermaid format. Useful for progressing tasks.","archived":false,"fork":false,"pushed_at":"2025-02-13T12:53:07.000Z","size":340,"stargazers_count":42,"open_issues_count":8,"forks_count":4,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-05-13T16:14:51.243Z","etag":null,"topics":["dag","data-structures","mermaid","plantuml","workflow"],"latest_commit_sha":null,"homepage":"https://scrapbox.io/ddddddo/useful_tools","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ddddddO.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-08-20T17:35:32.000Z","updated_at":"2025-02-13T12:53:11.000Z","dependencies_parsed_at":"2023-02-17T20:45:24.106Z","dependency_job_id":"ee38ecb3-d107-4f4e-8648-36e9f82ddd64","html_url":"https://github.com/ddddddO/gdag","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddddddO%2Fgdag","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddddddO%2Fgdag/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddddddO%2Fgdag/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ddddddO%2Fgdag/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ddddddO","download_url":"https://codeload.github.com/ddddddO/gdag/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253981760,"owners_count":21994330,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dag","data-structures","mermaid","plantuml","workflow"],"created_at":"2024-11-18T20:24:27.928Z","updated_at":"2025-05-13T16:31:22.213Z","avatar_url":"https://github.com/ddddddO.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gdag\n\n![](spider.png)\n\nEasily manage 🕸DAG🕷 with Go.\u003cbr\u003e\nDAG is an acronym for Directed Acyclic Graph.\u003cbr\u003e\nOutput is in PlantUML or Mermaid format.\u003cbr\u003e\nUseful for progressing tasks, designing components, etc...\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/ddddddO/gdag.svg)](https://pkg.go.dev/github.com/ddddddO/gdag) [![GitHub release](https://img.shields.io/github/release/ddddddO/gdag.svg)](https://github.com/ddddddO/gdag/releases) [![ci](https://github.com/ddddddO/gdag/actions/workflows/ci.yaml/badge.svg)](https://github.com/ddddddO/gdag/actions/workflows/ci.yaml) [![codecov](https://codecov.io/gh/ddddddO/gdag/branch/main/graph/badge.svg?token=OO8ZSJFTL4)](https://codecov.io/gh/ddddddO/gdag)\n\n# Installation\n```console\n$ go get github.com/ddddddO/gdag\n```\n\n# Demo\n## PlantUML\n\n1. `go run main.go \u003e dag.pu`\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\tg \"github.com/ddddddO/gdag\"\n)\n\nfunc main() {\n\tvar dag *g.Node = g.DAG(\"ゴール(目的)\")\n\n\tvar design *g.Node = g.Task(\"設計\")\n\treviewDesign := g.Task(\"レビュー対応\")\n\n\tdevelopFeature1 := g.Task(\"feature1開発\")\n\tdevelopFeature1.Note(\"xxが担当\")\n\treviewDevelopFeature1 := g.Task(\"レビュー対応\")\n\n\tdevelopFeature2 := g.Task(\"feature2開発\")\n\tdevelopFeature2.Note(\"yyが担当\")\n\treviewDevelopFeature2 := g.Task(\"レビュー対応\")\n\n\tprepareInfra := g.Task(\"インフラ準備\")\n\tprepareInfra.Note(\"zzが担当\")\n\n\ttest := g.Task(\"結合テスト\")\n\trelease := g.Task(\"リリース\")\n\tfinish := g.Task(\"finish\")\n\n\tdag.Con(design).Con(reviewDesign).Con(developFeature1).Con(reviewDevelopFeature1).Con(test)\n\treviewDesign.Con(developFeature2).Con(reviewDevelopFeature2).Con(test)\n\treviewDesign.Con(prepareInfra).Con(test)\n\ttest.Con(release).Con(finish)\n\n\tg.Done(design, reviewDesign, developFeature1, reviewDevelopFeature1, developFeature2)\n\n\tuml, err := dag.UML()\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n\tfmt.Println(uml)\n}\n```\n\n```\n@startuml\nrectangle \"ゴール(目的)\" as 1\nusecase \"設計\" as 2 #DarkGray\nusecase \"レビュー対応\" as 3 #DarkGray\nusecase \"feature1開発\" as 4 #DarkGray\nnote left\nxxが担当\nend note\nusecase \"レビュー対応\" as 5 #DarkGray\nusecase \"結合テスト\" as 9\nusecase \"リリース\" as 10\nusecase \"finish\" as 11\nusecase \"feature2開発\" as 6 #DarkGray\nnote left\nyyが担当\nend note\nusecase \"レビュー対応\" as 7\nusecase \"インフラ準備\" as 8\nnote left\nzzが担当\nend note\n\n1 --\u003e 2\n2 --\u003e 3\n3 --\u003e 4\n4 --\u003e 5\n5 --\u003e 9\n9 --\u003e 10\n10 --\u003e 11\n3 --\u003e 6\n6 --\u003e 7\n7 --\u003e 9\n3 --\u003e 8\n8 --\u003e 9\n\n@enduml\n```\n\n2. dag.pu to png or svg\n![image](dag.svg)\n\n\n### Critical path\n\n1. `go run main.go \u003e dag.pu`\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\tg \"github.com/ddddddO/gdag\"\n)\n\nfunc main() {\n\tvar dag *g.Node = g.DAG(\"ゴール(目的)\")\n\n\tvar design *g.Node = g.Task(\"設計\").Hour(10)\n\treviewDesign := g.Task(\"レビュー対応\").Hour(2)\n\n\tdevelopFeature1 := g.Task(\"feature1開発\").Hour(20)\n\tdevelopFeature1.Note(\"xxが担当\")\n\treviewDevelopFeature1 := g.Task(\"レビュー対応\").Hour(1.5)\n\n\tdevelopFeature2 := g.Task(\"feature2開発\").Hour(15)\n\tdevelopFeature2.Note(\"yyが担当\")\n\treviewDevelopFeature2 := g.Task(\"レビュー対応\").Hour(1.5)\n\n\tprepareInfra := g.Task(\"インフラ準備\").Hour(15)\n\tprepareInfra.Note(\"zzが担当\")\n\n\ttest := g.Task(\"結合テスト\").Hour(20)\n\trelease := g.Task(\"リリース\").Hour(2)\n\tfinish := g.Task(\"finish\")\n\n\tdag.Con(design).Con(reviewDesign).Con(developFeature1).Con(reviewDevelopFeature1).Con(test)\n\treviewDesign.Con(developFeature2).Con(reviewDevelopFeature2).Con(test)\n\treviewDesign.Con(prepareInfra).Con(test)\n\ttest.Con(release).Con(finish)\n\n\tg.Done(design, reviewDesign, developFeature1, reviewDevelopFeature1, developFeature2)\n\n\t// If you do not want to represent critical path, use `dag.UMLNoCritical()`.\n\tuml, err := dag.UML()\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n\tfmt.Println(uml)\n}\n```\n\n```\n@startuml\nrectangle \"ゴール(目的)\" as 1\nusecase \"設計 (10.0h)\" as 2 #DarkGray-Yellow\nusecase \"レビュー対応 (2.0h)\" as 3 #DarkGray-Yellow\nusecase \"feature1開発 (20.0h)\" as 4 #DarkGray-Yellow\nnote left\nxxが担当\nend note\nusecase \"レビュー対応 (1.5h)\" as 5 #DarkGray-Yellow\nusecase \"結合テスト (20.0h)\" as 9 #Yellow\nusecase \"リリース (2.0h)\" as 10 #Yellow\nusecase \"finish\" as 11 #Yellow\nusecase \"feature2開発 (15.0h)\" as 6 #DarkGray\nnote left\nyyが担当\nend note\nusecase \"レビュー対応 (1.5h)\" as 7\nusecase \"インフラ準備 (15.0h)\" as 8\nnote left\nzzが担当\nend note\n\n1 --\u003e 2\n2 --\u003e 3\n3 --\u003e 4\n4 --\u003e 5\n5 --\u003e 9\n9 --\u003e 10\n10 --\u003e 11\n3 --\u003e 6\n6 --\u003e 7\n7 --\u003e 9\n3 --\u003e 8\n8 --\u003e 9\n\n@enduml\n```\n\n2. dag.pu to png or svg\n![image](dag_critical.svg)\n\n## Mermaid\n\n※ Mermaid method does not support critical paths.\n\n1. `go run main.go`\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\tg \"github.com/ddddddO/gdag\"\n)\n\nfunc main() {\n\tvar dag *g.Node = g.DAG(\"ゴール(目的)\")\n\n\tvar design *g.Node = g.Task(\"設計\").Hour(10)\n\treviewDesign := g.Task(\"レビュー対応\").Hour(2)\n\n\tdevelopFeature1 := g.Task(\"feature1開発\").Hour(20)\n\tdevelopFeature1.Note(\"xxが担当\")\n\treviewDevelopFeature1 := g.Task(\"レビュー対応\").Hour(1.5)\n\n\tdevelopFeature2 := g.Task(\"feature2開発\").Hour(15)\n\tdevelopFeature2.Note(\"yyが担当\")\n\treviewDevelopFeature2 := g.Task(\"レビュー対応\").Hour(1.5)\n\n\tprepareInfra := g.Task(\"インフラ準備\").Hour(15)\n\tprepareInfra.Note(\"zzが担当\")\n\n\ttest := g.Task(\"結合テスト\").Hour(20)\n\trelease := g.Task(\"リリース\").Hour(2)\n\tfinish := g.Task(\"finish\")\n\n\tdag.Con(design).Con(reviewDesign).Con(developFeature1).Con(reviewDevelopFeature1).Con(test)\n\treviewDesign.Con(developFeature2).Con(reviewDevelopFeature2).Con(test)\n\treviewDesign.Con(prepareInfra).Con(test)\n\ttest.Con(release).Con(finish)\n\n\tg.Done(design, reviewDesign, developFeature1, reviewDevelopFeature1, developFeature2)\n\n\tmermaid, err := dag.Mermaid()\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n\tfmt.Println(mermaid)\n}\n```\n\n```\ngraph TD\nclassDef doneColor fill:#868787\n1(\"ゴール(目的)\")\n2([\"設計 (10.0h)\"]):::doneColor\n3([\"レビュー対応 (2.0h)\"]):::doneColor\n4([\"feature1開発 (20.0h)\"]):::doneColor\n5([\"レビュー対応 (1.5h)\"]):::doneColor\n9([\"結合テスト (20.0h)\"])\n10([\"リリース (2.0h)\"])\n11([\"finish\"])\n6([\"feature2開発 (15.0h)\"]):::doneColor\n7([\"レビュー対応 (1.5h)\"])\n8([\"インフラ準備 (15.0h)\"])\n\n1 --\u003e 2\n2 --\u003e 3\n3 --\u003e 4\n4 --\u003e 5\n5 --\u003e 9\n9 --\u003e 10\n10 --\u003e 11\n3 --\u003e 6\n6 --\u003e 7\n7 --\u003e 9\n3 --\u003e 8\n8 --\u003e 9\n```\n\n2. rendering\n\n```mermaid\ngraph TD\nclassDef doneColor fill:#868787\n1(\"ゴール(目的)\")\n2([\"設計 (10.0h)\"]):::doneColor\n3([\"レビュー対応 (2.0h)\"]):::doneColor\n4([\"feature1開発 (20.0h)\"]):::doneColor\n5([\"レビュー対応 (1.5h)\"]):::doneColor\n9([\"結合テスト (20.0h)\"])\n10([\"リリース (2.0h)\"])\n11([\"finish\"])\n6([\"feature2開発 (15.0h)\"]):::doneColor\n7([\"レビュー対応 (1.5h)\"])\n8([\"インフラ準備 (15.0h)\"])\n\n1 --\u003e 2\n2 --\u003e 3\n3 --\u003e 4\n4 --\u003e 5\n5 --\u003e 9\n9 --\u003e 10\n10 --\u003e 11\n3 --\u003e 6\n6 --\u003e 7\n7 --\u003e 9\n3 --\u003e 8\n8 --\u003e 9\n```\n\n## CheckList\n\n1. `go run main.go`\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\tg \"github.com/ddddddO/gdag\"\n)\n\nfunc main() {\n\tdag := g.DAG(\"ゴール(目的)\")\n\n\tdesign := g.Task(\"設計\")\n\treviewDesign := g.Task(\"レビュー対応\")\n\n\tdevelopFeature1 := g.Task(\"feature1開発\")\n\tdevelopFeature1.Note(\"xxが担当\")\n\treviewDevelopFeature1 := g.Task(\"レビュー対応\")\n\n\tdevelopFeature2 := g.Task(\"feature2開発\")\n\tdevelopFeature2.Note(\"yyが担当\")\n\treviewDevelopFeature2 := g.Task(\"レビュー対応\")\n\n\tprepareInfra := g.Task(\"インフラ準備\")\n\tprepareInfra.Note(\"zzが担当\")\n\n\ttest := g.Task(\"結合テスト\")\n\trelease := g.Task(\"リリース\")\n\tfinish := g.Task(\"finish\")\n\n\tdag.Con(design).Con(reviewDesign).Con(developFeature1).Con(reviewDevelopFeature1).Con(test)\n\treviewDesign.Con(developFeature2).Con(reviewDevelopFeature2).Con(test)\n\treviewDesign.Con(prepareInfra).Con(test)\n\ttest.Con(release).Con(finish)\n\n\tg.Done(design, reviewDesign, developFeature2, finish)\n\n\tcheckList, err := dag.CheckList()\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n\tfmt.Println(checkList)\n}\n```\n\n```\n### ゴール(目的)\n- [x] 設計\n- [x] レビュー対応\n- [ ] feature1開発\n- [ ] レビュー対応\n- [x] feature2開発\n- [ ] レビュー対応\n- [ ] インフラ準備\n- [ ] 結合テスト\n- [ ] リリース\n- [x] finish\n```\n\n2. share with members\n### ゴール(目的)\n- [x] 設計\n- [x] レビュー対応\n- [ ] feature1開発\n- [ ] レビュー対応\n- [x] feature2開発\n- [ ] レビュー対応\n- [ ] インフラ準備\n- [ ] 結合テスト\n- [ ] リリース\n- [x] finish\n\n## Miscellaneous\n\n### FanIn/FanOut\n\n1. Fanin/Fanout func usage\n\t```go\n\tpackage main\n\n\timport (\n\t\t\"fmt\"\n\t\t\"os\"\n\n\t\tg \"github.com/ddddddO/gdag\"\n\t)\n\n\tfunc main() {\n\t\tdag := g.DAG(\"Fanin/Fanout\")\n\t\tdag.Fanout(\n\t\t\tg.Task(\"t1\"), g.Task(\"t2\"),\n\t\t).Fanin(\n\t\t\tg.Task(\"t3\"),\n\t\t).Fanout(\n\t\t\tg.Task(\"t4\"), g.Task(\"t5\"), g.Task(\"t6\"), g.Task(\"t7\"),\n\t\t).Fanin(\n\t\t\tg.Task(\"t8\"),\n\t\t).Con(\n\t\t\tg.Task(\"t9\"),\n\t\t).Fanout(\n\t\t\tg.Task(\"t10\"), g.Task(\"t11\"),\n\t\t).Fanin(\n\t\t\tg.Task(\"end\"),\n\t\t)\n\t\tuml, err := dag.UML()\n\t\tif err != nil {\n\t\t\tfmt.Fprintln(os.Stderr, err)\n\t\t\tos.Exit(1)\n\t\t}\n\t\tfmt.Println(uml)\n\t}\n\t```\n\n2. Result\n\n\t![](./_example/fanin_fanout/uml.svg)\n\n### short name methods\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\n\tg \"github.com/ddddddO/gdag\"\n)\n\nfunc main() {\n\tvar dag *g.Node = g.DAG(\"ゴール(目的)\")\n\n\tvar design *g.Node = g.T(\"設計\")\n\treviewDesign := g.T(\"レビュー対応\")\n\n\tdevelopFeature1 := g.T(\"feature1開発\")\n\tdevelopFeature1.N(\"xxが担当\")\n\treviewDevelopFeature1 := g.T(\"レビュー対応\")\n\n\tdevelopFeature2 := g.T(\"feature2開発\").N(\"yyが担当\")\n\treviewDevelopFeature2 := g.T(\"レビュー対応\")\n\n\tprepareInfra := g.T(\"インフラ準備\").N(\"zzが担当\")\n\n\ttest := g.T(\"結合テスト\")\n\trelease := g.T(\"リリース\")\n\tfinish := g.T(\"finish\")\n\n\tdag.C(design).C(reviewDesign).C(developFeature1).C(reviewDevelopFeature1).C(test)\n\treviewDesign.C(developFeature2).C(reviewDevelopFeature2).C(test)\n\treviewDesign.C(prepareInfra).C(test)\n\ttest.C(release).C(finish)\n\n\tg.D(design, reviewDesign, developFeature2, finish)\n\n\tuml, err := dag.UML()\n\tif err != nil {\n\t\tfmt.Fprintln(os.Stderr, err)\n\t\tos.Exit(1)\n\t}\n\tfmt.Println(uml)\n}\n```\n\n### Ginger grilled pork recipe (and more)\n![dag](_example/dinner/dag.svg)\n\n### Component design\n![dag](_example/component_design/components.svg)\n\n- 「Clean Architecture 達人に学ぶソフトウェアの構造と設計」P131 図14-4 より\n\n# Reference\n- [about DAG](https://nave-kazu.hatenablog.com/entry/2015/11/30/154810)\n- [タスクの鳥瞰図を楽に(?)管理する](https://zenn.dev/openlogi/articles/a8edae5e9eb884)\n\n# Stargazers over time\n[![Stargazers over time](https://starchart.cc/ddddddO/gdag.svg?variant=adaptive)](https://starchart.cc/ddddddO/gdag)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddddddo%2Fgdag","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fddddddo%2Fgdag","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fddddddo%2Fgdag/lists"}