cargo_readme/config/
badges.rs

1use std::collections::BTreeMap;
2
3// https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata
4
5use percent_encoding as pe;
6
7const BADGE_BRANCH_DEFAULT: &str = "master";
8const BADGE_SERVICE_DEFAULT: &str = "github";
9const BADGE_WORKFLOW_DEFAULT: &str = "main";
10
11type Attrs = BTreeMap<String, String>;
12
13pub fn appveyor(attrs: Attrs) -> String {
14    let repo = &attrs["repository"];
15    let branch = attrs
16        .get("branch")
17        .map(|i| i.as_ref())
18        .unwrap_or(BADGE_BRANCH_DEFAULT);
19    let service = attrs
20        .get("service")
21        .map(|i| i.as_ref())
22        .unwrap_or(BADGE_SERVICE_DEFAULT);
23
24    format!(
25        "[![Build Status](https://ci.appveyor.com/api/projects/status/{service}/{repo}?branch={branch}&svg=true)]\
26        (https://ci.appveyor.com/project/{repo}/branch/{branch})",
27        repo=repo, branch=branch, service=service
28    )
29}
30
31pub fn circle_ci(attrs: Attrs) -> String {
32    let repo = &attrs["repository"];
33    let branch = attrs
34        .get("branch")
35        .map(|i| i.as_ref())
36        .unwrap_or(BADGE_BRANCH_DEFAULT);
37    let service = badge_service_short_name(
38        attrs
39            .get("service")
40            .map(|i| i.as_ref())
41            .unwrap_or(BADGE_SERVICE_DEFAULT),
42    );
43
44    format!(
45        "[![Build Status](https://circleci.com/{service}/{repo}/tree/{branch}.svg?style=shield)]\
46         (https://circleci.com/{service}/{repo}/tree/{branch})",
47        repo = repo,
48        service = service,
49        branch = percent_encode(branch)
50    )
51}
52
53pub fn gitlab(attrs: Attrs) -> String {
54    let repo = &attrs["repository"];
55    let branch = attrs
56        .get("branch")
57        .map(|i| i.as_ref())
58        .unwrap_or(BADGE_BRANCH_DEFAULT);
59
60    format!(
61        "[![Build Status](https://gitlab.com/{repo}/badges/{branch}/pipeline.svg)]\
62         (https://gitlab.com/{repo}/commits/master)",
63        repo = repo,
64        branch = percent_encode(branch)
65    )
66}
67
68pub fn travis_ci(attrs: Attrs) -> String {
69    let repo = &attrs["repository"];
70    let branch = attrs
71        .get("branch")
72        .map(|i| i.as_ref())
73        .unwrap_or(BADGE_BRANCH_DEFAULT);
74
75    format!(
76        "[![Build Status](https://travis-ci.org/{repo}.svg?branch={branch})]\
77         (https://travis-ci.org/{repo})",
78        repo = repo,
79        branch = percent_encode(branch)
80    )
81}
82
83pub fn github(attrs: Attrs) -> String {
84    let repo = &attrs["repository"];
85    let workflow = attrs
86        .get("workflow")
87        .map(|i| i.as_ref())
88        .unwrap_or(BADGE_WORKFLOW_DEFAULT);
89
90    format!(
91        "[![Workflow Status](https://github.com/{repo}/workflows/{workflow}/badge.svg)]\
92         (https://github.com/{repo}/actions?query=workflow%3A%22{workflow_plus}%22)",
93        repo = repo,
94        workflow = percent_encode(workflow),
95        workflow_plus = percent_encode(&str::replace(workflow, " ", "+"))
96    )
97}
98
99pub fn codecov(attrs: Attrs) -> String {
100    let repo = &attrs["repository"];
101    let branch = attrs
102        .get("branch")
103        .map(|i| i.as_ref())
104        .unwrap_or(BADGE_BRANCH_DEFAULT);
105    let service = badge_service_short_name(
106        attrs
107            .get("service")
108            .map(|i| i.as_ref())
109            .unwrap_or(BADGE_SERVICE_DEFAULT),
110    );
111
112    format!(
113        "[![Coverage Status](https://codecov.io/{service}/{repo}/branch/{branch}/graph/badge.svg)]\
114         (https://codecov.io/{service}/{repo})",
115        repo = repo,
116        branch = percent_encode(branch),
117        service = service
118    )
119}
120
121pub fn coveralls(attrs: Attrs) -> String {
122    let repo = &attrs["repository"];
123    let branch = attrs
124        .get("branch")
125        .map(|i| i.as_ref())
126        .unwrap_or(BADGE_BRANCH_DEFAULT);
127    let service = attrs
128        .get("service")
129        .map(|i| i.as_ref())
130        .unwrap_or(BADGE_SERVICE_DEFAULT);
131
132    format!(
133        "[![Coverage Status](https://coveralls.io/repos/{service}/{repo}/badge.svg?branch=branch)]\
134         (https://coveralls.io/{service}/{repo}?branch={branch})",
135        repo = repo,
136        branch = percent_encode(branch),
137        service = service
138    )
139}
140
141pub fn is_it_maintained_issue_resolution(attrs: Attrs) -> String {
142    let repo = &attrs["repository"];
143    format!(
144        "[![Average time to resolve an issue](https://isitmaintained.com/badge/resolution/{repo}.svg)]\
145        (https://isitmaintained.com/project/{repo} \"Average time to resolve an issue\")",
146        repo=repo
147    )
148}
149
150pub fn is_it_maintained_open_issues(attrs: Attrs) -> String {
151    let repo = &attrs["repository"];
152    format!(
153        "[![Percentage of issues still open](https://isitmaintained.com/badge/open/{repo}.svg)]\
154         (https://isitmaintained.com/project/{repo} \"Percentage of issues still open\")",
155        repo = repo
156    )
157}
158
159pub fn maintenance(attrs: Attrs) -> String {
160    let status = &attrs["status"];
161
162    // https://github.com/rust-lang/crates.io/blob/5a08887d4b531e034d01386d3e5997514f3c8ee5/src/models/badge.rs#L82
163    let status_with_color = match status.as_ref() {
164        "actively-developed" => "activly--developed-brightgreen",
165        "passively-maintained" => "passively--maintained-yellowgreen",
166        "as-is" => "as--is-yellow",
167        "none" => "maintenance-none-lightgrey", // color is a guess
168        "experimental" => "experimental-blue",
169        "looking-for-maintainer" => "looking--for--maintainer-darkblue", // color is a guess
170        "deprecated" => "deprecated-red",
171        _ => "unknow-black",
172    };
173
174    //example https://img.shields.io/badge/maintenance-experimental-blue.svg
175    format!(
176        "![Maintenance](https://img.shields.io/badge/maintenance-{status}.svg)",
177        status = status_with_color
178    )
179}
180
181fn percent_encode(input: &str) -> pe::PercentEncode {
182    pe::utf8_percent_encode(input, pe::NON_ALPHANUMERIC)
183}
184
185fn badge_service_short_name(service: &str) -> &'static str {
186    match service {
187        "github" => "gh",
188        "bitbucket" => "bb",
189        "gitlab" => "gl",
190        _ => "gh",
191    }
192}