diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 00000000..4a6a1abd --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[resolver] +incompatible-rust-versions = "fallback" diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 7ab13b9f..cc1fefc3 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -6,16 +6,19 @@ commitMessageLowerCase: 'never', configMigration: true, dependencyDashboard: true, + "pre-commit": { + enabled: true + }, customManagers: [ { customType: 'regex', - fileMatch: [ - '^rust-toolchain\\.toml$', - 'Cargo.toml$', - 'clippy.toml$', - '\\.clippy.toml$', - '^\\.github/workflows/ci.yml$', - '^\\.github/workflows/rust-next.yml$', + managerFilePatterns: [ + '/^rust-toolchain\\.toml$/', + '/Cargo.toml$/', + '/clippy.toml$/', + '/\\.clippy.toml$/', + '/^\\.github/workflows/ci.yml$/', + '/^\\.github/workflows/rust-next.yml$/', ], matchStrings: [ 'STABLE.*?(?\\d+\\.\\d+(\\.\\d+)?)', @@ -25,6 +28,18 @@ packageNameTemplate: 'rust-lang/rust', datasourceTemplate: 'github-releases', }, + { + customType: 'regex', + managerFilePatterns: [ + '/^\\.github/workflows/pre-commit.yml$/', + ], + matchStrings: [ + 'prek-version.*?(?\\d+\\.\\d+(\\.\\d+)?)', + ], + depNameTemplate: 'prek', + packageNameTemplate: 'j178/prek', + datasourceTemplate: 'github-releases', + }, ], packageRules: [ { @@ -41,6 +56,20 @@ ], automerge: true, }, + { + commitMessageTopic: 'Prek', + matchManagers: [ + 'custom.regex', + ], + matchDepNames: [ + 'prek', + ], + extractVersion: '^(?\\d+\\.\\d+\\.\\d+)', + schedule: [ + '* * * * *', + ], + automerge: true, + }, // Goals: // - Keep version reqs low, ignoring compatible normal/build dependencies // - Take advantage of latest dev-dependencies diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3296938..5964cae7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,6 +38,9 @@ jobs: rust: ["stable"] continue-on-error: ${{ matrix.rust != 'stable' }} runs-on: ${{ matrix.os }} + env: + # Reduce amount of data cached + CARGO_PROFILE_DEV_DEBUG: line-tables-only steps: - name: Checkout repository uses: actions/checkout@v6 @@ -50,10 +53,13 @@ jobs: - name: Build run: cargo test --workspace --no-run - name: Test - run: cargo hack test --feature-powerset --workspace + run: cargo hack test --each-feature --workspace msrv: name: "Check MSRV" - runs-on: ubuntu-latest + strategy: + matrix: + os: ["ubuntu-latest"] + runs-on: ${{ matrix.os }} steps: - name: Checkout repository uses: actions/checkout@v6 @@ -64,10 +70,13 @@ jobs: - uses: Swatinem/rust-cache@v2 - uses: taiki-e/install-action@cargo-hack - name: Default features - run: cargo hack check --feature-powerset --locked --rust-version --ignore-private --workspace --all-targets + run: cargo hack check --each-feature --locked --rust-version --ignore-private --workspace --all-targets --keep-going minimal-versions: name: Minimal versions - runs-on: ubuntu-latest + strategy: + matrix: + os: ["ubuntu-latest"] + runs-on: ${{ matrix.os }} steps: - name: Checkout repository uses: actions/checkout@v6 @@ -82,7 +91,7 @@ jobs: - name: Downgrade dependencies to minimal versions run: cargo +nightly generate-lockfile -Z minimal-versions - name: Compile with minimal versions - run: cargo +stable check --workspace --all-features --locked + run: cargo +stable check --workspace --all-features --locked --keep-going lockfile: runs-on: ubuntu-latest steps: @@ -104,12 +113,12 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.83" # STABLE + toolchain: "1.93" # STABLE - uses: Swatinem/rust-cache@v2 - name: Check documentation env: RUSTDOCFLAGS: -D warnings - run: cargo doc --workspace --all-features --no-deps --document-private-items + run: cargo doc --workspace --all-features --no-deps --document-private-items --keep-going rustfmt: name: rustfmt runs-on: ubuntu-latest @@ -119,11 +128,11 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.83" # STABLE + toolchain: "1.93" # STABLE components: rustfmt - uses: Swatinem/rust-cache@v2 - name: Check formatting - run: cargo fmt --all -- --check + run: cargo fmt --check clippy: name: clippy runs-on: ubuntu-latest @@ -135,7 +144,7 @@ jobs: - name: Install Rust uses: dtolnay/rust-toolchain@stable with: - toolchain: "1.83" # STABLE + toolchain: "1.93" # STABLE components: clippy - uses: Swatinem/rust-cache@v2 - name: Install SARIF tools @@ -144,7 +153,7 @@ jobs: run: cargo install sarif-fmt --locked - name: Check run: > - cargo clippy --workspace --all-features --all-targets --message-format=json -- -D warnings --allow deprecated + cargo clippy --workspace --all-features --all-targets --message-format=json | clippy-sarif | tee clippy-results.sarif | sarif-fmt @@ -155,7 +164,7 @@ jobs: sarif_file: clippy-results.sarif wait-for-processing: true - name: Report status - run: cargo clippy --workspace --all-features --all-targets -- -D warnings --allow deprecated + run: cargo clippy --workspace --all-features --all-targets --keep-going -- -D warnings --allow deprecated coverage: name: Coverage runs-on: ubuntu-latest diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 9eabc676..ef1a54ac 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -23,7 +23,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v6 - - uses: actions/setup-python@v6 + - uses: j178/prek-action@v1 with: - python-version: '3.x' - - uses: pre-commit/action@v3.0.1 + prek-version: '0.2.27' diff --git a/.github/workflows/rust-next.yml b/.github/workflows/rust-next.yml index 272658c0..2147daff 100644 --- a/.github/workflows/rust-next.yml +++ b/.github/workflows/rust-next.yml @@ -28,6 +28,9 @@ jobs: rust: "nightly" continue-on-error: ${{ matrix.rust != 'stable' }} runs-on: ${{ matrix.os }} + env: + # Reduce amount of data cached + CARGO_PROFILE_DEV_DEBUG: line-tables-only steps: - name: Checkout repository uses: actions/checkout@v6 @@ -40,10 +43,15 @@ jobs: - name: Build run: cargo test --workspace --no-run - name: Test - run: cargo hack test --feature-powerset --workspace + run: cargo hack test --each-feature --workspace latest: name: "Check latest dependencies" - runs-on: ubuntu-latest + strategy: + matrix: + os: ["ubuntu-latest"] + runs-on: ${{ matrix.os }} + env: + CARGO_RESOLVER_INCOMPATIBLE_RUST_VERSIONS: allow steps: - name: Checkout repository uses: actions/checkout@v6 @@ -58,4 +66,4 @@ jobs: - name: Build run: cargo test --workspace --no-run - name: Test - run: cargo hack test --feature-powerset --workspace + run: cargo hack test --each-feature --workspace diff --git a/.github/workflows/template.yml b/.github/workflows/template.yml new file mode 100644 index 00000000..1d4fd850 --- /dev/null +++ b/.github/workflows/template.yml @@ -0,0 +1,58 @@ +name: Template Update + +permissions: + contents: read + +on: + schedule: + - cron: '1 1 1 * *' + workflow_dispatch: + +env: + RUST_BACKTRACE: 1 + CARGO_TERM_COLOR: always + CLICOLOR: 1 + TEMPLATE_URL: "https://github.com/epage/_rust.git" + TEMPLATE_BRANCH: "main" + +concurrency: + group: "${{ github.workflow }}-${{ github.ref }}" + cancel-in-progress: true + +jobs: + update: + permissions: + security-events: write # to create PR + pull-requests: write + contents: write # to push the branch + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v6 + with: + fetch-depth: 0 + - name: Configure git + run: | + git config --global user.name '${{ github.actor }}' + git config --global user.email '<>' + - name: Fetch template + run: "git remote add template ${{ env.TEMPLATE_URL }} && git fetch template ${{ env.TEMPLATE_BRANCH }}" + - name: Merge template + run: "git checkout -b template-update && git merge template/${{ env.TEMPLATE_BRANCH }} -m 'chore: Update from template'" + - name: Clear any existing branch + run: "git push origin --delete template-update" + continue-on-error: true + env: + GH_TOKEN: ${{ github.token }} + - name: Push branch + run: "git push --set-upstream origin template-update" + env: + GH_TOKEN: ${{ github.token }} + - name: Create PR + run: "gh pr create --head template-update --title 'chore: Update from template' --body ''" + env: + GH_TOKEN: ${{ github.token }} + - name: Merge PR + run: "gh pr merge --auto --delete-branch" + env: + GH_TOKEN: ${{ github.token }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 68db968e..7aa56f78 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,26 +1,19 @@ +default_install_hook_types: ["pre-commit", "commit-msg"] repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v6.0.0 hooks: - id: check-yaml - stages: [commit] - id: check-json - stages: [commit] - id: check-toml - stages: [commit] - id: check-merge-conflict - stages: [commit] - id: check-case-conflict - stages: [commit] - id: detect-private-key - stages: [commit] - repo: https://github.com/crate-ci/typos - rev: v1.16.20 + rev: v1.42.1 hooks: - id: typos - stages: [commit] - repo: https://github.com/crate-ci/committed - rev: v1.0.20 + rev: v1.1.10 hooks: - id: committed - stages: [commit-msg] diff --git a/CHANGELOG.md b/CHANGELOG.md index 91c33a8a..7bb2b6b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,9 @@ # Change Log All notable changes to this project will be documented in this file. -This project adheres to [Semantic Versioning](http://semver.org/). + +The format is based on [Keep a Changelog](https://keepachangelog.com/) +and this project adheres to [Semantic Versioning](https://semver.org/). ## [Unreleased] - ReleaseDate diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5565f47c..b9a76ae3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,18 +7,18 @@ appreciate any level you're willing to do. Need some new functionality to help? You can let us know by opening an [issue][new issue]. It's helpful to look through [all issues][all issues] in -case its already being talked about. +case it's already being talked about. ## Bug Reports Please let us know about what problems you run into, whether in behavior or ergonomics of API. You can do this by opening an [issue][new issue]. It's -helpful to look through [all issues][all issues] in case its already being +helpful to look through [all issues][all issues] in case it's already being talked about. ## Pull Requests -Looking for an idea? Check our [issues][issues]. If it's look more open ended, +Looking for an idea? Check our [issues][issues]. If the issue looks open ended, it is probably best to post on the issue how you are thinking of resolving the issue so you can get feedback early in the process. We want you to be successful and it can be discouraging to find out a lot of re-work is needed. @@ -41,15 +41,18 @@ As a heads up, we'll be running your PR through the following gauntlet: Not everything can be checked automatically though. We request that the commit history gets cleaned up. + We ask that commits are atomic, meaning they are complete and have a single responsibility. -PRs should tell a cohesive story, with test and refactor commits that keep the +A complete commit should build, pass tests, update documentation and tests, and not have dead code. + +PRs should tell a cohesive story, with refactor and test commits that keep the fix or feature commits simple and clear. Specifically, we would encourage - File renames be isolated into their own commit -- Add tests in a commit before their feature or fix, showing the current behavior. +- Add tests in a commit before their feature or fix, showing the current behavior (i.e. they should pass). The diff for the feature/fix commit will then show how the behavior changed, - making it clearer to reviewrs and the community and showing people that the + making the commit's intent clearer to reviewers and the community, and showing people that the test is verifying the expected state. - e.g. [clap#5520](https://github.com/clap-rs/clap/pull/5520) diff --git a/Cargo.toml b/Cargo.toml index 5c01f213..42c253d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,12 +13,12 @@ include = [ "Cargo.lock", "LICENSE*", "README.md", - "benches/**/*", "examples/**/*" ] [workspace.lints.rust] rust_2018_idioms = { level = "warn", priority = -1 } +unnameable_types = "warn" unreachable_pub = "warn" unsafe_op_in_unsafe_fn = "warn" unused_lifetimes = "warn" @@ -34,7 +34,7 @@ create_dir = "warn" dbg_macro = "warn" debug_assert_with_mut_call = "warn" doc_markdown = "warn" -empty_enum = "warn" +empty_enums = "warn" enum_glob_use = "warn" expl_impl_clone_on_copy = "warn" explicit_deref_methods = "warn" @@ -61,7 +61,7 @@ lossy_float_literal = "warn" macro_use_imports = "warn" mem_forget = "warn" mutex_integer = "warn" -needless_continue = "warn" +needless_continue = "allow" needless_for_each = "warn" negative_feature_names = "warn" path_buf_push_overwrite = "warn" @@ -78,7 +78,6 @@ str_to_string = "warn" string_add = "warn" string_add_assign = "warn" string_lit_as_bytes = "warn" -string_to_string = "warn" todo = "warn" trait_duplication_in_bounds = "warn" uninlined_format_args = "warn" @@ -86,6 +85,15 @@ verbose_file_reads = "warn" wildcard_imports = "warn" zero_sized_map_values = "warn" +[profile.dev] +panic = "abort" + +[profile.release] +panic = "abort" +codegen-units = 1 +lto = true +# debug = "line-tables-only" # requires Cargo 1.71 + [package] name = "rexpect" description = "Interact with unix processes/bash the same way as pexpect or Don libes expect does" @@ -100,7 +108,7 @@ include.workspace = true [package.metadata.docs.rs] all-features = true -rustdoc-args = ["--cfg", "docsrs", "--generate-link-to-definition"] +rustdoc-args = ["--generate-link-to-definition"] [package.metadata.release] pre-release-replacements = [ diff --git a/README.md b/README.md index 6f6a4fa7..95451423 100644 --- a/README.md +++ b/README.md @@ -133,8 +133,8 @@ fn main() { Licensed under either of -* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) -* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or ) at your option. @@ -142,7 +142,7 @@ at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 -license, shall be dual licensed as above, without any additional terms or +license, shall be dual-licensed as above, without any additional terms or conditions. diff --git a/deny.toml b/deny.toml index b6ecbe9c..27bf59a8 100644 --- a/deny.toml +++ b/deny.toml @@ -87,12 +87,16 @@ allow = [ "MIT", "MIT-0", "Apache-2.0", + "BSD-2-Clause", "BSD-3-Clause", "MPL-2.0", "Unicode-DFS-2016", + "Unicode-3.0", "CC0-1.0", "ISC", "OpenSSL", + "Zlib", + "NCSA", ] # The confidence threshold for detecting a license from license text. # The higher the value, the more closely the license text must be to the diff --git a/src/lib.rs b/src/lib.rs index 52c2dcca..cc656a03 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ //! } //! ``` -#![cfg_attr(docsrs, feature(doc_auto_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] #![warn(clippy::print_stderr)] #![warn(clippy::print_stdout)] @@ -79,3 +79,7 @@ pub use session::{spawn, spawn_bash, spawn_python, spawn_stream, spawn_with_opti // include the README.md here to test its doc #[doc = include_str!("../README.md")] mod test {} + +#[doc = include_str!("../README.md")] +#[cfg(doctest)] +pub struct ReadmeDoctests; diff --git a/src/process.rs b/src/process.rs index 0dbf7e17..63cfb498 100644 --- a/src/process.rs +++ b/src/process.rs @@ -126,7 +126,7 @@ impl PtyProcess { flags.local_flags &= !termios::LocalFlags::ECHO; termios::tcsetattr(&stdin, termios::SetArg::TCSANOW, &flags)?; - command.exec(); + let _ = command.exec(); Err(Error::Nix(nix::Error::last())) } ForkResult::Parent { child: child_pid } => Ok(PtyProcess { @@ -173,11 +173,7 @@ impl PtyProcess { /// ``` /// pub fn status(&self) -> Option { - if let Ok(status) = wait::waitpid(self.child_pid, Some(wait::WaitPidFlag::WNOHANG)) { - Some(status) - } else { - None - } + wait::waitpid(self.child_pid, Some(wait::WaitPidFlag::WNOHANG)).ok() } /// Wait until process has exited. This is a blocking call. @@ -188,7 +184,7 @@ impl PtyProcess { /// Regularly exit the process, this method is blocking until the process is dead pub fn exit(&mut self) -> Result { - self.kill(signal::SIGTERM).map_err(Error::from) + self.kill(signal::SIGTERM) } /// Non-blocking variant of `kill()` (doesn't wait for process to be killed)