Skip to content

Instantly share code, notes, and snippets.

@devjoca
Forked from aarongorka/gitlab_dag_diagram.py
Created February 17, 2020 19:18
Show Gist options
  • Save devjoca/b1b1ed0a65e6e16bf75f6d9e453a929c to your computer and use it in GitHub Desktop.
Save devjoca/b1b1ed0a65e6e16bf75f6d9e453a929c to your computer and use it in GitHub Desktop.

Revisions

  1. @aarongorka aarongorka revised this gist Sep 24, 2019. 1 changed file with 23 additions and 2 deletions.
    25 changes: 23 additions & 2 deletions gitlab_dag_diagram.py
    Original file line number Diff line number Diff line change
    @@ -3,6 +3,7 @@

    import sys
    import yaml
    from pprint import pprint

    def merge(user, default):
    if isinstance(user,dict) and isinstance(default,dict):
    @@ -28,6 +29,11 @@ def merge(user, default):
    print('@startuml')
    print('left to right direction')
    jobs = {k: v for k, v in merged.items() if k not in ['image', 'services', 'stages', 'include']}
    branches = {}
    all_changes = [v['only']['changes'] for k, v in jobs.items() if type(v.get('only')) is dict and v.get('only', {}).get('changes', {}) and not v.get('needs')] # gather all `only:changes`
    for changes in all_changes:
    branches[str(changes)] = [] # list of e.g. {"kibana/**/*": deployKibanaDev}

    if len(sys.argv) > 1:
    for stage in merged['stages']: # This groups by stage, which looks nice but may be misleading
    matching_jobs = [k for k, v in jobs.items() if v['stage'] == stage]
    @@ -42,10 +48,25 @@ def merge(user, default):
    print("}")
    else:
    for job in jobs:
    changes = []
    needs = merged[job].get('needs')
    if needs:
    try:
    changes = merged[job]['only']['changes']
    except:
    pass
    if needs: # if `needs:` exists, `only:changes` is implied from transitive depenencies
    for need in needs:
    print(f'"{need}" --> "{job}" ')
    else:
    print(f'(*) --> "{job}" ')
    if changes: # first job, has `only:changes`
    branches[str(changes)].append(job)
    else: # first job, triggers off all commits
    print(f'(*) --> "{job}" ')
    if branches:
    for branch in branches:
    print(f'(*) --> if "{branch}" then')
    for job in branches[branch]:
    print(f' --> "{job}"')
    print(f'else') # this is probably not how `else` is supposed to be used but it looks good.
    print('}')
    print('@enduml')
  2. @aarongorka aarongorka revised this gist Sep 20, 2019. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion gitlab_dag_diagram.py
    Original file line number Diff line number Diff line change
    @@ -3,7 +3,6 @@

    import sys
    import yaml
    from pprint import pprint

    def merge(user, default):
    if isinstance(user,dict) and isinstance(default,dict):
  3. @aarongorka aarongorka revised this gist Sep 19, 2019. 1 changed file with 21 additions and 19 deletions.
    40 changes: 21 additions & 19 deletions gitlab_dag_diagram.py
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,7 @@
    #!/usr/bin/env python3
    """Prints a PlantUML diagram that shows the DAG of the GitLab pipeline"""

    import sys
    import yaml
    from pprint import pprint

    @@ -28,23 +29,24 @@ def merge(user, default):
    print('@startuml')
    print('left to right direction')
    jobs = {k: v for k, v in merged.items() if k not in ['image', 'services', 'stages', 'include']}
    # This groups by stage, which looks nice but may be misleading
    #for stage in merged['stages']:
    # matching_jobs = [k for k, v in jobs.items() if v['stage'] == stage]
    # print(f'partition "{stage}" {{')
    # for job in matching_jobs:
    # needs = merged[job].get('needs')
    # if needs:
    # for need in needs:
    # print(f' "{need}" --> "{job}" ')
    # else:
    # print(f' (*) --> "{job}" ')
    # print("}")
    for job in jobs:
    needs = merged[job].get('needs')
    if needs:
    for need in needs:
    print(f'"{need}" --> "{job}" ')
    else:
    print(f'(*) --> "{job}" ')
    if len(sys.argv) > 1:
    for stage in merged['stages']: # This groups by stage, which looks nice but may be misleading
    matching_jobs = [k for k, v in jobs.items() if v['stage'] == stage]
    print(f'partition "{stage}" {{')
    for job in matching_jobs:
    needs = merged[job].get('needs')
    if needs:
    for need in needs:
    print(f' "{need}" --> "{job}" ')
    else:
    print(f' (*) --> "{job}" ')
    print("}")
    else:
    for job in jobs:
    needs = merged[job].get('needs')
    if needs:
    for need in needs:
    print(f'"{need}" --> "{job}" ')
    else:
    print(f'(*) --> "{job}" ')
    print('@enduml')
  4. @aarongorka aarongorka revised this gist Sep 9, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion gitlab_dag_diagram.py
    Original file line number Diff line number Diff line change
    @@ -20,7 +20,7 @@ def merge(user, default):
    filenames.append('.gitlab-ci.yml')

    for filename in filenames:
    with open(filename) as file:
    with open(f'./{filename}') as file:
    tmp = yaml.load(file)
    merge(merged, tmp)
    tmp = {}
  5. @aarongorka aarongorka revised this gist Sep 9, 2019. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions gitlab_dag_diagram.py
    Original file line number Diff line number Diff line change
    @@ -14,13 +14,13 @@ def merge(user, default):
    return user

    merged = {}
    with open('../.gitlab-ci.yml') as file:
    with open('.gitlab-ci.yml') as file:
    tmp = yaml.load(file)
    filenames = tmp['include']
    filenames.append('.gitlab-ci.yml')

    for filename in filenames:
    with open(f'../{filename}') as file:
    with open(filename) as file:
    tmp = yaml.load(file)
    merge(merged, tmp)
    tmp = {}
  6. @aarongorka aarongorka created this gist Sep 4, 2019.
    50 changes: 50 additions & 0 deletions gitlab_dag_diagram.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,50 @@
    #!/usr/bin/env python3
    """Prints a PlantUML diagram that shows the DAG of the GitLab pipeline"""

    import yaml
    from pprint import pprint

    def merge(user, default):
    if isinstance(user,dict) and isinstance(default,dict):
    for k,v in default.items():
    if k not in user:
    user[k] = v
    else:
    user[k] = merge(user[k],v)
    return user

    merged = {}
    with open('../.gitlab-ci.yml') as file:
    tmp = yaml.load(file)
    filenames = tmp['include']
    filenames.append('.gitlab-ci.yml')

    for filename in filenames:
    with open(f'../{filename}') as file:
    tmp = yaml.load(file)
    merge(merged, tmp)
    tmp = {}

    print('@startuml')
    print('left to right direction')
    jobs = {k: v for k, v in merged.items() if k not in ['image', 'services', 'stages', 'include']}
    # This groups by stage, which looks nice but may be misleading
    #for stage in merged['stages']:
    # matching_jobs = [k for k, v in jobs.items() if v['stage'] == stage]
    # print(f'partition "{stage}" {{')
    # for job in matching_jobs:
    # needs = merged[job].get('needs')
    # if needs:
    # for need in needs:
    # print(f' "{need}" --> "{job}" ')
    # else:
    # print(f' (*) --> "{job}" ')
    # print("}")
    for job in jobs:
    needs = merged[job].get('needs')
    if needs:
    for need in needs:
    print(f'"{need}" --> "{job}" ')
    else:
    print(f'(*) --> "{job}" ')
    print('@enduml')