func GenerateManifest(ctx context.Context, options GenerateManifestOptions) (*api.Manifest, error) {
	manifest := &api.Manifest{}
	if options.BaseDir == "" {
		return nil, xerrors.New("must specify BaseDir")
	}
	basedir := options.BaseDir
	if !strings.HasSuffix(basedir, "/") {
		basedir += "/"
	}
	if err := filepath.Walk(basedir, func(p string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !strings.HasPrefix(p, basedir) {
			return xerrors.Errorf("expected path %q to have prefix %q", p, basedir)
		}
		if !strings.HasPrefix(p, filepath.Join(basedir, options.Prefix)) {
			return nil
		}
		if !info.IsDir() {
			relativePath := strings.TrimPrefix(p, basedir)
			sha256, err := hash.SHA256ForFile(p)
			if err != nil {
				return xerrors.Errorf("error hashing file %q: %w", p, err)
			}
			manifest.Files = append(manifest.Files, api.File{
				Name:   relativePath,
				SHA256: sha256,
			})
		}
		return nil
	}); err != nil {
		return nil, xerrors.Errorf("error walking path %q: %w", options.BaseDir, err)
	}
	return manifest, nil
}
GenerateManifest generates a manifest containing the files in options.BaseDir
package promobot
import (
	"context"
	"os"
	"path/filepath"
	"strings"
	"golang.org/x/xerrors"
	api "sigs.k8s.io/promo-tools/v3/api/files"
	"sigs.k8s.io/release-utils/hash"
)
type GenerateManifestOptions struct {
	BaseDir string
	Prefix string
}
func (o *GenerateManifestOptions) PopulateDefaults() {
}