github.com/nektos/act@v0.2.83/cmd/notices.go (about)

     1  package cmd
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"net/http"
     7  	"net/url"
     8  	"os"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strings"
    12  	"time"
    13  
    14  	log "github.com/sirupsen/logrus"
    15  )
    16  
    17  type Notice struct {
    18  	Level   string `json:"level"`
    19  	Message string `json:"message"`
    20  }
    21  
    22  func displayNotices(input *Input) {
    23  	// Avoid causing trouble parsing the json
    24  	if input.listOptions {
    25  		return
    26  	}
    27  	select {
    28  	case notices := <-noticesLoaded:
    29  		if len(notices) > 0 {
    30  			noticeLogger := log.New()
    31  			if input.jsonLogger {
    32  				noticeLogger.SetFormatter(&log.JSONFormatter{})
    33  			} else {
    34  				noticeLogger.SetFormatter(&log.TextFormatter{
    35  					DisableQuote:     true,
    36  					DisableTimestamp: true,
    37  					PadLevelText:     true,
    38  				})
    39  			}
    40  
    41  			fmt.Printf("\n")
    42  			for _, notice := range notices {
    43  				level, err := log.ParseLevel(notice.Level)
    44  				if err != nil {
    45  					level = log.InfoLevel
    46  				}
    47  				noticeLogger.Log(level, notice.Message)
    48  			}
    49  		}
    50  	case <-time.After(time.Second * 1):
    51  		log.Debugf("Timeout waiting for notices")
    52  	}
    53  }
    54  
    55  var noticesLoaded = make(chan []Notice)
    56  
    57  func loadVersionNotices(version string) {
    58  	go func() {
    59  		noticesLoaded <- getVersionNotices(version)
    60  	}()
    61  }
    62  
    63  const NoticeURL = "https://api.nektosact.com/notices"
    64  
    65  func getVersionNotices(version string) []Notice {
    66  	if os.Getenv("ACT_DISABLE_VERSION_CHECK") == "1" {
    67  		return nil
    68  	}
    69  
    70  	noticeURL, err := url.Parse(NoticeURL)
    71  	if err != nil {
    72  		log.Error(err)
    73  		return nil
    74  	}
    75  	query := noticeURL.Query()
    76  	query.Add("os", runtime.GOOS)
    77  	query.Add("arch", runtime.GOARCH)
    78  	query.Add("version", version)
    79  
    80  	noticeURL.RawQuery = query.Encode()
    81  
    82  	client := &http.Client{}
    83  	req, err := http.NewRequest("GET", noticeURL.String(), nil)
    84  	if err != nil {
    85  		log.Debug(err)
    86  		return nil
    87  	}
    88  
    89  	etag := loadNoticesEtag()
    90  	if etag != "" {
    91  		log.Debugf("Conditional GET for notices etag=%s", etag)
    92  		req.Header.Set("If-None-Match", etag)
    93  	}
    94  
    95  	resp, err := client.Do(req)
    96  	if err != nil {
    97  		log.Debug(err)
    98  		return nil
    99  	}
   100  
   101  	newEtag := resp.Header.Get("Etag")
   102  	if newEtag != "" {
   103  		log.Debugf("Saving notices etag=%s", newEtag)
   104  		saveNoticesEtag(newEtag)
   105  	}
   106  
   107  	defer resp.Body.Close()
   108  	notices := []Notice{}
   109  	if resp.StatusCode == 304 {
   110  		log.Debug("No new notices")
   111  		return nil
   112  	}
   113  	if err := json.NewDecoder(resp.Body).Decode(&notices); err != nil {
   114  		log.Debug(err)
   115  		return nil
   116  	}
   117  
   118  	return notices
   119  }
   120  
   121  func loadNoticesEtag() string {
   122  	p := etagPath()
   123  	content, err := os.ReadFile(p)
   124  	if err != nil {
   125  		log.Debugf("Unable to load etag from %s: %e", p, err)
   126  	}
   127  	return strings.TrimSuffix(string(content), "\n")
   128  }
   129  
   130  func saveNoticesEtag(etag string) {
   131  	p := etagPath()
   132  	err := os.WriteFile(p, []byte(strings.TrimSuffix(etag, "\n")), 0o600)
   133  	if err != nil {
   134  		log.Debugf("Unable to save etag to %s: %e", p, err)
   135  	}
   136  }
   137  
   138  func etagPath() string {
   139  	dir := filepath.Join(CacheHomeDir, "act")
   140  	if err := os.MkdirAll(dir, 0o777); err != nil {
   141  		log.Fatal(err)
   142  	}
   143  	return filepath.Join(dir, ".notices.etag")
   144  }