From cf99a635b72cce59ce3557ab1499d722917e1680 Mon Sep 17 00:00:00 2001 From: Manfred Touron <94029+moul@users.noreply.github.com> Date: Sun, 30 May 2021 02:20:00 +0000 Subject: [PATCH] feat: add assets-config Signed-off-by: Manfred Touron <94029+moul@users.noreply.github.com> --- .github/assets-config.json | 36 ++++++++++ Makefile | 2 + README.md | 5 +- assets-config.go | 131 +++++++++++++++++++++++++++++++++++++ go.mod | 2 + go.sum | 9 +++ main.go | 4 +- 7 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 .github/assets-config.json create mode 100644 assets-config.go diff --git a/.github/assets-config.json b/.github/assets-config.json new file mode 100644 index 0000000..5fcd2b6 --- /dev/null +++ b/.github/assets-config.json @@ -0,0 +1,36 @@ +{ + "VersionAliases": { + "latest": { + "Assets": 18, + "TargetVersion": "v1.5.1" + }, + "v1": { + "Assets": 18, + "TargetVersion": "v1.5.1" + }, + "v1.0": { + "Assets": 18, + "TargetVersion": "v1.0.0" + }, + "v1.1": { + "Assets": 18, + "TargetVersion": "v1.1.3" + }, + "v1.2": { + "Assets": 18, + "TargetVersion": "v1.2.0" + }, + "v1.3": { + "Assets": 18, + "TargetVersion": "v1.3.0" + }, + "v1.4": { + "Assets": 18, + "TargetVersion": "v1.4.5" + }, + "v1.5": { + "Assets": 18, + "TargetVersion": "v1.5.1" + } + } +} diff --git a/Makefile b/Makefile index 6c2527f..d5b86c3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,8 @@ generate: install echo 'foo@bar:~$$ repoman info .' > .tmp/example-info.txt repoman info . >> .tmp/example-info.txt + repoman assets-config . > .github/assets-config.json + embedmd -w README.md rm -rf .tmp .PHONY: generate diff --git a/README.md b/README.md index 80e5974..b886294 100644 --- a/README.md +++ b/README.md @@ -26,9 +26,9 @@ foo@bar:~$ repoman info . { "Git": { "CloneURL": "git@github.com:moul/repoman", - "CurrentBranch": "master", + "CurrentBranch": "dev/moul/assets-config", "HTMLURL": "https://github.com/moul/repoman", - "InMainBranch": true, + "InMainBranch": false, "IsDirty": null, "MainBranch": "master", "Metadata": { @@ -63,6 +63,7 @@ SUBCOMMANDS maintenance perform various maintenance tasks (write) version show version and build info template-post-clone replace template + assets-config generate a configuration for assets FLAGS -v false verbose mode diff --git a/assets-config.go b/assets-config.go new file mode 100644 index 0000000..73bcd7c --- /dev/null +++ b/assets-config.go @@ -0,0 +1,131 @@ +package main + +import ( + "context" + "flag" + "fmt" + "sort" + + "github.com/Masterminds/semver" + "github.com/google/go-github/v35/github" + "github.com/hokaccha/go-prettyjson" + "go.uber.org/multierr" + "go.uber.org/zap" + "golang.org/x/sync/errgroup" + "moul.io/u" +) + +func doAssetsConfig(ctx context.Context, args []string) error { + if len(args) < 1 { + return flag.ErrHelp + } + paths := u.UniqueStrings(args) + logger.Debug("doAssetsConfig", zap.Any("opts", opts), zap.Strings("project", paths)) + + var errs error + g, ctx := errgroup.WithContext(ctx) + for _, path := range paths { + path := path + g.Go(func() error { + err := doAssetsConfigOnce(ctx, path) + if err != nil { + errs = multierr.Append(errs, fmt.Errorf("%q: %w", path, err)) + } + return nil + }) + } + _ = g.Wait() + return errs +} + +type assetConfigVersion struct { + TargetVersion string `json:",omitempty"` + Assets int `json:",omitempty"` +} + +type assetConfig struct { + VersionAliases map[string]assetConfigVersion + SemverMapping map[string]string `json:",omitempty"` +} + +func doAssetsConfigOnce(_ context.Context, path string) error { + project, err := projectFromPath(path) + if err != nil { + return fmt.Errorf("invalid project: %w", err) + } + + // fetch releases + var releases []*github.RepositoryRelease + { + client := github.NewClient(nil) + var err error + releases, _, err = client.Repositories.ListReleases(context.Background(), project.Git.RepoOwner, project.Git.RepoName, nil) + if err != nil { + return fmt.Errorf("GH API: list releases: %w", err) + } + } + + // compute config + var config assetConfig + { + config = assetConfig{ + VersionAliases: make(map[string]assetConfigVersion), + SemverMapping: make(map[string]string), + } + + rawVersions := []string{} + for _, release := range releases { + if release.GetDraft() || release.GetPrerelease() || len(release.Assets) == 0 { + continue + } + rawVersions = append(rawVersions, release.GetTagName()) + } + versions := make([]*semver.Version, 0) + for _, raw := range rawVersions { + version, err := semver.NewVersion(raw) + if err != nil { + logger.Warn("cannot parse version", zap.String("raw", raw), zap.Error(err)) + continue + } + config.SemverMapping[version.String()] = raw + versions = append(versions, version) + } + sort.Sort(semver.Collection(versions)) + + for _, version := range versions { + raw := config.SemverMapping[version.String()] + var release *github.RepositoryRelease + for _, r := range releases { + if r.GetTagName() == raw { + release = r + break + } + } + _ = release + minor := fmt.Sprintf("v%d.%d", version.Major(), version.Minor()) + major := fmt.Sprintf("v%d", version.Major()) + configVersion := assetConfigVersion{ + TargetVersion: raw, + Assets: len(release.Assets), + } + config.VersionAliases[minor] = configVersion + config.VersionAliases[major] = configVersion + config.VersionAliases["latest"] = configVersion + } + } + + // cleanup + { + config.SemverMapping = nil + } + + // print + { + s, err := prettyjson.Marshal(config) + if err != nil { + return fmt.Errorf("json marshal error: %w", err) + } + fmt.Println(string(s)) + } + return nil +} diff --git a/go.mod b/go.mod index bb412ec..18bbcb9 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,13 @@ module moul.io/repoman go 1.13 require ( + github.com/Masterminds/semver v1.5.0 github.com/Microsoft/go-winio v0.5.0 // indirect github.com/ProtonMail/go-crypto v0.0.0-20210512092938-c05353c2d58c // indirect github.com/fatih/color v1.12.0 // indirect github.com/github/hub/v2 v2.14.3-0.20210319163717-c8e68d548a39 github.com/go-git/go-git/v5 v5.4.1 + github.com/google/go-github/v35 v35.2.0 github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519 github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/kevinburke/ssh_config v1.1.0 // indirect diff --git a/go.sum b/go.sum index e11cf99..a628efb 100644 --- a/go.sum +++ b/go.sum @@ -1,6 +1,8 @@ github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= +github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0= github.com/Microsoft/go-winio v0.5.0 h1:Elr9Wn+sGKPlkaBvwu4mTrxtmOp3F3yV9qhaHbXGjwU= @@ -38,9 +40,14 @@ github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2Su github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0= github.com/go-git/go-git/v5 v5.4.1 h1:2RJXJuTMac944e419pJJJ3mOJBcr3A3M6SN6wQKZ/Gs= github.com/go-git/go-git/v5 v5.4.1/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-github/v35 v35.2.0 h1:s/soW8jauhjUC3rh8JI0FePuocj0DEI9DNBg/bVplE8= +github.com/google/go-github/v35 v35.2.0/go.mod h1:s0515YVTI+IMrDoy9Y4pHt9ShGpzHvHO8rZ7L7acgvs= +github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= +github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519 h1:nqAlWFEdqI0ClbTDrhDvE/8LeQ4pftrqKUX9w5k0j3s= github.com/hokaccha/go-prettyjson v0.0.0-20210113012101-fb4e108d2519/go.mod h1:pFlLw2CfqZiIBOx6BuCeRLCrfxBJipTY0nIOF/VbGcI= @@ -147,6 +154,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k= golang.org/x/net v0.0.0-20210525063256-abc453219eb5 h1:wjuX4b5yYQnEQHzd+CBcrcC6OVR2J1CN6mUy0oSxIPo= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= @@ -194,6 +202,7 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/main.go b/main.go index a563a05..031762e 100644 --- a/main.go +++ b/main.go @@ -56,7 +56,8 @@ var ( infoFs = flag.NewFlagSet("doctor", flag.ExitOnError) maintenanceFs = flag.NewFlagSet("maintenance", flag.ExitOnError) versionFs = flag.NewFlagSet("version", flag.ExitOnError) - templatePostCloneFs = flag.NewFlagSet("tmeplate-post-clone", flag.ExitOnError) + templatePostCloneFs = flag.NewFlagSet("template-post-clone", flag.ExitOnError) + assetsConfigFs = flag.NewFlagSet("assets-config", flag.ExitOnError) opts Opts logger *zap.Logger @@ -94,6 +95,7 @@ func run(args []string) error { {Name: "maintenance", Exec: doMaintenance, FlagSet: maintenanceFs, ShortHelp: "perform various maintenance tasks (write)", ShortUsage: "maintenance [opts] "}, {Name: "version", Exec: doVersion, FlagSet: versionFs, ShortHelp: "show version and build info", ShortUsage: "version"}, {Name: "template-post-clone", Exec: doTemplatePostClone, FlagSet: templatePostCloneFs, ShortHelp: "replace template", ShortUsage: "template-post-clone [opts] "}, + {Name: "assets-config", Exec: doAssetsConfig, FlagSet: assetsConfigFs, ShortHelp: "generate a configuration for assets", ShortUsage: "assets-config [opts] "}, }, Exec: func(ctx context.Context, args []string) error { return flag.ErrHelp