From bc7401622a8f9dc735c5d34beeb8b62fbf103c93 Mon Sep 17 00:00:00 2001
From: Nicolas80 <nicolas.pmail@protonmail.com>
Date: Mon, 12 May 2025 16:17:31 +0200
Subject: [PATCH] gcli command auto completion and arm64 build

- Extra command `completion` added which takes a `--shell` argument to generate a completions script for a specified shell.
- Adapted the Linux (amd64) build to:
  - generate the `gcli-completion.bash`, `gcli-completion.zsh`, `gcli-completion.fish`, `gcli-completion.ps1` completion scripts
  - add the `bash`, `zsh` and `fish` completion scripts in the `.deb` package
- Added the ARM64 build generating a binary and a `.deb` package that also include those completion scripts.
---
 .gitlab-ci.yml | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--
 CHANGELOG.md   | 24 ++++++++++++++++
 Cargo.lock     | 12 +++++++-
 Cargo.toml     | 22 ++++++++++++++-
 src/main.rs    | 16 ++++++++++-
 5 files changed, 144 insertions(+), 5 deletions(-)

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 3d5e019..df94e14 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -18,15 +18,26 @@ build_linux:
   script:
      # Build the project for Linux
     - cargo build --release
-    # Create Debian package
+    # Create completion scripts for different shells
+    - ./target/release/gcli completion --shell bash > gcli-completion.bash
+    - ./target/release/gcli completion --shell zsh > gcli-completion.zsh
+    - ./target/release/gcli completion --shell fish > gcli-completion.fish
+    - ./target/release/gcli completion --shell powershell > gcli-completion.ps1
+    # Dependency to create Debian package
     - cargo install cargo-deb
-    - cargo deb --no-build
+    # Create Debian package
+    # Should include completion scripts assets which are declared in Cargo.toml in [package.metadata.deb] section
+    - cargo deb --no-build 
     - ls target/debian/*.deb | head -n 1 > debian_package.txt
   artifacts:
     paths:
       - target/release/gcli
       - target/debian/*.deb
       - debian_package.txt
+      - gcli-completion.bash
+      - gcli-completion.zsh
+      - gcli-completion.fish
+      - gcli-completion.ps1
   cache:
     key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
     paths:
@@ -35,6 +46,51 @@ build_linux:
   only:
     - tags
 
+build_linux_arm64:
+  stage: build
+  image: rust:buster
+  # Needs the completion scripts built with build_linux
+  needs:
+    - job: build_linux
+      artifacts: true
+  script:
+    # Add the arm64 architecture
+    - dpkg --add-architecture arm64
+    # Also include libssl-dev necessary for openssl-sys
+    - >
+      apt-get update && apt-get install -y 
+      gcc-aarch64-linux-gnu 
+      libssl-dev:arm64 
+      pkg-config
+    - export CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER=aarch64-linux-gnu-gcc
+    # Tells Cargo to use the ARM64-specific pkg-config wrapper for the aarch64-unknown-linux-gnu target.
+    - export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig
+    # Specifies the sysroot directory where the ARM64 libraries (e.g., /usr/aarch64-linux-gnu/lib) are located, helping pkg-config find the correct paths.
+    - export PKG_CONFIG_SYSROOT_DIR=/usr/aarch64-linux-gnu
+    # Rust toolchain should includes support for the aarch64-unknown-linux-gnu target
+    - rustup target add aarch64-unknown-linux-gnu
+    # Build the project for Linux ARM64
+    - cargo build --release --target aarch64-unknown-linux-gnu
+    # Dependency to create Debian package
+    - cargo install cargo-deb
+    # Create Debian package
+    # Should include completion scripts assets which are declared in Cargo.toml in [package.metadata.deb] section
+    # Those assets are built during build_linux which is run before (see the "needs" declaration here)
+    - cargo deb --no-build --target aarch64-unknown-linux-gnu 
+    - ls target/aarch64-unknown-linux-gnu/debian/*.deb | head -n 1 > debian_package_arm64.txt
+  artifacts:
+    paths:
+      - target/aarch64-unknown-linux-gnu/release/gcli
+      - target/aarch64-unknown-linux-gnu/debian/*.deb
+      - debian_package_arm64.txt
+  cache:
+    key: "$CI_JOB_NAME-$CI_COMMIT_REF_SLUG"
+    paths:
+      - target/aarch64-unknown-linux-gnu/release
+      - target/aarch64-unknown-linux-gnu/debian
+  only:
+    - tags
+
 build_macos:
   stage: build
   image: poka/rust-osxcross:latest
@@ -85,13 +141,28 @@ release:
           url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/release/gcli?job=build_linux"
         - name: "gcli v$CI_COMMIT_TAG Debian Package"
           url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/$(cat debian_package.txt)?job=build_linux"
+        - name: "gcli v$CI_COMMIT_TAG for Linux ARM64 (binary)"
+          url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/aarch64-unknown-linux-gnu/release/gcli?job=build_linux_arm64"
+        - name: "gcli v$CI_COMMIT_TAG Debian Package ARM64"
+          url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/$(cat debian_package_arm64.txt)?job=build_linux_arm64"
         - name: "gcli v$CI_COMMIT_TAG for macOS"
           url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/target/macos/gcli.zip?job=build_macos"
+        # Make the completions scripts available for download
+        - name: "gcli v$CI_COMMIT_TAG Bash completion"
+          url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/gcli-completion.bash?job=build_linux"
+        - name: "gcli v$CI_COMMIT_TAG Zsh completion"
+          url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/gcli-completion.zsh?job=build_linux"
+        - name: "gcli v$CI_COMMIT_TAG Fish completion"
+          url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/gcli-completion.fish?job=build_linux"
+        - name: "gcli v$CI_COMMIT_TAG PowerShell completion"
+          url: "$CI_PROJECT_URL/-/jobs/artifacts/$CI_COMMIT_TAG/raw/gcli-completion.ps1?job=build_linux"
   only:
     - tags
   dependencies:
     - build_linux
+    - build_linux_arm64
     - build_macos
   artifacts:
     paths:
       - debian_package.txt
+      - debian_package_arm64.txt
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c772b67..20c14a6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,29 @@
 
 List of changelogs ordered from latest to oldest
 
+
+## [0.4.2] - 2025-05-12
+### Added / Changed
+- Extra command `completion` added which takes a `--shell` argument to generate a completions script for a specified shell.
+
+### CI/CD
+- Adapted the Linux (amd64) build to:
+  - generate the `gcli-completion.bash`, `gcli-completion.zsh`, `gcli-completion.fish`, `gcli-completion.ps1` completion scripts
+  - add the `bash`, `zsh` and `fish` completion scripts in the `.deb` package
+- Added the ARM64 build generating a binary and a `.deb` package that also include those completion scripts.
+
+### Fixed
+- None
+
+### Deprecated
+- Two commands are still deprecated and will be removed in a future release:
+  - `gcli vault list-files`
+  - `gcli vault migrate`
+
+### Removed
+- None
+
+
 ## [0.4.1] - 2025-04-08
 ### Added / Changed
 - We now use `ed25519` crypto scheme by default for all commands.  It means that if you import your substrate mnemonic without giving a specific argument to change the crypto scheme, the resulting SS58 address will not be the same as before (it was using `sr25519` for substrate mnemonic previously)
@@ -46,6 +69,7 @@ List of changelogs ordered from latest to oldest
 ### CI/CD
 - None
 
+
 ## [0.4.0] - 2025-02-xx
 ### Changed
 - Old key files cannot be used directly anymore, they have to be migrated to the SQLite file database.  You can use the following commands for that:
diff --git a/Cargo.lock b/Cargo.lock
index 0264e14..4299623 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1148,6 +1148,15 @@ dependencies = [
  "strsim 0.11.1",
 ]
 
+[[package]]
+name = "clap_complete"
+version = "4.5.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e16bb32eaa759f7fe76c59793c4e00dad6d11705f74ddfe4887e62f459536f16"
+dependencies = [
+ "clap",
+]
+
 [[package]]
 name = "clap_derive"
 version = "4.5.18"
@@ -2338,13 +2347,14 @@ dependencies = [
 
 [[package]]
 name = "gcli"
-version = "0.4.1"
+version = "0.4.2"
 dependencies = [
  "age",
  "anyhow",
  "bip39",
  "bs58",
  "clap",
+ "clap_complete",
  "colored",
  "comfy-table",
  "confy",
diff --git a/Cargo.toml b/Cargo.toml
index 8600c6d..1d1b0b5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,7 +10,7 @@ license = "AGPL-3.0-only"
 name = "gcli"
 repository = "https://git.duniter.org/clients/rust/gcli-v2s"
 description = "A command-line interface for Duniter v2s uses"
-version = "0.4.1"
+version = "0.4.2"
 
 [dependencies]
 # subxt is main dependency
@@ -27,6 +27,7 @@ sp-runtime = { git = "https://github.com/duniter/duniter-polkadot-sdk.git", bran
 # crates.io dependencies
 anyhow = "^1.0"
 clap = { version = "^4.5.19", features = ["derive"] }
+clap_complete = "^4.5.19"
 codec = { package = "parity-scale-codec", version = "^3.6.12" }
 env_logger = "^0.10"
 futures = "^0.3.30"
@@ -68,3 +69,22 @@ g1 = []
 name = "gcli"
 identifier = "com.axiomteam.gcli"
 icon = ["gcli.png"]
+
+# Used by gitlab ci to add extra assets in the .deb packages (both amd64 & arm64)
+# Those gcli-completion.* assets are created during gitlab ci "build_linux"
+#Documentation in https://github.com/kornelski/cargo-deb
+[package.metadata.deb]
+assets = [
+    # Examples
+    #target/release path is special, and gets replaced by cargo-deb with the actual target dir path.
+    #["target/release/cargo-deb", "usr/bin/", "755"],
+    #both array and object syntaxes are equivalent:
+    #{ source = "README.md", dest = "usr/share/doc/cargo-deb/README", mode = "644"},
+
+    # Bin has to be manually added since we override the default "assets"
+    { source = "target/release/gcli", dest = "usr/bin/", mode = "755" },
+    # The extra shell completion script assets
+    { source = "gcli-completion.bash", dest = "/etc/bash_completion.d/gcli", mode = "644" },
+    { source = "gcli-completion.zsh", dest = "/usr/local/share/zsh/site-functions/_gcli", mode = "644" },
+    { source = "gcli-completion.fish", dest = "/usr/share/fish/vendor_completions.d/gcli.fish", mode = "644" }
+]
\ No newline at end of file
diff --git a/src/main.rs b/src/main.rs
index 26a87da..2a03562 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -12,7 +12,8 @@ mod utils;
 
 use anyhow::anyhow;
 use clap::builder::OsStr;
-use clap::Parser;
+use clap::{CommandFactory, Parser};
+use clap_complete::{generate, Shell};
 use codec::Encode;
 use colored::Colorize;
 use data::*;
@@ -20,6 +21,7 @@ use display::DisplayEvent;
 use keys::*;
 use runtime_config::*;
 use serde::{Deserialize, Serialize};
+use std::io;
 use std::str::FromStr;
 use subxt::{
 	blocks::ExtrinsicEvents,
@@ -158,6 +160,12 @@ pub enum Subcommand {
 	/// Publish a new git tag with actual version
 	#[clap(hide = true)]
 	Publish,
+	/// Generate a completions script for a specified shell
+	Completion {
+		/// target shell
+		#[clap(long)]
+		shell: Shell,
+	},
 }
 
 /// main function
@@ -171,6 +179,12 @@ async fn main() -> Result<(), GcliError> {
 
 	// match subcommands
 	let result = match data.args.subcommand.clone() {
+		// handle shell completions
+		Subcommand::Completion { shell } => {
+			let mut app = Args::command();
+			generate(shell, &mut app, "gcli", &mut io::stdout());
+			return Ok(());
+		}
 		Subcommand::Nothing => Ok(()),
 		Subcommand::Account(subcommand) => {
 			commands::account::handle_command(data, subcommand).await
-- 
GitLab