From 47cd5f02d6f130d75020dbdaaf1072de441ca9c6 Mon Sep 17 00:00:00 2001 From: Latif Sulistyo Date: Sat, 15 Jul 2023 11:45:43 +0700 Subject: [PATCH 1/2] ci: add release workflow --- .cargo/config.toml | 11 +++ .github/workflows/ci-cd.yml | 142 ++++++++++++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 .cargo/config.toml create mode 100644 .github/workflows/ci-cd.yml diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..370e334 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,11 @@ +[target.aarch64-unknown-linux-gnu] +linker = "aarch64-linux-gnu-gcc" + +[target.aarch64-linux-android] +linker = "aarch64-linux-android33-clang++" + +[profile.release] +strip = "symbols" +lto = true +codegen-units = 1 +opt-level = "s" diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 0000000..dff0618 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,142 @@ +name: โš™๏ธ๐Ÿš€ + +on: + pull_request: + workflow_dispatch: + push: + branches: [master] + tags: ["*"] + +concurrency: + group: ci-cd-${{ github.ref }} + cancel-in-progress: true + +jobs: + code-quality: + name: ๐Ÿฆ€ Code Quality + runs-on: ubuntu-latest + steps: + - name: ๐Ÿ›Ž๏ธ Checkout + uses: actions/checkout@v3 + + - name: ๐Ÿฆ€ Install Rust + uses: dtolnay/rust-toolchain@stable + with: + components: clippy, rustfmt + + - name: โ™ป๏ธ Manage Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/ + target/ + key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} + cargo-${{ runner.os }}- + + - name: ๐ŸŽจ Check Formatting + run: cargo fmt --check --all + + - name: ๐Ÿ“Ž Check Linting + run: cargo clippy --locked --all-targets --all-features -- -D warnings + + - name: ๐Ÿงช Run Tests + run: cargo test --locked --all-targets --all-features + + build-artifacts: + name: โš™๏ธ Build (${{ matrix.artifact-name }}) + needs: [code-quality] + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + include: + - os: ubuntu-latest + artifact-name: vimv-x86_64-unknown-linux-gnu + cargo-target: x86_64-unknown-linux-gnu + - os: ubuntu-latest + artifact-name: vimv-aarch64-unknown-linux-gnu + cargo-target: aarch64-unknown-linux-gnu + linker: gcc-aarch64-linux-gnu + - os: ubuntu-latest + artifact-name: vimv-aarch64-linux-android + cargo-target: aarch64-linux-android + - os: macos-latest + artifact-name: vimv-aarch64-apple-darwin + cargo-target: aarch64-apple-darwin + - os: windows-latest + artifact-name: vimv-x86_64-pc-windows-gnu + cargo-target: x86_64-pc-windows-gnu + + steps: + - name: ๐Ÿ›Ž๏ธ Checkout + uses: actions/checkout@v3 + + - name: ๐Ÿฆ€ Install Rust + uses: dtolnay/rust-toolchain@stable + with: + target: ${{ matrix.cargo-target }} + + - name: ๐Ÿ”— Install Linker packages + if: matrix.linker != '' + run: | + sudo apt-get -y update + sudo apt-get -y install ${{ matrix.linker }} + + - name: ๐Ÿ›ฃ๏ธ Set Linker Path + if: matrix.cargo-target == 'aarch64-linux-android' + run: echo "$ANDROID_NDK/toolchains/llvm/prebuilt/linux-x86_64/bin" >> $GITHUB_PATH + + - name: โ™ป๏ธ Manage Build Cache + uses: actions/cache@v3 + with: + path: | + ~/.cargo/ + target/ + key: cargo-${{ matrix.artifact-name }}-${{ hashFiles('**/Cargo.lock') }} + restore-keys: | + cargo-${{ matrix.artifact-name }}-${{ hashFiles('**/Cargo.lock') }} + cargo-${{ matrix.artifact-name }}- + + - name: ๐Ÿ› ๏ธ Build Binary + run: cargo build --locked --release --target ${{ matrix.cargo-target }} + + - name: ๐Ÿ“ Setup Archive + Extension + shell: bash + run: | + mkdir -p staging + if [ "${{ matrix.os }}" = "windows-latest" ]; then + cp "target/${{ matrix.cargo-target }}/release/vimv.exe" staging/ + cd staging + 7z a ../${{ matrix.artifact-name }}.zip * + else + cp "target/${{ matrix.cargo-target }}/release/vimv" staging/ + cd staging + zip ../${{ matrix.artifact-name }}.zip * + fi + + - name: โฌ†๏ธ Upload Binary Artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.artifact-name }} + path: ${{ matrix.artifact-name }}.zip + retention-days: 5 + + release: + name: ๐Ÿš€ Create Release + if: github.ref_type == 'tag' + needs: [build-artifacts] + runs-on: ubuntu-latest + + steps: + - name: โฌ‡๏ธ Download All Binary Artifacts + uses: actions/download-artifact@v3 + + - name: ๐Ÿ—ƒ๏ธ Create Release + uses: softprops/action-gh-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + generate_release_notes: true + files: vimv-*/*.zip From ddbdcf48afc1113c44d8d99f37b5d2d4b69df965 Mon Sep 17 00:00:00 2001 From: Latif Sulistyo Date: Sat, 15 Jul 2023 12:01:42 +0700 Subject: [PATCH 2/2] style: fix linting & formatting --- src/main.rs | 76 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 51 insertions(+), 25 deletions(-) diff --git a/src/main.rs b/src/main.rs index 21782fb..f406c7d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,12 @@ use arguably::ArgParser; -use std::path::Path; -use std::process::exit; +use colored::*; +use rand::Rng; +use std::collections::HashSet; use std::env; use std::fs; -use std::collections::HashSet; -use rand::Rng; use std::io::Read; -use colored::*; - +use std::path::Path; +use std::process::exit; const HELPTEXT: &str = " Usage: vimv [files] @@ -50,7 +49,6 @@ Flags: -v, --version Print the version number and exit. "; - fn main() { let mut parser = ArgParser::new() .helptext(HELPTEXT) @@ -88,10 +86,18 @@ fn main() { eprintln!("error: failed to read current directory entry: {}", err); exit(1); }); - let entry_as_string = entry.path().into_os_string().into_string().unwrap_or_else(|err| { - eprintln!("error: failed to decode current directory entry name: {:?}", err); - exit(1); - }); + let entry_as_string = + entry + .path() + .into_os_string() + .into_string() + .unwrap_or_else(|err| { + eprintln!( + "error: failed to decode current directory entry name: {:?}", + err + ); + exit(1); + }); input_files.push(entry_as_string); } input_files.sort(); @@ -101,7 +107,10 @@ fn main() { if parser.found("stdin") { let mut buffer = String::new(); if let Err(err) = std::io::stdin().read_to_string(&mut buffer) { - eprintln!("error: failed to read filenames from standard input: {}", err); + eprintln!( + "error: failed to read filenames from standard input: {}", + err + ); exit(1); } if !buffer.trim().is_empty() { @@ -116,7 +125,7 @@ fn main() { // Sanity check - verify that no input filename begins with '#'. for input_file in &input_files { - if input_file.starts_with("#") { + if input_file.starts_with('#') { eprintln!("error: input filenames cannot begin with '#'"); exit(1); } @@ -134,7 +143,10 @@ fn main() { let mut input_set = HashSet::new(); for input_file in &input_files { if input_set.contains(input_file) { - eprintln!("error: the filename '{}' appears in the input list multiple times", input_file); + eprintln!( + "error: the filename '{}' appears in the input list multiple times", + input_file + ); exit(1); } input_set.insert(input_file); @@ -163,9 +175,12 @@ fn main() { // Sanity check - verify that the output filenames are unique. let mut case_sensitive_output_set = HashSet::new(); - for output_file in output_files.iter().filter(|s| !s.starts_with("#")) { + for output_file in output_files.iter().filter(|s| !s.starts_with('#')) { if case_sensitive_output_set.contains(output_file) { - eprintln!("error: the filename '{}' appears in the output list multiple times", output_file); + eprintln!( + "error: the filename '{}' appears in the output list multiple times", + output_file + ); exit(1); } case_sensitive_output_set.insert(output_file); @@ -173,7 +188,11 @@ fn main() { // Sanity check - verify that the output filenames are case-insensitively unique. let mut case_insensitive_output_set = HashSet::new(); - for output_file in output_files.iter().filter(|s| !s.starts_with("#")).map(|s| s.to_lowercase()) { + for output_file in output_files + .iter() + .filter(|s| !s.starts_with('#')) + .map(|s| s.to_lowercase()) + { if case_insensitive_output_set.contains(&output_file) { eprintln!( "error: the filename '{}' appears multiple times in the output list (case \ @@ -208,11 +227,14 @@ fn main() { rename_set.insert(input_file.to_string()); continue; } - eprintln!("error: cannot overwrite the existing directory '{}'", output_file); + eprintln!( + "error: cannot overwrite the existing directory '{}'", + output_file + ); exit(1); } - if output_file.starts_with("#") { + if output_file.starts_with('#') { delete_list.push(input_file); continue; } @@ -224,7 +246,7 @@ fn main() { continue; } - if parser.found("force") { + if parser.found("force") { rename_list.push((input_file.to_string(), output_file.to_string())); rename_set.insert(input_file.to_string()); continue; @@ -264,7 +286,6 @@ fn main() { } } - // Generate a unique temporary filename. fn get_temp_filename(base: &str) -> String { let mut rng = rand::thread_rng(); @@ -281,7 +302,6 @@ fn get_temp_filename(base: &str) -> String { exit(1); } - // Move the specified file to the system's trash/recycle bin. fn delete_file(input_file: &str, quiet: bool) { if !quiet { @@ -293,7 +313,6 @@ fn delete_file(input_file: &str, quiet: bool) { } } - // Rename `input_file` to `output_file`. fn move_file(input_file: &str, output_file: &str, quiet: bool) { if !quiet { @@ -303,13 +322,20 @@ fn move_file(input_file: &str, output_file: &str, quiet: bool) { if let Some(parent_path) = Path::new(output_file).parent() { if !parent_path.is_dir() { if let Err(err) = std::fs::create_dir_all(parent_path) { - eprintln!("error: cannot create the required directory '{}': {}", parent_path.display(), err); + eprintln!( + "error: cannot create the required directory '{}': {}", + parent_path.display(), + err + ); exit(1); } } } if let Err(err) = std::fs::rename(input_file, output_file) { - eprintln!("error: cannot rename the file '{}' to '{}': {}", input_file, output_file, err); + eprintln!( + "error: cannot rename the file '{}' to '{}': {}", + input_file, output_file, err + ); exit(1); } }