package config import ( "fmt" "strings" ) // Config is the complete set of inputs to the action, parsed from env. type Config struct { WorkingDirectory string AppName string Version string WailsVersion string ExtraBuildFlags string DeveloperIDCertBase64 string DeveloperIDCertPassword string NotarizationMethod string // "api-key" | "apple-id" | "auto" NotarizationAPIKeyBase64 string NotarizationAPIKeyID string NotarizationAPIIssuerID string NotarizationAppleID string NotarizationApplePassword string NotarizationTeamID string S3Bucket string S3Key string S3EndpointURL string S3Region string } // Load reads the action's INPUT_* environment variables. func Load(get func(string) string) *Config { c := &Config{ WorkingDirectory: getOr(get, "INPUT_WORKING_DIRECTORY", "."), AppName: get("INPUT_APP_NAME"), Version: get("INPUT_VERSION"), WailsVersion: get("INPUT_WAILS_VERSION"), ExtraBuildFlags: get("INPUT_EXTRA_BUILD_FLAGS"), DeveloperIDCertBase64: get("INPUT_DEVELOPER_ID_CERT_BASE64"), DeveloperIDCertPassword: get("INPUT_DEVELOPER_ID_CERT_PASSWORD"), NotarizationMethod: getOr(get, "INPUT_NOTARIZATION_METHOD", "auto"), NotarizationAPIKeyBase64: get("INPUT_NOTARIZATION_API_KEY_BASE64"), NotarizationAPIKeyID: get("INPUT_NOTARIZATION_API_KEY_ID"), NotarizationAPIIssuerID: get("INPUT_NOTARIZATION_API_ISSUER_ID"), NotarizationAppleID: get("INPUT_NOTARIZATION_APPLE_ID"), NotarizationApplePassword: get("INPUT_NOTARIZATION_APPLE_PASSWORD"), NotarizationTeamID: get("INPUT_NOTARIZATION_TEAM_ID"), S3Bucket: get("INPUT_S3_BUCKET"), S3Key: get("INPUT_S3_KEY"), S3EndpointURL: get("INPUT_S3_ENDPOINT_URL"), S3Region: getOr(get, "INPUT_S3_REGION", "us-east-1"), } return c } func getOr(get func(string) string, key, def string) string { if v := get(key); v != "" { return v } return def } // Validate checks structural rules. It does NOT touch the filesystem. func (c *Config) Validate() error { var missing []string if c.DeveloperIDCertBase64 == "" { missing = append(missing, "developer-id-cert-base64") } if c.DeveloperIDCertPassword == "" { missing = append(missing, "developer-id-cert-password") } if len(missing) > 0 { return fmt.Errorf("missing required input(s): %s", strings.Join(missing, ", ")) } apiFields := []struct{ name, value string }{ {"notarization-api-key-base64", c.NotarizationAPIKeyBase64}, {"notarization-api-key-id", c.NotarizationAPIKeyID}, {"notarization-api-issuer-id", c.NotarizationAPIIssuerID}, } appleFields := []struct{ name, value string }{ {"notarization-apple-id", c.NotarizationAppleID}, {"notarization-apple-password", c.NotarizationApplePassword}, {"notarization-team-id", c.NotarizationTeamID}, } apiFilled, apiMissing := groupStatus(apiFields) appleFilled, appleMissing := groupStatus(appleFields) switch c.NotarizationMethod { case "api-key": if !apiFilled { return fmt.Errorf("notarization-method=api-key requires: %s (missing: %s)", joinNames(apiFields), strings.Join(apiMissing, ", ")) } case "apple-id": if !appleFilled { return fmt.Errorf("notarization-method=apple-id requires: %s (missing: %s)", joinNames(appleFields), strings.Join(appleMissing, ", ")) } case "auto", "": switch { case apiFilled && appleFilled: return fmt.Errorf("notarization credentials are ambiguous: both api-key and apple-id groups are populated; set notarization-method explicitly") case !apiFilled && !appleFilled: return fmt.Errorf("no notarization credentials supplied: populate either the api-key group (%s) or the apple-id group (%s)", joinNames(apiFields), joinNames(appleFields)) } default: return fmt.Errorf("notarization-method must be one of api-key, apple-id, auto (got %q)", c.NotarizationMethod) } if c.S3Bucket != "" && c.S3Key == "" { return fmt.Errorf("s3-bucket is set but s3-key is empty") } return nil } // ResolvedNotarizationMethod returns "api-key" or "apple-id" once Validate has succeeded. func (c *Config) ResolvedNotarizationMethod() string { if c.NotarizationMethod == "api-key" || c.NotarizationMethod == "apple-id" { return c.NotarizationMethod } if c.NotarizationAPIKeyID != "" { return "api-key" } return "apple-id" } func groupStatus(fields []struct{ name, value string }) (filled bool, missing []string) { any := false for _, f := range fields { if f.value != "" { any = true } else { missing = append(missing, f.name) } } return any && len(missing) == 0, missing } func joinNames(fields []struct{ name, value string }) string { names := make([]string, len(fields)) for i, f := range fields { names[i] = f.name } return strings.Join(names, ", ") }