envio 0.4.0

Envio is a command-line tool that simplifies the management of environment variables across multiple profiles. It allows users to easily switch between different configurations and apply them to their current environment. Envio also encrypts sensitive environment variable values to ensure secure storage and transmission
name: CICD

env:
  CICD_INTERMEDIATES_DIR: "_cicd-intermediates"

on:
  pull_request:
    paths:
      - 'src/**'
      - '.github/**'
      - 'Cargo.toml'
      - 'Cargo.lock'
      - 'build.rs'
  push:
    branches:
      - main
    paths:
      - 'src/**'
      - '.github/**'
      - 'Cargo.toml'
      - 'Cargo.lock'
      - 'build.rs'
    tags:
      - "*"

permissions:
  contents: write

jobs:
  min_version:
    name: Minimum supported rust version
    runs-on: ubuntu-20.04
    steps:
      - name: Checkout source code
        uses: actions/checkout@v3
      - name: Get the MSRV from the package metadata
        id: msrv
        run: cargo metadata --no-deps --format-version 1 | jq -r '"version=" + (.packages[] | select(.name = "hyperfine").rust_version)' >> $GITHUB_OUTPUT
      - name: Install rust toolchain (v${{ steps.msrv.outputs.version }})
        uses: dtolnay/rust-toolchain@master
        with:
          toolchain: ${{ steps.msrv.outputs.version }}
          components: clippy, rustfmt
      - name: Run cargo fmt
        run: cargo fmt -- --check
      - name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
        run: cargo clippy --locked --all-targets ${{ env.MSRV_FEATURES }}
      - name: Run tests
        run: cargo test --locked ${{ env.MSRV_FEATURES }}

  build:
    name: ${{ matrix.job.os }} (${{ matrix.job.target }})
    runs-on: ${{ matrix.job.os }}
    strategy:
      fail-fast: false
      matrix:
        job:
          - { target: x86_64-unknown-linux-gnu,     os: ubuntu-20.04,   use-cross: true }
          - { target: aarch64-unknown-linux-gnu,    os: ubuntu-20.04,   use-cross: true }
          - { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04,   use-cross: true }
          - { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04,   use-cross: true }
          - { target: i686-unknown-linux-gnu,       os: ubuntu-20.04,   use-cross: true }
          - { target: x86_64-apple-darwin,          os: macos-12,                       }
          - { target: x86_64-pc-windows-gnu,        os: windows-2019,   arch: x86_64    }
          - { target: i686-pc-windows-msvc,         os: windows-2019,   arch: x86       }

    env:
      BUILD_CMD: cargo
    steps:
      - name: Checkout source code
        uses: actions/checkout@v3

      - name: Install prerequisites
        shell: bash
        run: |
          case ${{ matrix.job.target }} in
            arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
            aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
          esac

      - name: Extract crate information
        shell: bash
        run: |
          echo "PROJECT_NAME=envio" >> $GITHUB_ENV
          echo "PROJECT_VERSION=$(sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml | head -n1)" >> $GITHUB_ENV
          echo "PROJECT_MAINTAINER=$(sed -n 's/^authors = \["\(.*\)"\]/\1/p' Cargo.toml)" >> $GITHUB_ENV
          echo "PROJECT_HOMEPAGE=$(sed -n 's/^homepage = "\(.*\)"/\1/p' Cargo.toml)" >> $GITHUB_ENV

      - name: Install Rust toolchain
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.job.target }}

      - name: Show version information (Rust, cargo, GCC)
        shell: bash
        run: |
          gcc --version || true
          rustup -V
          rustup toolchain list
          rustup default
          cargo -V
          rustc -V

      - name: Install cross
        if: matrix.job.use-cross
        uses: taiki-e/install-action@v2
        with:
          tool: cross

      - name: Overwrite build command env variable
        if: matrix.job.use-cross
        shell: bash
        run: |
          sudo apt-get install libudev-dev
          sudo apt-get install libssl-dev

          echo "BUILD_CMD=cross" >> $GITHUB_ENV

      - name: Build
        shell: bash
        run: |
          $BUILD_CMD build --locked --release --target=${{ matrix.job.target }}

      - name: Strip debug information from executable
        id: strip
        shell: bash
        run: |
          # Figure out suffix of binary
          EXE_suffix=""
          case ${{ matrix.job.target }} in
            *-pc-windows-*) EXE_suffix=".exe" ;;
          esac;

          STRIP="strip"
          case ${{ matrix.job.target }} in
            arm-unknown-linux-*) STRIP="arm-linux-gnueabihf-strip" ;;
            aarch64-unknown-linux-gnu) STRIP="aarch64-linux-gnu-strip" ;;
            *-pc-windows-msvc) STRIP="" ;;
          esac;

          BIN_DIR="${{ env.CICD_INTERMEDIATES_DIR }}/stripped-release-bin/"
          mkdir -p "${BIN_DIR}"
          BIN_NAME="${{ env.PROJECT_NAME }}${EXE_suffix}"
          BIN_PATH="${BIN_DIR}/${BIN_NAME}"

          cp "target/${{ matrix.job.target }}/release/${BIN_NAME}" "${BIN_DIR}"

          # Also strip if possible
          if [ -n "${STRIP}" ]; then
            "${STRIP}" "${BIN_PATH}"
          fi

          echo "BIN_PATH=${BIN_PATH}" >> $GITHUB_OUTPUT
          echo "BIN_NAME=${BIN_NAME}" >> $GITHUB_OUTPUT

      - name: Run tests
        shell: bash
        run: $BUILD_CMD test --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}

      - name: Create tarball
        id: package
        shell: bash
        run: |
          PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
          PKG_BASENAME=${PROJECT_NAME}-v${PROJECT_VERSION}-${{ matrix.job.target }}
          PKG_NAME=${PKG_BASENAME}${PKG_suffix}
          echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT

          PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package"
          ARCHIVE_DIR="${PKG_STAGING}/${PKG_BASENAME}/"
          mkdir -p "${ARCHIVE_DIR}"
          mkdir -p "${ARCHIVE_DIR}/autocomplete"

          cp "${{ steps.strip.outputs.BIN_PATH }}" "$ARCHIVE_DIR"

          cp 'man/${{ env.PROJECT_NAME }}.1' "$ARCHIVE_DIR"

          cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "CHANGELOG.md" "$ARCHIVE_DIR"

          cp completions/'${{ env.PROJECT_NAME }}.bash' "$ARCHIVE_DIR/autocomplete/"
          cp completions/'${{ env.PROJECT_NAME }}.fish' "$ARCHIVE_DIR/autocomplete/"
          cp completions/'_${{ env.PROJECT_NAME }}'  "$ARCHIVE_DIR/autocomplete/"
          cp completions/'_${{ env.PROJECT_NAME }}.ps1'  "$ARCHIVE_DIR/autocomplete/"

          pushd "${PKG_STAGING}/" >/dev/null
          case ${{ matrix.job.target }} in
            *-pc-windows-*) 7z -y a "${PKG_NAME}" "${PKG_BASENAME}"/* | tail -2 ;;
            *) tar czf "${PKG_NAME}" "${PKG_BASENAME}"/* ;;
          esac;
          popd >/dev/null

          echo "PKG_PATH=${PKG_STAGING}/${PKG_NAME}" >> $GITHUB_OUTPUT

      - name: Create Debian package
        id: debian-package
        shell: bash
        if: startsWith(matrix.job.os, 'ubuntu')
        run: |
          COPYRIGHT_YEARS="2023 - "$(date "+%Y")
          DPKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/debian-package"
          DPKG_DIR="${DPKG_STAGING}/dpkg"
          mkdir -p "${DPKG_DIR}"
          DPKG_BASENAME=${PROJECT_NAME}
          DPKG_CONFLICTS=${PROJECT_NAME}-musl
          case ${{ matrix.job.target }} in *-musl) DPKG_BASENAME=${PROJECT_NAME}-musl ; DPKG_CONFLICTS=${PROJECT_NAME} ;; esac;
          DPKG_VERSION=${PROJECT_VERSION}
          unset DPKG_ARCH
          case ${{ matrix.job.target }} in
            aarch64-*-linux-*) DPKG_ARCH=arm64 ;;
            arm-*-linux-*hf) DPKG_ARCH=armhf ;;
            i686-*-linux-*) DPKG_ARCH=i686 ;;
            x86_64-*-linux-*) DPKG_ARCH=amd64 ;;
            *) DPKG_ARCH=notset ;;
          esac;
          DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb"
          echo "DPKG_NAME=${DPKG_NAME}" >> $GITHUB_OUTPUT
          # Binary
          install -Dm755 "${{ steps.strip.outputs.BIN_PATH }}" "${DPKG_DIR}/usr/bin/${{ steps.strip.outputs.BIN_NAME }}"
          # Man page
          install -Dm644 'man/${{ env.PROJECT_NAME }}.1' "${DPKG_DIR}/usr/share/man/man1/${{ env.PROJECT_NAME }}.1"
          gzip -n --best "${DPKG_DIR}/usr/share/man/man1/${{ env.PROJECT_NAME }}.1"
          # Autocompletion files
          install -Dm644 completions/'${{ env.PROJECT_NAME }}.bash' "${DPKG_DIR}/usr/share/bash-completion/completions/${{ env.PROJECT_NAME }}"
          install -Dm644 completions/'${{ env.PROJECT_NAME }}.fish' "${DPKG_DIR}/usr/share/fish/vendor_completions.d/${{ env.PROJECT_NAME }}.fish"
          install -Dm644 completions/'_${{ env.PROJECT_NAME }}' "${DPKG_DIR}/usr/share/zsh/vendor-completions/_${{ env.PROJECT_NAME }}"
          # README and LICENSE
          install -Dm644 "README.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/README.md"
          install -Dm644 "LICENSE-MIT" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-MIT"
          install -Dm644 "LICENSE-APACHE" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-APACHE"
          install -Dm644 "CHANGELOG.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/changelog"
          gzip -n --best "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/changelog"
          cat > "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright" <<EOF
          Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
          Upstream-Name: ${{ env.PROJECT_NAME }}
          Source: ${{ env.PROJECT_HOMEPAGE }}
          Files: *
          Copyright: ${{ env.PROJECT_MAINTAINER }}
          Copyright: $COPYRIGHT_YEARS ${{ env.PROJECT_MAINTAINER }}
          License: Apache-2.0 or MIT
          License: Apache-2.0
            On Debian systems, the complete text of the Apache-2.0 can be found in the
            file /usr/share/common-licenses/Apache-2.0.
          License: MIT
            Permission is hereby granted, free of charge, to any
            person obtaining a copy of this software and associated
            documentation files (the "Software"), to deal in the
            Software without restriction, including without
            limitation the rights to use, copy, modify, merge,
            publish, distribute, sublicense, and/or sell copies of
            the Software, and to permit persons to whom the Software
            is furnished to do so, subject to the following
            conditions:
            .
            The above copyright notice and this permission notice
            shall be included in all copies or substantial portions
            of the Software.
            .
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
            ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
            TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
            PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
            SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
            CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
            OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
            IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
            DEALINGS IN THE SOFTWARE.
          EOF
            chmod 644 "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright"
            # control file
            mkdir -p "${DPKG_DIR}/DEBIAN"
            cat > "${DPKG_DIR}/DEBIAN/control" <<EOF
          Package: ${DPKG_BASENAME}
          Version: ${DPKG_VERSION}
          Section: utils
          Priority: optional
          Maintainer: ${{ env.PROJECT_MAINTAINER }}
          Homepage: ${{ env.PROJECT_HOMEPAGE }}
          Architecture: ${DPKG_ARCH}
          Provides: ${{ env.PROJECT_NAME }}
          Conflicts: ${DPKG_CONFLICTS}
          Description: A command-line benchmarking tool
          EOF
          DPKG_PATH="${DPKG_STAGING}/${DPKG_NAME}"
          echo "DPKG_PATH=${DPKG_PATH}" >> $GITHUB_OUTPUT
          # build dpkg
          fakeroot dpkg-deb --build "${DPKG_DIR}" "${DPKG_PATH}"

      - name: Set path for candle and light
        shell: bash
        if: startsWith(matrix.job.os, 'windows')
        run: echo "C:\Program Files (x86)\WiX Toolset v3.11\bin" >> $GITHUB_PATH

      - name: Build Windows Installer
        id: msi-installer
        shell: bash
        if: startsWith(matrix.job.os, 'windows')
        run: |
          cargo install cargo-wix
          cargo wix init
          cargo wix --target ${{ matrix.job.target }}

          PKG_NAME=${PROJECT_NAME}-${PROJECT_VERSION}-${{ matrix.job.arch }}.msi

          echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT
          echo "PKG_PATH=target/wix/${PKG_NAME}" >> $GITHUB_OUTPUT


      - name: "Artifact upload: tarball"
        uses: actions/upload-artifact@master
        with:
          name: ${{ steps.package.outputs.PKG_NAME }}
          path: ${{ steps.package.outputs.PKG_PATH }}

      - name: "Artifact upload: Windows installer"
        uses: actions/upload-artifact@master
        if: steps.msi-installer.outputs.PKG_NAME
        with:
          name: ${{ steps.msi-installer.outputs.PKG_NAME }}
          path: ${{ steps.msi-installer.outputs.PKG_PATH }}

      - name: "Artifact upload: Debian package"
        uses: actions/upload-artifact@master
        if: steps.debian-package.outputs.DPKG_NAME
        with:
          name: ${{ steps.debian-package.outputs.DPKG_NAME }}
          path: ${{ steps.debian-package.outputs.DPKG_PATH }}

      - name: Check for release
        id: is-release
        shell: bash
        run: |
          unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/v[0-9].* ]]; then IS_RELEASE='true' ; fi
          echo "IS_RELEASE=${IS_RELEASE}" >> $GITHUB_OUTPUT

      - name: Publish archives and packages
        uses: softprops/action-gh-release@v1
        if: steps.is-release.outputs.IS_RELEASE
        with:
          files: |
            ${{ steps.package.outputs.PKG_PATH }}
            ${{ steps.msi-installer.outputs.PKG_PATH }}
            ${{ steps.debian-package.outputs.DPKG_PATH }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}