github.com/drone/runner-go@v1.12.0/pipeline/reporter/history/history.go (about)

     1  // Copyright 2019 Drone.IO Inc. All rights reserved.
     2  // Use of this source code is governed by the Polyform License
     3  // that can be found in the LICENSE file.
     4  
     5  // Package history implements a tracer that provides access to
     6  // pipeline execution history.
     7  package history
     8  
     9  import (
    10  	"context"
    11  	"sync"
    12  	"time"
    13  
    14  	"github.com/drone/runner-go/internal"
    15  	"github.com/drone/runner-go/pipeline"
    16  )
    17  
    18  var _ pipeline.Reporter = (*History)(nil)
    19  
    20  // default number of historical entries.
    21  const defaultLimit = 25
    22  
    23  // History tracks pending, running and complete pipeline stages
    24  // processed by the system.
    25  type History struct {
    26  	sync.Mutex
    27  	base  pipeline.Reporter
    28  	limit int
    29  	items []*Entry
    30  }
    31  
    32  // New returns a new History recorder that wraps the base
    33  // reporter.
    34  func New(base pipeline.Reporter) *History {
    35  	return &History{base: base}
    36  }
    37  
    38  // ReportStage adds or updates the pipeline history.
    39  func (h *History) ReportStage(ctx context.Context, state *pipeline.State) error {
    40  	h.Lock()
    41  	h.update(state)
    42  	h.prune()
    43  	h.Unlock()
    44  	return h.base.ReportStage(ctx, state)
    45  }
    46  
    47  // ReportStep adds or updates the pipeline history.
    48  func (h *History) ReportStep(ctx context.Context, state *pipeline.State, name string) error {
    49  	h.Lock()
    50  	h.update(state)
    51  	h.prune()
    52  	h.Unlock()
    53  	return h.base.ReportStep(ctx, state, name)
    54  }
    55  
    56  // Entries returns a list of entries.
    57  func (h *History) Entries() []*Entry {
    58  	h.Lock()
    59  	var entries []*Entry
    60  	for _, src := range h.items {
    61  		dst := new(Entry)
    62  		*dst = *src
    63  		entries = append(entries, dst)
    64  	}
    65  	h.Unlock()
    66  	return entries
    67  }
    68  
    69  // Entry returns the entry by id.
    70  func (h *History) Entry(id int64) *Entry {
    71  	h.Lock()
    72  	defer h.Unlock()
    73  	for _, src := range h.items {
    74  		if src.Stage.ID == id {
    75  			dst := new(Entry)
    76  			*dst = *src
    77  			return dst
    78  		}
    79  	}
    80  	return nil
    81  }
    82  
    83  // Limit returns the history limit.
    84  func (h *History) Limit() int {
    85  	if h.limit == 0 {
    86  		return defaultLimit
    87  	}
    88  	return h.limit
    89  }
    90  
    91  func (h *History) update(state *pipeline.State) {
    92  	for _, v := range h.items {
    93  		if v.Stage.ID == state.Stage.ID {
    94  			v.Stage = internal.CloneStage(state.Stage)
    95  			v.Build = internal.CloneBuild(state.Build)
    96  			v.Repo = internal.CloneRepo(state.Repo)
    97  			v.Updated = time.Now().UTC()
    98  			return
    99  		}
   100  	}
   101  	h.items = append(h.items, &Entry{
   102  		Stage:   internal.CloneStage(state.Stage),
   103  		Build:   internal.CloneBuild(state.Build),
   104  		Repo:    internal.CloneRepo(state.Repo),
   105  		Created: time.Now(),
   106  		Updated: time.Now(),
   107  	})
   108  }
   109  
   110  func (h *History) prune() {
   111  	if len(h.items) > h.Limit() {
   112  		h.items = h.items[:h.Limit()-1]
   113  	}
   114  }