Skip to content
53 changes: 53 additions & 0 deletions .github/workflows/manual-republishing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
name: Build & Upload Python Package to Asset

# Controls when the action will run. Workflow runs when manually triggered using the UI
# or API.
on:
workflow_dispatch:

permissions:
contents: write

jobs:
build-n-publish:
name: Build and publish
runs-on: ubuntu-latest

steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: "3.10"
cache: 'pip'

- name: GitHub Tag Name example
run: |
echo "Tag name from GITHUB_REF_NAME: $GITHUB_REF_NAME"
echo "Tag name from github.ref_name: ${{ github.ref_name }}"
echo "Tag name from github.tag_name: ${{ github.tag_name }}"

- name: Install dependencies
run: |
python -m pip install --upgrade pip
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install -U poetry
pip install build

- name: Build package
run: python -m build

#- name: Publish package to PyPI
# uses: pypa/gh-action-pypi-publish@master
# with:
# user: __token__
# password: ${{ secrets.PYPI_API_TOKEN }}

- name: Create and upload release with asset to GitHub
id: upload-release-asset
uses: softprops/action-gh-release@v1
with:
draft: true
generate_release_notes: true
files: dist/*
4 changes: 4 additions & 0 deletions .github/workflows/python-package.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ name: Python package build
on:
push:
branches: [ "main" ]
tags:
- "v*"
pull_request:
branches: [ "dev" ]
tags:
- "v*"

jobs:
build:
Expand Down
45 changes: 39 additions & 6 deletions .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,22 @@
name: Upload Python Package

on:
release:
types: [published]
#release:
# types: [published]
workflow_dispatch:

permissions:
contents: read
contents: write
pull-requests: write
repository-projects: write

jobs:
deploy:

runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkout source
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v4
with:
Expand All @@ -32,10 +36,39 @@ jobs:
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
pip install -U poetry
pip install build

- name: Build package
run: python -m build
- name: Publish package
uses: pypa/gh-action-pypi-publish@27b31702a0e7fc50959f5ad993c78deac1bdfc29

- name: Publish package to PyPI
uses: pypa/gh-action-pypi-publish@master
with:
user: __token__
password: ${{ secrets.PYPI_API_TOKEN }}

#- name: Create GitHub Release
# id: create_release
# uses: actions/create-release@v1
# env:
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token
# with:
# tag_name: ${{ github.ref }}
# release_name: ${{ github.ref }}
# draft: false
# prerelease: false

- name: Get Asset Name
run: |
export PKG=$(ls dist/ | grep whl)
set -- $PKG
echo "name=$1" >> $GITHUB_ENV
- name: Upload Release Asset (whl) to GitHub
id: upload-release-asset
uses: actions/upload-release-asset@v1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
upload_url: ${{ steps.create_release.outputs.upload_url }}
asset_path: dist/${{ env.name }}
asset_name: ${{ env.name }}
asset_content_type: application/zip
43 changes: 36 additions & 7 deletions PySSHHelper/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import logging
import paramiko
import time
from re import Pattern


class SSHConnection:
Expand All @@ -11,7 +12,23 @@ class SSHConnection:
def __init__(self, host: str, port: int, username_ssh: str, password_ssh: str,
username_sudo: str, password_sudo: str, exec_sleep_time: int = 1, ssh_timeout: int = 15,
prompt_shell: str = '$', prompt_sudo: str = '#',
verbose_ssh: bool = False, verbose: bool = False):
verbose_ssh: bool = False, verbose: bool = False) -> object:
"""
Represents interactive SSH shell and SFTP.

:param host: remote server address
:param port: ssh port
:param username_ssh: ssh login
:param password_ssh: shh password for interactive authentication, can be empty if key authentication used
:param username_sudo: login for sudo su - login, can be empty.
:param password_sudo: password for sudo
:param exec_sleep_time: loop sleep time when command executing
:param ssh_timeout: common ssh client timeout.
:param prompt_shell: unprivileged shell prompt symbol.
:param prompt_sudo: privileged shell prompt symbol.
:param verbose_ssh: verbose logging only for ssh connection.
:param verbose: verbose logging.
"""
self.host = host
self.port = port
self.username_ssh = username_ssh
Expand Down Expand Up @@ -75,6 +92,7 @@ def connect(self):
def elevate_privileges(self, prompt_start_timeout: int = 2):
"""
Elevate privileges by sudo su - username command

:param prompt_start_timeout: wait timeout before sudo prompt.
"""
if self.ssh_client:
Expand All @@ -100,14 +118,15 @@ def revoke_privileges(self):
else:
self.logger.warning("Not connected to SSH server")

def execute_command(self, command, buffer_size: int = 65535,
def execute_command(self, command: str, buffer_size: int = 65535,
wait_complete: bool = True, timeout: int = 60) -> str:
"""
:return: all output from console
:rtype: str
:param command: shell command
:param buffer_size: socket buffer size
:param wait_complete: wait shell prompt after command execution
:param timeout: output wait timeout
:return: all output from console
"""
if self.ssh_client:
if not self.ssh_shell:
Expand Down Expand Up @@ -150,13 +169,17 @@ def execute_command(self, command, buffer_size: int = 65535,

@staticmethod
def cleanup_escape_codes(text: str) -> str:
"""Remove escape codes from the text using the pre-compiled pattern"""
"""
Remove escape codes from the text using the pre-compiled pattern
:param text: text string
:return: clean string
"""
clean_text = SSHConnection.ESCAPE_PATTERN.sub('', text)
return clean_text

def sftp_get(self, remote_path, local_path):
"""
Get file from remote server
Get file from remote server
"""
if self.ssh_client:
sftp_client = self.ssh_client.open_sftp()
Expand All @@ -176,9 +199,12 @@ def sftp_put(self, local_path, remote_path):
else:
self.logger.warning("Not connected to SSH server")

def list_directory(self, path: str = '.'):
def list_directory(self, path: str = '.') -> list[str]:
"""
List files in directory path on remote server
List files in a directory path on a remote server
:rtype: list
:param path: path
:return: file list
"""
if self.ssh_client:
sftp_client = self.ssh_client.open_sftp()
Expand All @@ -189,6 +215,9 @@ def list_directory(self, path: str = '.'):
self.logger.warning("Not connected to SSH server")

def close(self):
"""
Close all connections
"""
if self.ssh_client:
self.ssh_client.close()
self.logger.info("Disconnected from SSH server")
Expand Down
Loading