Skip to content

Commit 1b5cdc2

Browse files
fix release flow regressions
1 parent 02f2be4 commit 1b5cdc2

7 files changed

Lines changed: 504 additions & 63 deletions

File tree

crates/adapters/src/generic.rs

Lines changed: 58 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,22 @@ impl Adapter for GenericAdapter {
161161
Bump::Patch
162162
}
163163

164-
fn is_published(&self, _pkg: &Pkg, _version: &str) -> Result<bool> {
165-
// No registry API to query; rely on the dated changelog / tag for idempotency upstream.
166-
Ok(false)
164+
fn is_published(&self, pkg: &Pkg, version: &str) -> Result<bool> {
165+
// No generic registry API exists, so use the tag created after a successful publish as
166+
// the resumability marker.
167+
let tag = format!("{}@{}", pkg.name, version);
168+
let out = Command::new("git")
169+
.args(["tag", "--list", &tag])
170+
.current_dir(&self.root)
171+
.output()
172+
.with_context(|| format!("checking for release tag: {tag}"))?;
173+
if !out.status.success() {
174+
bail!(
175+
"`git tag --list {tag}` failed:\n{}",
176+
String::from_utf8_lossy(&out.stderr)
177+
);
178+
}
179+
Ok(!String::from_utf8_lossy(&out.stdout).trim().is_empty())
167180
}
168181

169182
fn publish(&self, pkg: &Pkg, _staged_assets: Option<&Path>) -> Result<()> {
@@ -253,4 +266,46 @@ mod tests {
253266
let p = a.discover_packages().unwrap().pop().unwrap();
254267
assert!(a.publish(&p, None).is_err());
255268
}
269+
270+
#[test]
271+
fn is_published_uses_existing_release_tag() {
272+
let tmp = tempfile::tempdir().unwrap();
273+
std::fs::write(tmp.path().join("deno.json"), "{\"version\":\"1.0.0\"}").unwrap();
274+
std::process::Command::new("git")
275+
.args(["init", "-q"])
276+
.current_dir(tmp.path())
277+
.status()
278+
.unwrap();
279+
std::process::Command::new("git")
280+
.args(["config", "user.email", "t@t"])
281+
.current_dir(tmp.path())
282+
.status()
283+
.unwrap();
284+
std::process::Command::new("git")
285+
.args(["config", "user.name", "Test"])
286+
.current_dir(tmp.path())
287+
.status()
288+
.unwrap();
289+
std::process::Command::new("git")
290+
.args(["add", "-A"])
291+
.current_dir(tmp.path())
292+
.status()
293+
.unwrap();
294+
std::process::Command::new("git")
295+
.args(["commit", "-q", "-m", "init"])
296+
.current_dir(tmp.path())
297+
.status()
298+
.unwrap();
299+
300+
let a = GenericAdapter::new(tmp.path(), vec![pkg("lib", "deno.json", Some("true"))]);
301+
let p = a.discover_packages().unwrap().pop().unwrap();
302+
assert!(!a.is_published(&p, "1.0.0").unwrap());
303+
304+
std::process::Command::new("git")
305+
.args(["tag", "lib@1.0.0"])
306+
.current_dir(tmp.path())
307+
.status()
308+
.unwrap();
309+
assert!(a.is_published(&p, "1.0.0").unwrap());
310+
}
256311
}

crates/cli/src/main.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,14 @@ fn main() -> Result<()> {
170170
first_release,
171171
skip_pr: false,
172172
};
173-
for eco in &config.adapters {
174-
let adapter = factory.make(*eco);
175-
version::run(adapter.as_ref(), &root, &opts, &config)?;
176-
}
173+
let adapters: Vec<Box<dyn Adapter>> = config
174+
.adapters
175+
.iter()
176+
.map(|eco| factory.make(*eco))
177+
.collect();
178+
let adapter_refs: Vec<&dyn Adapter> =
179+
adapters.iter().map(|adapter| adapter.as_ref()).collect();
180+
version::run_many(&adapter_refs, &root, &opts, &config)?;
177181
Ok(())
178182
}
179183

crates/cli/tests/e2e.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use anyhow::Result;
1515

1616
use otf_release_adapters::npm::{CommandOutput, CommandRunner, NpmAdapter};
1717
use otf_release_core::adapter::{Bump, Pkg};
18-
use otf_release_core::config::{Hooks, ReleaseConfig};
18+
use otf_release_core::config::ReleaseConfig;
1919
use otf_release_core::forge::Forge;
2020
use otf_release_core::git::GitRepo;
2121
use otf_release_core::prompt::Prompt;

crates/cli/tests/version_flow.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use otf_release_core::forge::Forge;
1616
use otf_release_core::git::GitRepo;
1717
use otf_release_core::prompt::Prompt;
1818
use otf_release_core::version::{orchestrate, VersionOptions};
19-
use otf_release_core::config::{Hooks, ReleaseConfig};
19+
use otf_release_core::config::ReleaseConfig;
2020

2121
/// Every `npm` invocation "succeeds" (the version flow only calls `update_lockfile`).
2222
struct OkRunner;

crates/core/src/init.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,7 @@ pub fn render_workflow(config: &ReleaseConfig) -> String {
302302
s.push_str("\npermissions:\n contents: write # create tags and GitHub Releases\n");
303303
}
304304
s.push_str("\njobs:\n");
305-
let version_cmd = version_read_cmd(config.packages.first());
305+
let version_cmd = version_read_cmd(config);
306306
render_check_release_job(&mut s, &version_cmd);
307307

308308
// Build jobs only for packages that actually declare a build command.
@@ -346,8 +346,8 @@ pub fn render_workflow(config: &ReleaseConfig) -> String {
346346

347347
/// The shell snippet that reads the release version for the GitHub Release tag, based on the
348348
/// first build-only package: a manifest field (generic), `package.json` (npm), or `Cargo.toml`.
349-
fn version_read_cmd(entry: Option<&PackageEntry>) -> String {
350-
match entry {
349+
fn version_read_cmd(config: &ReleaseConfig) -> String {
350+
match config.packages.first() {
351351
Some(e) if e.adapter == Ecosystem::Generic => {
352352
let manifest = e.manifest.as_deref().unwrap_or("deno.json");
353353
let field = e.version_field.as_deref().unwrap_or("version");
@@ -364,9 +364,18 @@ fn version_read_cmd(entry: Option<&PackageEntry>) -> String {
364364
Some(e) if e.adapter == Ecosystem::Npm => {
365365
"node -p \"require('./package.json').version\"".to_string()
366366
}
367-
_ => {
367+
Some(_) => {
368368
"cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version'".to_string()
369369
}
370+
None if config.adapters.contains(&Ecosystem::Npm) => {
371+
"node -p \"require('./package.json').version\"".to_string()
372+
}
373+
None if config.adapters.contains(&Ecosystem::Cargo) => {
374+
"cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version'".to_string()
375+
}
376+
_ => {
377+
"echo 0.0.0 # edit me: where the version lives".to_string()
378+
}
370379
}
371380
}
372381

@@ -1066,6 +1075,8 @@ mod tests {
10661075
let out = render_workflow(&config);
10671076
assert!(out.contains(" publish:\n"));
10681077
assert!(out.contains(" - uses: actions/setup-node@v4\n"));
1078+
assert!(out.contains(" version=\"$(node -p \"require('./package.json').version\")\""));
1079+
assert!(!out.contains("version=\"$(cargo metadata"));
10691080
assert!(out.contains(" run: otf-release publish\n"));
10701081
// No build steps, so no needs and no artifact download.
10711082
assert!(out.contains("needs: [check-release]"));

crates/core/src/snapshot.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ use crate::adapter::Adapter;
55
use crate::config::ReleaseConfig;
66
use crate::publish;
77
use crate::graph::Graph;
8-
use crate::hooks;
98
use crate::git;
109

1110
pub fn run(adapter: &dyn Adapter, root: &Path, config: &ReleaseConfig) -> Result<()> {

0 commit comments

Comments
 (0)