Skip to content

revert "chore(rc): mark source code Sem Ver as '-rc', Release Candidate" #1245

revert "chore(rc): mark source code Sem Ver as '-rc', Release Candidate"

revert "chore(rc): mark source code Sem Ver as '-rc', Release Candidate" #1245

Workflow file for this run

name: CI/CD Pipeline
# Continuous Integration / Continuous Delivery
# Triggers on all branches and tags starting with v
### Full Job Matrix for Stress Testing on: ###
# - tags v*
# - the 'stress-test' branch (GITHUB_REF_NAME == 'stress-test')
### PyPI publish on: ###
# - v* tags on 'master' branch only
## Test PyPI publish on: ##
# - v*-rc 'pre-release' tags on 'release' branch
### Dockerhub publish on ###
# - all branches and tags
on:
push:
branches:
- "*"
tags:
- v*
env:
### STRESS TEST Job MATRIX ###
FULL_MATRIX_STRATEGY: "{\"platform\": [\"ubuntu-latest\", \"macos-latest\", \"windows-latest\"], \"python-version\": [\"3.7\", \"3.8\", \"3.9\", \"3.10\", \"3.11\"]}"
# Python 3.7 has reached End of Life (EOL) on June 27th, 2023
# Python 3.12 is in bugfix mode, same as 3.11 -> can start supporting 3.12 it
UBUNTU_PY310_STRATEGY: "{\"platform\":[\"ubuntu-latest\"], \"python-version\":[\"3.10\"]}"
TEST_STRATEGY: "{\"platform\":[\"ubuntu-latest\", \"macos-latest\", \"windows-latest\"], \"python-version\":[\"3.9\"]}"
##### JOB ON/OFF SWITCHES #####
RUN_UNIT_TESTS: "true"
RUN_LINT_CHECKS: "true"
DOCKER_JOB_ON: "true"
PUBLISH_ON_PYPI: "true"
DRAW_DEPENDENCIES: "true"
###############################
### DOCKER Job Policy ####
# Override Docker Policy-dependent decision-making and
# Accept any ALL (branch/build) to Publish to Dockerhub
# if true, it will push image and ignore DOCKER_JOB_POLICY
ALWAYS_BUILD_N_PUBLSIH_DOCKER: "false"
DOCKER_JOB_POLICY: "CDeployment"
# - CDeployment : Builds and Publishes only if Tests ran and passed
# - CDelivery : Builds and Publishes if Tests Passed or if Tests were Skipped
############################
#### STATIC CODE ANALYSIS Job ####
ALWAYS_LINT: "false"
LINT_JOB_POLICY: '2' # {2, 3}
## Python Runtime version to set the Job runner with ##
STATIC_ANALYSIS_PY: "3.10"
## Pylint Minimum Acceptance Rating/Score ##
PYLINT_SCORE_THRESHOLD: "8.2"
#### CODE VISUALIZATION Job ####
ALWAYS_CODE_VIZ: "false"
CODE_VIZ_POLICY: '2' # {2, 3}
##########################
jobs:
# we use the below to read the workflow env vars and be able to use in "- if:" Job conditionals
# now we can do -> if: ${{ needs.set_github_outputs.outputs.TESTS_ENABLED == 'true' }}
# github does not have a way to simply do "- if: ${{ env.RUN_UNIT_TESTS == 'true' }} " !!
set_github_outputs:
name: Read Workflow Env Section Vars and set Github Outputs
runs-on: ubuntu-latest
steps:
- name: Pass 'env' section variables to GITHUB_OUTPUT
id: pass-env-to-output
env:
BOARDING_EVENT: 'do Boarding CI Tests'
run: |
# set the matrix strategy to Full Matrix Stress Test if on master/main or stress-test branch or any tag
BRANCH_NAME=${GITHUB_REF_NAME}
if [[ $BRANCH_NAME == "stress-test" || $GITHUB_REF == refs/tags/* ]]; then
echo "matrix=$FULL_MATRIX_STRATEGY" >> $GITHUB_OUTPUT
# github.event.head_commit.message has 'do Boarding CI Tests' string
elif [[ "${{ contains(github.event.head_commit.message, env.BOARDING_EVENT) }}" == 'true' ]]; then
echo "matrix=$TEST_STRATEGY" >> $GITHUB_OUTPUT
else
echo "matrix=$UBUNTU_PY310_STRATEGY" >> $GITHUB_OUTPUT
fi
echo "TESTS_ENABLED=$RUN_UNIT_TESTS" >> $GITHUB_OUTPUT
echo "PUBLISH_ON_PYPI=$PUBLISH_ON_PYPI" >> $GITHUB_OUTPUT
## Docker - Pipeline Settings ##
- id: derive_docker_policy
run: echo "POL=${{ (env.DOCKER_JOB_ON != 'true' && '0') || (env.ALWAYS_BUILD_N_PUBLSIH_DOCKER == 'true' && '1') || (env.DOCKER_JOB_POLICY == 'CDeployment' && '2') || (env.DOCKER_JOB_POLICY == 'CDelivery' && '3') }}" >> $GITHUB_OUTPUT
## Static Code Analysis - Pipeline Settings ##
- id: derive_sqa_policy
run: echo "POL=${{ (env.RUN_LINT_CHECKS != 'true' && '0') || (env.ALWAYS_LINT == 'true' && '1') || env.LINT_JOB_POLICY }}" >> $GITHUB_OUTPUT
- id: read_sqa_py
run: echo SQA_PY=${{ env.STATIC_ANALYSIS_PY }} >> $GITHUB_OUTPUT
- id: read_pylint_score_threshold
run: echo PYLINT_SCORE_THRESHOLD=${{ env.PYLINT_SCORE_THRESHOLD }} >> $GITHUB_OUTPUT
## Code Visualization - Pipeline Settings ##
- id: derive_code_viz_policy
run: echo "POL=${{ (env.DRAW_DEPENDENCIES != 'true' && '0') || (env.ALWAYS_CODE_VIZ == 'true' && '1') || env.CODE_VIZ_POLICY }}" >> $GITHUB_OUTPUT
outputs:
matrix: ${{ steps.pass-env-to-output.outputs.matrix }}
TESTS_ENABLED: ${{ steps.pass-env-to-output.outputs.TESTS_ENABLED }}
PUBLISH_ON_PYPI: ${{ steps.pass-env-to-output.outputs.PUBLISH_ON_PYPI }}
## Docker - Pipeline Settings ##
PIPE_DOCKER_POLICY: ${{ steps.derive_docker_policy.outputs.POL }}
## Static Code Analysis - Pipeline Settings ##
PIPE_SQA_POLICY: ${{ steps.derive_sqa_policy.outputs.POL }}
PIPE_SQA_PY: ${{ steps.read_sqa_py.outputs.SQA_PY }}
PIPE_SQA_PYLINT_PASS_SCORE: ${{ steps.read_pylint_score_threshold.outputs.PYLINT_SCORE_THRESHOLD }}
## Code Visualization - Pipeline Settings ##
PIPE_CODE_VIZ_POLICY: ${{ steps.derive_code_viz_policy.outputs.POL }}
# RUN TEST SUITE ON ALL PLATFORMS
test_suite:
runs-on: ${{ matrix.platform }}
needs: set_github_outputs
if: ${{ needs.set_github_outputs.outputs.TESTS_ENABLED == 'true' }}
strategy:
matrix: ${{fromJSON(needs.set_github_outputs.outputs.matrix)}}
outputs:
SEMVER_PIP_FORMAT: ${{ steps.parse_version.outputs.SEMVER_PIP_FORMAT }}
steps:
- run: echo "Platform -> ${{ matrix.platform }} , Python -> ${{ matrix.python-version }}"
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- run: python -m pip install --upgrade pip && python -m pip install tox==3.28 tox-gh-actions
- name: Do Type Checking
run: tox -e type -vv -s false
- name: Parse package version from __init__.py to assist building
shell: bash
id: parse_version
run: |
PARSER="src/cookiecutter_python/{{ cookiecutter.project_slug }}/scripts/parse_version.py"
PARSED_VERSION=$(python "${PARSER}")
# transform version (ie 1.7.4-rc.1) to match the name of the wheel produced (ie 1.7.4rc1)
WHEEL_VERSION=$(echo $PARSED_VERSION | sed -E 's/([^.]*)\.([^.]*)\.([^-]*)-(rc)\.?(.*)/\1.\2.\3\4\5/')
# manually append the 0 to index the release candidate
# we account for wheel building that automatically does the above
last_two=${WHEEL_VERSION: -2}
if [[ $last_two == "rc" ]]; then
WHEEL_VERSION="${WHEEL_VERSION}0"
fi
echo "==== $PARSED_VERSION --> $WHEEL_VERSION"
echo "PKG_VERSION=$WHEEL_VERSION" >> $GITHUB_ENV # to be used in the next step
echo "SEMVER_PIP_FORMAT=$WHEEL_VERSION" >> $GITHUB_OUTPUT # to be used in other jobs
###### TEST SUITE RUN ######
- name: Run Unit Tests
run: tox -vv -s false
env:
PLATFORM: ${{ matrix.platform }}
## Code Coverage ##
- name: "Combine Coverage (dev, sdist, wheel) & make Reports"
run: tox -e coverage --sitepackages -vv -s false
- name: Rename Coverage Files
shell: bash
run: |
mv ./.tox/coverage.xml ./coverage-${{ matrix.platform }}-${{ matrix.python-version }}.xml
- name: "Upload Test Coverage as Artifacts"
uses: actions/upload-artifact@v3
with:
name: all_coverage_raw
path: coverage-${{ matrix.platform }}-${{ matrix.python-version }}.xml
if-no-files-found: error
- name: Check for compliance with Python Best Practices
shell: bash
run: |
DIST_DIR=dist
echo "DIST_DIR=dist" >> $GITHUB_ENV
mkdir ${DIST_DIR}
mv ".tox/${DIST_DIR}/cookiecutter_python-${PKG_VERSION}.tar.gz" "${DIST_DIR}"
mv ".tox/${DIST_DIR}/cookiecutter_python-${PKG_VERSION}-py3-none-any.whl" "${DIST_DIR}"
tox -e check -vv -s false
- name: Upload Source & Wheel distributions as Artefacts
uses: actions/upload-artifact@v3
with:
name: dist-${{ matrix.platform }}-${{ matrix.python-version }}
path: ${{ env.DIST_DIR }}
if-no-files-found: error
codecov_coverage_host:
runs-on: ubuntu-latest
needs: test_suite
steps:
- uses: actions/checkout@v3
- name: Get Codecov binary
run: |
curl -Os https://uploader.codecov.io/latest/linux/codecov
chmod +x codecov
- name: Download Raw Coverage Data Artefacts
uses: actions/download-artifact@v3
with:
name: all_coverage_raw
- name: Upload Coverage Reports to Codecov
run: |
for file in coverage*.xml; do
OS_NAME=$(echo $file | sed -E "s/coverage-(\w\+)-/\1/")
PY_VERSION=$(echo $file | sed -E "s/coverage-\w\+-(\d\.)\+/\1/")
./codecov -f $file -e "OS=$OS_NAME,PYTHON=$PY_VERSION" --flags unittests --verbose
echo "Sent to Codecov: $file !"
done
## DOCKER BUILD and PUBLISH ON DOCKERHUB ##
docker_build:
needs: [set_github_outputs, test_suite]
uses: boromir674/automated-workflows/.github/workflows/[email protected]
if: always()
with:
acceptance_policy: ${{ needs.set_github_outputs.outputs.PIPE_DOCKER_POLICY }}
image_slug: "generate-python"
# target_stage: "some_stage_alias" # no stage, means no `--target` flag, on build
tests_pass: ${{ needs.test_suite.result == 'success' }}
tests_run: ${{ !contains(fromJSON('["skipped", "cancelled"]'), needs.test_suite.result) }}
DOCKER_USER: ${{ vars.DOCKER_USER }}
secrets:
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
## JOB: Signal for Automated PyPI Upload ##
check_which_git_branch_we_are_on:
runs-on: ubuntu-latest
needs: set_github_outputs
if: ${{ startsWith(github.event.ref, 'refs/tags/v') && needs.set_github_outputs.outputs.PUBLISH_ON_PYPI == 'true' }}
# Signals only if all below are True:
# - PyPI Job Switch is ON
# - Workflow Event is a 'v*' Tag (e.g. v1.0.0, v-test)
# - Tag is tagging a commit on either the 'master' or 'release' Branch
env:
RELEASE_BR: 'release'
MAIN_BR: 'master'
steps:
# Fetch 'master' and 'release' branches
- uses: actions/checkout@v3
with:
fetch-depth: 0
- run: git branch --track "${{ env.RELEASE_BR }}" "origin/${{ env.RELEASE_BR }}"
- name: "Check if '${{ github.ref }}' tag is on '${{ env.MAIN_BR }}' branch"
uses: rickstaa/action-contains-tag@v1
id: main_contains_tag
with:
reference: ${{ env.MAIN_BR }}
tag: "${{ github.ref }}"
- name: "Check if '${{ github.ref }}' tag is on '${{ env.RELEASE_BR }}' branch"
uses: rickstaa/action-contains-tag@v1
id: release_contains_tag
with:
reference: ${{ env.RELEASE_BR }}
tag: "${{ github.ref }}"
- name: Pick Production or Test Environment, if tag on master or release branch respectively
id: set_environment_name
run: |
DEPLOY=true
if [[ "${{ steps.main_contains_tag.outputs.retval }}" == "true" ]]; then
echo "ENVIRONMENT_NAME=PROD_DEPLOYMENT" >> $GITHUB_OUTPUT
elif [[ "${{ steps.release_contains_tag.outputs.retval }}" == "true" ]]; then
echo "ENVIRONMENT_NAME=TEST_DEPLOYMENT" >> $GITHUB_OUTPUT
else
echo "A tag was pushed but not on master or release branch. No deployment will be done."
DEPLOY=false
fi
echo "AUTOMATED_DEPLOY=$DEPLOY" >> $GITHUB_OUTPUT
outputs:
ENVIRONMENT_NAME: ${{ steps.set_environment_name.outputs.ENVIRONMENT_NAME }}
AUTOMATED_DEPLOY: ${{ steps.set_environment_name.outputs.AUTOMATED_DEPLOY }}
TAG_ON_MASTER: ${{ steps.main_contains_tag.outputs.retval }}
## JOB: PYPI UPLOAD ##
pypi_publish:
needs: [test_suite, check_which_git_branch_we_are_on]
if: always()
uses: boromir674/automated-workflows/.github/workflows/pypi_env.yml@8e97f596067fcbbaa0a6927ec1ee47dce4ab5f1a
with:
should_trigger: ${{ needs.check_which_git_branch_we_are_on.outputs.AUTOMATED_DEPLOY == 'true' }}
distro_name: cookiecutter_python
distro_version: ${{ needs.test_suite.outputs.SEMVER_PIP_FORMAT }}
pypi_env: '${{ needs.check_which_git_branch_we_are_on.outputs.ENVIRONMENT_NAME }}'
artifacts_path: downloaded-artifacts
require_wheel: true
allow_existing: true
secrets:
TWINE_PASSWORD: ${{ secrets.TWINE_PASSWORD }}
### STATIC CODE ANALYSIS & LINTING ###
lint:
name: Static Code Analysis
needs: set_github_outputs
uses: ./.github/workflows/policy_lint.yml
with:
run_policy: ${{ needs.set_github_outputs.outputs.PIPE_SQA_POLICY }}
dedicated_branches: 'master, main, dev'
source_code_targets: 'src,tests,scripts'
python_version: ${{ needs.set_github_outputs.outputs.PIPE_SQA_PY }}
pylint_threshold: ${{ needs.set_github_outputs.outputs.PIPE_SQA_PYLINT_PASS_SCORE }}
### DRAW PYTHON DEPENDENCY GRAPHS ###
code_visualization:
needs: set_github_outputs
name: Code Visualization of Python Imports as Graphs, in .svg
uses: boromir674/automated-workflows/.github/workflows/python_imports.yml@test
with:
run_policy: '${{ needs.set_github_outputs.outputs.PIPE_CODE_VIZ_POLICY }}'
branches: 'main, master, dev'
source_code_targets: 'src'
python_version: '3.10'
artifacts_dir: 'dependency-graphs'