diff options
Diffstat (limited to 'xtask')
-rw-r--r-- | xtask/src/dist.rs | 34 | ||||
-rw-r--r-- | xtask/src/flags.rs | 9 | ||||
-rw-r--r-- | xtask/src/main.rs | 8 | ||||
-rw-r--r-- | xtask/src/release.rs | 50 | ||||
-rw-r--r-- | xtask/src/release/changelog.rs | 159 | ||||
-rw-r--r-- | xtask/src/tidy.rs | 2 |
6 files changed, 197 insertions, 65 deletions
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index f2503f807..12a7fea1e 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
@@ -7,26 +7,31 @@ use std::{ | |||
7 | 7 | ||
8 | use anyhow::Result; | 8 | use anyhow::Result; |
9 | use flate2::{write::GzEncoder, Compression}; | 9 | use flate2::{write::GzEncoder, Compression}; |
10 | use xshell::{cmd, cp, mkdir_p, pushd, read_file, rm_rf, write_file}; | 10 | use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file}; |
11 | 11 | ||
12 | use crate::{date_iso, project_root}; | 12 | use crate::{date_iso, flags, project_root}; |
13 | 13 | ||
14 | pub(crate) struct DistCmd { | 14 | impl flags::Dist { |
15 | pub(crate) nightly: bool, | ||
16 | pub(crate) client_version: Option<String>, | ||
17 | } | ||
18 | |||
19 | impl DistCmd { | ||
20 | pub(crate) fn run(self) -> Result<()> { | 15 | pub(crate) fn run(self) -> Result<()> { |
16 | let stable = | ||
17 | std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release"; | ||
18 | |||
21 | let dist = project_root().join("dist"); | 19 | let dist = project_root().join("dist"); |
22 | rm_rf(&dist)?; | 20 | rm_rf(&dist)?; |
23 | mkdir_p(&dist)?; | 21 | mkdir_p(&dist)?; |
24 | 22 | ||
25 | if let Some(version) = self.client_version { | 23 | if let Some(patch_version) = self.client_patch_version { |
26 | let release_tag = if self.nightly { "nightly".to_string() } else { date_iso()? }; | 24 | let version = if stable { |
25 | format!("0.2.{}", patch_version) | ||
26 | } else { | ||
27 | // A hack to make VS Code prefer nightly over stable. | ||
28 | format!("0.3.{}", patch_version) | ||
29 | }; | ||
30 | let release_tag = if stable { date_iso()? } else { "nightly".to_string() }; | ||
27 | dist_client(&version, &release_tag)?; | 31 | dist_client(&version, &release_tag)?; |
28 | } | 32 | } |
29 | dist_server()?; | 33 | let release_channel = if stable { "stable" } else { "nightly" }; |
34 | dist_server(release_channel)?; | ||
30 | Ok(()) | 35 | Ok(()) |
31 | } | 36 | } |
32 | } | 37 | } |
@@ -39,7 +44,9 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> { | |||
39 | 44 | ||
40 | patch | 45 | patch |
41 | .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version)) | 46 | .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version)) |
42 | .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag)); | 47 | .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag)) |
48 | .replace(r#""$generated-start": false,"#, "") | ||
49 | .replace(",\n \"$generated-end\": false", ""); | ||
43 | 50 | ||
44 | if nightly { | 51 | if nightly { |
45 | patch.replace( | 52 | patch.replace( |
@@ -57,7 +64,8 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> { | |||
57 | Ok(()) | 64 | Ok(()) |
58 | } | 65 | } |
59 | 66 | ||
60 | fn dist_server() -> Result<()> { | 67 | fn dist_server(release_channel: &str) -> Result<()> { |
68 | let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel); | ||
61 | let target = get_target(); | 69 | let target = get_target(); |
62 | if target.contains("-linux-gnu") || target.contains("-linux-musl") { | 70 | if target.contains("-linux-gnu") || target.contains("-linux-musl") { |
63 | env::set_var("CC", "clang"); | 71 | env::set_var("CC", "clang"); |
diff --git a/xtask/src/flags.rs b/xtask/src/flags.rs index 34e447c2f..69b3cb9c1 100644 --- a/xtask/src/flags.rs +++ b/xtask/src/flags.rs | |||
@@ -36,8 +36,7 @@ xflags::xflags! { | |||
36 | optional --dry-run | 36 | optional --dry-run |
37 | } | 37 | } |
38 | cmd dist { | 38 | cmd dist { |
39 | optional --nightly | 39 | optional --client-patch-version version: String |
40 | optional --client version: String | ||
41 | } | 40 | } |
42 | cmd metrics { | 41 | cmd metrics { |
43 | optional --dry-run | 42 | optional --dry-run |
@@ -84,9 +83,6 @@ pub struct Install { | |||
84 | } | 83 | } |
85 | 84 | ||
86 | #[derive(Debug)] | 85 | #[derive(Debug)] |
87 | pub struct Lint; | ||
88 | |||
89 | #[derive(Debug)] | ||
90 | pub struct FuzzTests; | 86 | pub struct FuzzTests; |
91 | 87 | ||
92 | #[derive(Debug)] | 88 | #[derive(Debug)] |
@@ -101,8 +97,7 @@ pub struct Promote { | |||
101 | 97 | ||
102 | #[derive(Debug)] | 98 | #[derive(Debug)] |
103 | pub struct Dist { | 99 | pub struct Dist { |
104 | pub nightly: bool, | 100 | pub client_patch_version: Option<String>, |
105 | pub client: Option<String>, | ||
106 | } | 101 | } |
107 | 102 | ||
108 | #[derive(Debug)] | 103 | #[derive(Debug)] |
diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 0dbbde275..d0bef7b7a 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs | |||
@@ -27,8 +27,6 @@ use std::{ | |||
27 | use walkdir::{DirEntry, WalkDir}; | 27 | use walkdir::{DirEntry, WalkDir}; |
28 | use xshell::{cmd, cp, pushd, pushenv}; | 28 | use xshell::{cmd, cp, pushd, pushenv}; |
29 | 29 | ||
30 | use crate::dist::DistCmd; | ||
31 | |||
32 | fn main() -> Result<()> { | 30 | fn main() -> Result<()> { |
33 | let _d = pushd(project_root())?; | 31 | let _d = pushd(project_root())?; |
34 | 32 | ||
@@ -42,9 +40,7 @@ fn main() -> Result<()> { | |||
42 | flags::XtaskCmd::FuzzTests(_) => run_fuzzer(), | 40 | flags::XtaskCmd::FuzzTests(_) => run_fuzzer(), |
43 | flags::XtaskCmd::Release(cmd) => cmd.run(), | 41 | flags::XtaskCmd::Release(cmd) => cmd.run(), |
44 | flags::XtaskCmd::Promote(cmd) => cmd.run(), | 42 | flags::XtaskCmd::Promote(cmd) => cmd.run(), |
45 | flags::XtaskCmd::Dist(flags) => { | 43 | flags::XtaskCmd::Dist(cmd) => cmd.run(), |
46 | DistCmd { nightly: flags.nightly, client_version: flags.client }.run() | ||
47 | } | ||
48 | flags::XtaskCmd::Metrics(cmd) => cmd.run(), | 44 | flags::XtaskCmd::Metrics(cmd) => cmd.run(), |
49 | flags::XtaskCmd::Bb(cmd) => { | 45 | flags::XtaskCmd::Bb(cmd) => { |
50 | { | 46 | { |
@@ -110,7 +106,7 @@ fn run_fuzzer() -> Result<()> { | |||
110 | } | 106 | } |
111 | 107 | ||
112 | fn date_iso() -> Result<String> { | 108 | fn date_iso() -> Result<String> { |
113 | let res = cmd!("date --iso --utc").read()?; | 109 | let res = cmd!("date -u +%Y-%m-%d").read()?; |
114 | Ok(res) | 110 | Ok(res) |
115 | } | 111 | } |
116 | 112 | ||
diff --git a/xtask/src/release.rs b/xtask/src/release.rs index dde5d14ee..452f351d0 100644 --- a/xtask/src/release.rs +++ b/xtask/src/release.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use std::fmt::Write; | 1 | mod changelog; |
2 | 2 | ||
3 | use xshell::{cmd, cp, pushd, read_dir, write_file}; | 3 | use xshell::{cmd, cp, pushd, read_dir, write_file}; |
4 | 4 | ||
@@ -10,7 +10,16 @@ impl flags::Release { | |||
10 | cmd!("git switch release").run()?; | 10 | cmd!("git switch release").run()?; |
11 | cmd!("git fetch upstream --tags --force").run()?; | 11 | cmd!("git fetch upstream --tags --force").run()?; |
12 | cmd!("git reset --hard tags/nightly").run()?; | 12 | cmd!("git reset --hard tags/nightly").run()?; |
13 | cmd!("git push").run()?; | 13 | // The `release` branch sometimes has a couple of cherry-picked |
14 | // commits for patch releases. If that's the case, just overwrite | ||
15 | // it. As we are setting `release` branch to an up-to-date `nightly` | ||
16 | // tag, this shouldn't be problematic in general. | ||
17 | // | ||
18 | // Note that, as we tag releases, we don't worry about "losing" | ||
19 | // commits -- they'll be kept alive by the tag. More generally, we | ||
20 | // don't care about historic releases all that much, it's fine even | ||
21 | // to delete old tags. | ||
22 | cmd!("git push --force").run()?; | ||
14 | } | 23 | } |
15 | codegen::docs()?; | 24 | codegen::docs()?; |
16 | 25 | ||
@@ -38,42 +47,7 @@ impl flags::Release { | |||
38 | let tags = cmd!("git tag --list").read()?; | 47 | let tags = cmd!("git tag --list").read()?; |
39 | let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap(); | 48 | let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap(); |
40 | 49 | ||
41 | let git_log = cmd!("git log {prev_tag}..HEAD --merges --reverse").read()?; | 50 | let contents = changelog::get_changelog(changelog_n, &commit, prev_tag, &today)?; |
42 | let mut git_log_summary = String::new(); | ||
43 | for line in git_log.lines() { | ||
44 | let line = line.trim_start(); | ||
45 | if let Some(p) = line.find(':') { | ||
46 | if let Ok(pr) = line[..p].parse::<u32>() { | ||
47 | writeln!(git_log_summary, "* pr:{}[]{}", pr, &line[p + 1..]).unwrap(); | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | |||
52 | let contents = format!( | ||
53 | "\ | ||
54 | = Changelog #{} | ||
55 | :sectanchors: | ||
56 | :page-layout: post | ||
57 | |||
58 | Commit: commit:{}[] + | ||
59 | Release: release:{}[] | ||
60 | |||
61 | == Sponsors | ||
62 | |||
63 | **Become a sponsor:** On https://opencollective.com/rust-analyzer/[OpenCollective] or | ||
64 | https://github.com/sponsors/rust-analyzer[GitHub Sponsors]. | ||
65 | |||
66 | == New Features | ||
67 | |||
68 | {} | ||
69 | |||
70 | == Fixes | ||
71 | |||
72 | == Internal Improvements | ||
73 | ", | ||
74 | changelog_n, commit, today, git_log_summary | ||
75 | ); | ||
76 | |||
77 | let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n)); | 51 | let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n)); |
78 | write_file(&path, &contents)?; | 52 | write_file(&path, &contents)?; |
79 | 53 | ||
diff --git a/xtask/src/release/changelog.rs b/xtask/src/release/changelog.rs new file mode 100644 index 000000000..ffcae2cf7 --- /dev/null +++ b/xtask/src/release/changelog.rs | |||
@@ -0,0 +1,159 @@ | |||
1 | use std::fmt::Write; | ||
2 | use std::{env, iter}; | ||
3 | |||
4 | use anyhow::{bail, Result}; | ||
5 | use xshell::cmd; | ||
6 | |||
7 | pub(crate) fn get_changelog( | ||
8 | changelog_n: usize, | ||
9 | commit: &str, | ||
10 | prev_tag: &str, | ||
11 | today: &str, | ||
12 | ) -> Result<String> { | ||
13 | let git_log = cmd!("git log {prev_tag}..HEAD --merges --reverse").read()?; | ||
14 | let mut features = String::new(); | ||
15 | let mut fixes = String::new(); | ||
16 | let mut internal = String::new(); | ||
17 | let mut others = String::new(); | ||
18 | for line in git_log.lines() { | ||
19 | let line = line.trim_start(); | ||
20 | if let Some(p) = line.find(':') { | ||
21 | let pr = &line[..p]; | ||
22 | if let Ok(pr_num) = pr.parse::<u32>() { | ||
23 | let accept = "Accept: application/vnd.github.v3+json"; | ||
24 | let token = match env::var("GITHUB_TOKEN") { | ||
25 | Ok(token) => token, | ||
26 | Err(_) => bail!("Please obtain a personal access token from https://github.com/settings/tokens and set the `GITHUB_TOKEN` environment variable."), | ||
27 | }; | ||
28 | let authorization = format!("Authorization: token {}", token); | ||
29 | let pr_url = "https://api.github.com/repos/rust-analyzer/rust-analyzer/issues"; | ||
30 | |||
31 | // we don't use an HTTPS client or JSON parser to keep the build times low | ||
32 | let pr_json = | ||
33 | cmd!("curl -s -H {accept} -H {authorization} {pr_url}/{pr}").read()?; | ||
34 | let pr_title = cmd!("jq .title").stdin(&pr_json).read()?; | ||
35 | let pr_title = unescape(&pr_title[1..pr_title.len() - 1]); | ||
36 | let pr_comment = cmd!("jq .body").stdin(pr_json).read()?; | ||
37 | |||
38 | let comments_json = | ||
39 | cmd!("curl -s -H {accept} -H {authorization} {pr_url}/{pr}/comments").read()?; | ||
40 | let pr_comments = cmd!("jq .[].body").stdin(comments_json).read()?; | ||
41 | |||
42 | let l = iter::once(pr_comment.as_str()) | ||
43 | .chain(pr_comments.lines()) | ||
44 | .rev() | ||
45 | .find_map(|it| { | ||
46 | let it = unescape(&it[1..it.len() - 1]); | ||
47 | it.lines().find_map(parse_changelog_line) | ||
48 | }) | ||
49 | .into_iter() | ||
50 | .next() | ||
51 | .unwrap_or_else(|| parse_title_line(&pr_title)); | ||
52 | let s = match l.kind { | ||
53 | PrKind::Feature => &mut features, | ||
54 | PrKind::Fix => &mut fixes, | ||
55 | PrKind::Internal => &mut internal, | ||
56 | PrKind::Other => &mut others, | ||
57 | PrKind::Skip => continue, | ||
58 | }; | ||
59 | writeln!(s, "* pr:{}[] {}", pr_num, l.message.as_deref().unwrap_or(&pr_title)) | ||
60 | .unwrap(); | ||
61 | } | ||
62 | } | ||
63 | } | ||
64 | |||
65 | let contents = format!( | ||
66 | "\ | ||
67 | = Changelog #{} | ||
68 | :sectanchors: | ||
69 | :page-layout: post | ||
70 | |||
71 | Commit: commit:{}[] + | ||
72 | Release: release:{}[] | ||
73 | |||
74 | == Sponsors | ||
75 | |||
76 | **Become a sponsor:** On https://opencollective.com/rust-analyzer/[OpenCollective] or | ||
77 | https://github.com/sponsors/rust-analyzer[GitHub Sponsors]. | ||
78 | |||
79 | == New Features | ||
80 | |||
81 | {} | ||
82 | |||
83 | == Fixes | ||
84 | |||
85 | {} | ||
86 | |||
87 | == Internal Improvements | ||
88 | |||
89 | {} | ||
90 | |||
91 | == Others | ||
92 | |||
93 | {} | ||
94 | ", | ||
95 | changelog_n, commit, today, features, fixes, internal, others | ||
96 | ); | ||
97 | Ok(contents) | ||
98 | } | ||
99 | |||
100 | #[derive(Clone, Copy)] | ||
101 | enum PrKind { | ||
102 | Feature, | ||
103 | Fix, | ||
104 | Internal, | ||
105 | Other, | ||
106 | Skip, | ||
107 | } | ||
108 | |||
109 | struct PrInfo { | ||
110 | message: Option<String>, | ||
111 | kind: PrKind, | ||
112 | } | ||
113 | |||
114 | fn unescape(s: &str) -> String { | ||
115 | s.replace(r#"\""#, "").replace(r#"\n"#, "\n").replace(r#"\r"#, "") | ||
116 | } | ||
117 | |||
118 | fn parse_changelog_line(s: &str) -> Option<PrInfo> { | ||
119 | let parts = s.splitn(3, ' ').collect::<Vec<_>>(); | ||
120 | if parts.len() < 2 || parts[0] != "changelog" { | ||
121 | return None; | ||
122 | } | ||
123 | let message = parts.get(2).map(|it| it.to_string()); | ||
124 | let kind = match parts[1].trim_end_matches(':') { | ||
125 | "feature" => PrKind::Feature, | ||
126 | "fix" => PrKind::Fix, | ||
127 | "internal" => PrKind::Internal, | ||
128 | "skip" => PrKind::Skip, | ||
129 | _ => { | ||
130 | let kind = PrKind::Other; | ||
131 | let message = format!("{} {}", parts[1], message.unwrap_or_default()); | ||
132 | return Some(PrInfo { kind, message: Some(message) }); | ||
133 | } | ||
134 | }; | ||
135 | let res = PrInfo { kind, message }; | ||
136 | Some(res) | ||
137 | } | ||
138 | |||
139 | fn parse_title_line(s: &str) -> PrInfo { | ||
140 | let lower = s.to_ascii_lowercase(); | ||
141 | const PREFIXES: [(&str, PrKind); 5] = [ | ||
142 | ("feat: ", PrKind::Feature), | ||
143 | ("feature: ", PrKind::Feature), | ||
144 | ("fix: ", PrKind::Fix), | ||
145 | ("internal: ", PrKind::Internal), | ||
146 | ("minor: ", PrKind::Skip), | ||
147 | ]; | ||
148 | |||
149 | for &(prefix, kind) in &PREFIXES { | ||
150 | if lower.starts_with(prefix) { | ||
151 | let message = match &kind { | ||
152 | PrKind::Skip => None, | ||
153 | _ => Some(s[prefix.len()..].to_string()), | ||
154 | }; | ||
155 | return PrInfo { kind, message }; | ||
156 | } | ||
157 | } | ||
158 | PrInfo { kind: PrKind::Other, message: Some(s.to_string()) } | ||
159 | } | ||
diff --git a/xtask/src/tidy.rs b/xtask/src/tidy.rs index 50d9efccd..c3c785eff 100644 --- a/xtask/src/tidy.rs +++ b/xtask/src/tidy.rs | |||
@@ -224,7 +224,7 @@ Apache-2.0 OR BSL-1.0 | |||
224 | Apache-2.0 OR MIT | 224 | Apache-2.0 OR MIT |
225 | Apache-2.0/MIT | 225 | Apache-2.0/MIT |
226 | BSD-3-Clause | 226 | BSD-3-Clause |
227 | CC0-1.0 | 227 | CC0-1.0 OR Artistic-2.0 |
228 | ISC | 228 | ISC |
229 | MIT | 229 | MIT |
230 | MIT / Apache-2.0 | 230 | MIT / Apache-2.0 |