Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .github/dotslash-argument-comment-lint-config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"outputs": {
"argument-comment-lint": {
"platforms": {
"macos-aarch64": {
"regex": "^argument-comment-lint-aarch64-apple-darwin\\.tar\\.gz$",
"path": "argument-comment-lint/bin/argument-comment-lint"
},
"linux-x86_64": {
"regex": "^argument-comment-lint-x86_64-unknown-linux-gnu\\.tar\\.gz$",
"path": "argument-comment-lint/bin/argument-comment-lint"
},
"linux-aarch64": {
"regex": "^argument-comment-lint-aarch64-unknown-linux-gnu\\.tar\\.gz$",
"path": "argument-comment-lint/bin/argument-comment-lint"
},
"windows-x86_64": {
"regex": "^argument-comment-lint-x86_64-pc-windows-msvc\\.zip$",
"path": "argument-comment-lint/bin/argument-comment-lint.exe"
}
}
}
}
}
103 changes: 103 additions & 0 deletions .github/workflows/rust-release-argument-comment-lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
name: rust-release-argument-comment-lint

on:
workflow_call:
inputs:
publish:
required: true
type: boolean

jobs:
skip:
if: ${{ !inputs.publish }}
runs-on: ubuntu-latest
steps:
- run: echo "Skipping argument-comment-lint release assets for prerelease tag"

build:
if: ${{ inputs.publish }}
name: Build - ${{ matrix.runner }} - ${{ matrix.target }}
runs-on: ${{ matrix.runs_on || matrix.runner }}
timeout-minutes: 60

strategy:
fail-fast: false
matrix:
include:
- runner: macos-15-xlarge
target: aarch64-apple-darwin
archive_name: argument-comment-lint-aarch64-apple-darwin.tar.gz
lib_name: libargument_comment_lint@nightly-2025-09-18-aarch64-apple-darwin.dylib
runner_binary: argument-comment-lint
cargo_dylint_binary: cargo-dylint
- runner: ubuntu-24.04
target: x86_64-unknown-linux-gnu
archive_name: argument-comment-lint-x86_64-unknown-linux-gnu.tar.gz
lib_name: libargument_comment_lint@nightly-2025-09-18-x86_64-unknown-linux-gnu.so
runner_binary: argument-comment-lint
Comment on lines +33 to +37
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Publish Linux artifacts with portable release targets

These release assets are built as *-unknown-linux-gnu on Ubuntu 24.04 runners, and the archive also bundles a host-built cargo-dylint. On older-but-still-supported Linux environments (for example Ubuntu 20.04 / Debian 10 from docs/install.md), that package can fail before linting with a GLIBC version error. The main release workflow uses musl targets for shipped Linux binaries, so this new DotSlash package would be the one released tool that does not run across the repo's supported Linux baseline.

Useful? React with 👍 / 👎.

cargo_dylint_binary: cargo-dylint
- runner: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
archive_name: argument-comment-lint-aarch64-unknown-linux-gnu.tar.gz
lib_name: libargument_comment_lint@nightly-2025-09-18-aarch64-unknown-linux-gnu.so
runner_binary: argument-comment-lint
cargo_dylint_binary: cargo-dylint
- runner: windows-x64
target: x86_64-pc-windows-msvc
archive_name: argument-comment-lint-x86_64-pc-windows-msvc.zip
lib_name: argument_comment_lint@nightly-2025-09-18-x86_64-pc-windows-msvc.dll
runner_binary: argument-comment-lint.exe
cargo_dylint_binary: cargo-dylint.exe
runs_on:
group: codex-runners
labels: codex-windows-x64

steps:
- uses: actions/checkout@v6

- uses: dtolnay/rust-toolchain@1.93.0
with:
toolchain: nightly-2025-09-18
targets: ${{ matrix.target }}
components: llvm-tools-preview, rustc-dev, rust-src

- name: Install tooling
shell: bash
run: |
install_root="${RUNNER_TEMP}/argument-comment-lint-tools"
cargo install --locked cargo-dylint --root "$install_root"
cargo install --locked dylint-link
echo "INSTALL_ROOT=$install_root" >> "$GITHUB_ENV"

- name: Cargo build
working-directory: tools/argument-comment-lint
shell: bash
run: cargo build --release --target ${{ matrix.target }}

- name: Stage artifact
shell: bash
run: |
dest="dist/argument-comment-lint/${{ matrix.target }}"
mkdir -p "$dest"
package_root="${RUNNER_TEMP}/argument-comment-lint"
rm -rf "$package_root"
mkdir -p "$package_root/bin" "$package_root/lib"

cp "tools/argument-comment-lint/target/${{ matrix.target }}/release/${{ matrix.runner_binary }}" \
"$package_root/bin/${{ matrix.runner_binary }}"
cp "${INSTALL_ROOT}/bin/${{ matrix.cargo_dylint_binary }}" \
"$package_root/bin/${{ matrix.cargo_dylint_binary }}"
cp "tools/argument-comment-lint/target/${{ matrix.target }}/release/${{ matrix.lib_name }}" \
"$package_root/lib/${{ matrix.lib_name }}"

archive_path="$dest/${{ matrix.archive_name }}"
if [[ "${{ runner.os }}" == "Windows" ]]; then
(cd "${RUNNER_TEMP}" && 7z a "$GITHUB_WORKSPACE/$archive_path" argument-comment-lint >/dev/null)
else
(cd "${RUNNER_TEMP}" && tar -czf "$GITHUB_WORKSPACE/$archive_path" argument-comment-lint)
fi

- uses: actions/upload-artifact@v7
with:
name: argument-comment-lint-${{ matrix.target }}
path: dist/argument-comment-lint/${{ matrix.target }}/*
15 changes: 15 additions & 0 deletions .github/workflows/rust-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -380,11 +380,19 @@ jobs:
publish: true
secrets: inherit

argument-comment-lint-release-assets:
name: argument-comment-lint release assets
needs: tag-check
uses: ./.github/workflows/rust-release-argument-comment-lint.yml
with:
publish: true

release:
needs:
- build
- build-windows
- shell-tool-mcp
- argument-comment-lint-release-assets
name: release
runs-on: ubuntu-latest
permissions:
Expand Down Expand Up @@ -521,6 +529,13 @@ jobs:
tag: ${{ github.ref_name }}
config: .github/dotslash-config.json

- uses: facebook/dotslash-publish-release@v2
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
tag: ${{ github.ref_name }}
config: .github/dotslash-argument-comment-lint-config.json

- name: Trigger developers.openai.com deploy
# Only trigger the deploy if the release is not a pre-release.
# The deploy is used to update the developers.openai.com website with the new config schema json file.
Expand Down
5 changes: 5 additions & 0 deletions tools/argument-comment-lint/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,11 @@ cd tools/argument-comment-lint
cargo test
```

GitHub releases also publish a DotSlash file named
`argument-comment-lint` for macOS arm64, Linux arm64, Linux x64, and Windows
x64. The published package contains a small runner executable, a bundled
`cargo-dylint`, and the prebuilt lint library.

Run the lint against `codex-rs` from the repo root:

```bash
Expand Down
164 changes: 164 additions & 0 deletions tools/argument-comment-lint/src/bin/argument-comment-lint.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use std::env;
use std::ffi::OsString;
use std::fs;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::ExitCode;

fn main() -> ExitCode {
match run() {
Ok(code) => code,
Err(err) => {
eprintln!("{err}");
ExitCode::from(1)
}
}
}

fn run() -> Result<ExitCode, String> {
let exe_path =
env::current_exe().map_err(|err| format!("failed to locate current executable: {err}"))?;
let bin_dir = exe_path.parent().ok_or_else(|| {
format!(
"failed to locate parent directory for executable {}",
exe_path.display()
)
})?;
let package_root = bin_dir.parent().ok_or_else(|| {
format!(
"failed to locate package root for executable {}",
exe_path.display()
)
})?;
let cargo_dylint = bin_dir.join(cargo_dylint_binary_name());
let library_dir = package_root.join("lib");
let library_path = find_bundled_library(&library_dir)?;

ensure_exists(&cargo_dylint, "bundled cargo-dylint executable")?;
ensure_exists(
&library_dir,
"bundled argument-comment lint library directory",
)?;

let args: Vec<OsString> = env::args_os().skip(1).collect();
let mut command = Command::new(&cargo_dylint);
command.arg("dylint");
command.arg("--lib-path").arg(&library_path);
if !has_library_selection(&args) {
Comment on lines +44 to +48
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the published wrapper aligned with run.sh defaults

If someone invokes the released argument-comment-lint the same way CI invokes tools/argument-comment-lint/run.sh (for example from the repo root with -p codex-core), this wrapper just forwards the current working directory to cargo-dylint. Because the workspace manifest lives under codex-rs/Cargo.toml, cargo-dylint will fail to find a manifest unless the caller also remembers the --manifest-path/--workspace/--no-deps defaults that run.sh injects today. That makes the new release asset non-runnable for the repo's normal entrypoint instead of being a drop-in packaged replacement.

Useful? React with 👍 / 👎.

command.arg("--all");
}
command.args(&args);
set_default_env(&mut command);

let status = command
.status()
.map_err(|err| format!("failed to execute {}: {err}", cargo_dylint.display()))?;
Ok(exit_code_from_status(status.code()))
}

fn has_library_selection(args: &[OsString]) -> bool {
let mut expect_value = false;
for arg in args {
if expect_value {
return true;
}

match arg.to_string_lossy().as_ref() {
"--" => break,
"--lib" | "--lib-path" => {
expect_value = true;
}
"--lib=" | "--lib-path=" => return true,
value if value.starts_with("--lib=") || value.starts_with("--lib-path=") => {
return true;
}
_ => {}
}
}

false
}

fn set_default_env(command: &mut Command) {
if let Some(flags) = env::var_os("DYLINT_RUSTFLAGS") {
let mut flags = flags.to_string_lossy().to_string();
append_flag_if_missing(&mut flags, "-D uncommented-anonymous-literal-argument");
append_flag_if_missing(&mut flags, "-A unknown_lints");
command.env("DYLINT_RUSTFLAGS", flags);
} else {
command.env(
"DYLINT_RUSTFLAGS",
"-D uncommented-anonymous-literal-argument -A unknown_lints",
);
}

if env::var_os("CARGO_INCREMENTAL").is_none() {
command.env("CARGO_INCREMENTAL", "0");
}
}

fn append_flag_if_missing(flags: &mut String, flag: &str) {
if flags.contains(flag) {
return;
}

if !flags.is_empty() {
flags.push(' ');
}
flags.push_str(flag);
}

fn cargo_dylint_binary_name() -> &'static str {
if cfg!(windows) {
"cargo-dylint.exe"
} else {
"cargo-dylint"
}
}

fn ensure_exists(path: &Path, label: &str) -> Result<(), String> {
if path.exists() {
Ok(())
} else {
Err(format!("{label} not found at {}", path.display()))
}
}

fn find_bundled_library(library_dir: &Path) -> Result<PathBuf, String> {
let entries = fs::read_dir(library_dir).map_err(|err| {
format!(
"failed to read bundled library directory {}: {err}",
library_dir.display()
)
})?;
let mut candidates = entries
.filter_map(Result::ok)
.map(|entry| entry.path())
.filter(|path| path.is_file())
.filter(|path| {
path.file_name()
.map(|name| name.to_string_lossy().contains('@'))
.unwrap_or(false)
});

let Some(first) = candidates.next() else {
return Err(format!(
"no packaged Dylint library found in {}",
library_dir.display()
));
};
if candidates.next().is_some() {
return Err(format!(
"expected exactly one packaged Dylint library in {}",
library_dir.display()
));
}

Ok(first)
}

fn exit_code_from_status(code: Option<i32>) -> ExitCode {
code.and_then(|value| u8::try_from(value).ok())
.map_or_else(|| ExitCode::from(1), ExitCode::from)
}
Loading