Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

hello-world

Reference Python package demonstrating CI/CD with GitHub (PRs), Jenkins, Artifactory, and JFrog Xray.

The application is a small CLI with two subcommands:

  • greet — personalized greetings (casual or formal)
  • stats — text statistics rendered as a Rich table

Versioning uses setuptools-scm from git tags (v1.0.01.0.0). CI is Jenkins-only (no GitHub Actions workflows).

Quick start

python3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest
hello-world greet
hello-world greet --name Alice --style formal
hello-world stats "Hello, CI/CD demo!"
hello-world stats --file README.md
python -m build

Run the full local pipeline (same steps as Jenkins, without publish):

chmod +x scripts/ci.sh
./scripts/ci.sh

With JFrog CLI v2 and credentials:

export JF_URL="https://your-instance.jfrog.io"
export JF_ACCESS_TOKEN="***"
jf scan dist/ --fail          # after ./scripts/ci.sh build, or:
CI_PUBLISH=true BUILD_NUMBER=1 ./scripts/ci.sh

Application

CLI commands

Command Description
hello-world greet Casual greeting (Hello, World!)
hello-world greet --name Alice --style formal Formal greeting
hello-world stats "some text" Word/line/char stats as a table
hello-world stats --file path/to/file Stats from a file
hello-world --version Package version

Architecture

flowchart LR
  subgraph cli [cli.py]
    greetCmd[greet]
    statsCmd[stats]
  end
  subgraph core [package modules]
    greetings[greetings.py]
    textStats[text_stats.py]
    models[models.py]
  end
  greetCmd --> greetings
  statsCmd --> textStats
  textStats --> models
  statsCmd --> richLib[rich]
Loading
Module Role
models.py GreetingStyle enum, TextStats dataclass
greetings.py format_greeting()
text_stats.py analyze_text()
cli.py argparse subcommands and Rich table output

Dependencies

Kind Packages
Runtime rich (formatted CLI output)
Dev (pip install -e ".[dev]") pytest, mypy, ruff, pylint, bandit, build, …

The runtime dependency gives JFrog Xray a real third-party package to scan in built wheels.

Versioning and releases

Git state Example version
Tag v1.0.0 on commit 1.0.0
Commits after last tag 1.0.1.dev3+g1a2b3c4 (illustrative)
PR / feature branch dev version from git describe

Release workflow

  1. Merge changes to main.

  2. Create and push an annotated tag:

    git tag -a v1.0.0 -m "Release 1.0.0"
    git push origin v1.0.0
  3. Jenkins builds the tag, runs tests, jf scan, and publishes wheels to Artifactory.

Troubleshooting setuptools-scm

  • Jenkins checkout must use full history (depth: 0); shallow clones break versioning.
  • Ensure tags are fetched: git fetch --tags.
  • Tag format must match v* (e.g. v1.0.0), configured in pyproject.toml.

Jenkins setup

Multibranch pipeline (GitHub)

  1. New ItemMultibranch Pipeline.
  2. Branch Sources → GitHub → select repository.
  3. Enable Discover pull requests (from origin).
  4. BehaviorsDiscover tags with filter v* (optional: tag build strategy).
  5. Build Configuration → Script Path: Jenkinsfile.

Credentials (JFrog CLI v2)

Create Jenkins credentials (IDs must match Jenkinsfile or update the file):

Credential ID Type Purpose
jf-url Secret text Platform URL (JF_URL)
jf-access-token Secret text Access token (JF_ACCESS_TOKEN)

Optional job environment variable:

Variable Default Purpose
JF_RT_REPO pypi-local Artifactory repository key for uploads

Agents need Python 3.10+, git, and jf (JFrog CLI v2) on PATH for scan/publish stages.

Pipeline stages

The scripted pipeline groups work into these top-level stages:

Stage Contents
Prepare Checkout (full git history + tags), Python venv, pip install -e '.[dev]'
Static Code Analysis isort, flake8, pylint, ruff, mypy, bandit (in parallel), then Analysis Report
Test pytest + Cobertura (coverage.xml) + JUnit
Build python -m build, CLI smoke tests, write version.txt
Release Xray scan (jf scan), Artifactory publish (conditional)
Archive dist/*, logs, coverage, test results

Static analysis tools (run in parallel inside Static Code Analysis):

Tool Purpose
isort import order
flake8 style / pyflakes
pylint lint
ruff fast lint
mypy type check
bandit security

Analysis Report runs recordIssues (Warnings NG) and fails the build if any tool exited non-zero.

Requires Jenkins plugins: Warnings NG (recordIssues), Code Coverage (recordCoverage), JUnit.

Local equivalent: ./scripts/analyse.sh (all tools) or ./scripts/analyse.sh pylint flake8.

Pipeline behavior

Build type Analysis / test / build jf scan jf rt upload
Pull request yes yes (if jf present) no
Feature branch yes yes no
main yes yes yes
Tag v* yes yes yes

Publish runs when IS_RELEASE is true (main or tag) and the build is not a change request (CHANGE_ID unset).

GitHub PR checks

  1. Configure the multibranch job webhook / GitHub App (push + pull_request).
  2. In GitHub branch protection for main, require the Jenkins check (e.g. Jenkins / … / PR-123) before merge.
  3. Opening or updating a PR triggers Jenkins; Xray failures fail the PR build.

Artifactory layout

Upload target (configurable via JF_RT_REPO):

{pypi-local}/hello-world/{version}/
  hello_world-{version}-py3-none-any.whl
  hello_world-{version}.tar.gz

Build info: hello-world / ${BUILD_NUMBER} via jf rt build-publish.

Project layout

├── Jenkinsfile
├── pyproject.toml
├── src/hello_world/
│   ├── cli.py
│   ├── greetings.py
│   ├── models.py
│   └── text_stats.py
├── tests/
└── scripts/ci.sh

License

MIT

About

Dummy Project

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages