Feature/new versioning (#43) #217
Workflow file for this run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Build | |
on: | |
push: | |
branches: [ develop, release/**, main, feature/**, issue/**, dependabot/** ] | |
workflow_dispatch: | |
env: | |
REGISTRY: ghcr.io | |
IMAGE_NAME: ${{ github.repository }} | |
PYTHON_VERSION: '3.11' | |
POETRY_VERSION: '1.8.5' | |
jobs: | |
build: | |
name: Build, Test, Verify, Publish | |
runs-on: ubuntu-latest | |
permissions: | |
contents: write | |
packages: write | |
outputs: | |
version: ${{ steps.versioning.outputs.new_version }} | |
changes: ${{ steps.check_changes.outputs.changes }} | |
pyproject_name: ${{ steps.versioning.outputs.pyproject_name }} | |
steps: | |
- uses: actions/checkout@v4 | |
with: | |
fetch-depth: 0 # Needed for proper versioning | |
- name: Setup Python and Poetry | |
uses: ./.github/workflows/setup-python-poetry | |
with: | |
python-version: ${{ env.PYTHON_VERSION }} | |
poetry-version: ${{ env.POETRY_VERSION }} | |
- name: Version Management | |
id: versioning | |
run: | | |
# Combine version management logic into a single step | |
pyproject_name=$(poetry version | awk '{print $1}') | |
echo "pyproject_name=${pyproject_name}" >> $GITHUB_OUTPUT | |
echo "pyproject_name=${pyproject_name}" >> $GITHUB_ENV | |
current_version=$(poetry version -s) | |
base_version=$(echo "$current_version" | grep -oE '^[0-9]+\.[0-9]+\.[0-9]+') | |
# Version calculation based on branch | |
if [[ "${{ github.ref }}" =~ ^refs/heads/(issue|feature|dependabot)/ ]]; then | |
new_version="${base_version%%-*}+$(git rev-parse --short HEAD)" | |
elif [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then | |
new_version=$(poetry version prerelease -s) | |
elif [[ "${{ github.ref }}" =~ ^refs/heads/release/ ]]; then | |
if [[ ${current_version} =~ rc ]]; then | |
new_version=$(poetry version prerelease -s) | |
else | |
new_version="${GITHUB_REF#refs/heads/release/}rc1" | |
fi | |
elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then | |
new_version=${base_version} | |
fi | |
poetry version ${new_version} | |
echo "new_version=${new_version}" >> $GITHUB_OUTPUT | |
echo "new_version=${new_version}" >> $GITHUB_ENV | |
echo "old_version=${current_version}" >> $GITHUB_ENV | |
- name: Install Dependencies and Run Tests | |
run: | | |
poetry install | |
poetry run pylint podaac | |
poetry run flake8 podaac | |
poetry run pytest --junitxml=build/reports/pytest.xml --cov=podaac/ --cov-report=html -m "not aws and not integration" tests/ | |
- name: Security Scan | |
uses: snyk/actions/python@master | |
env: | |
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }} | |
with: | |
command: test | |
args: --org=${{ secrets.SNYK_ORG_ID }} --project-name=${{ github.repository }} --severity-threshold=high --fail-on=all | |
- name: Build Package | |
run: poetry build | |
- name: Quick check for changes | |
id: check_changes | |
if: | | |
github.ref == 'refs/heads/develop' || | |
github.ref == 'refs/heads/main' || | |
startsWith(github.ref, 'refs/heads/release') | |
run: | | |
if [ -n "$(git status --porcelain)" ]; then | |
echo "changes=true" >> $GITHUB_OUTPUT | |
else | |
echo "changes=false" >> $GITHUB_OUTPUT | |
fi | |
- name: Commit Version Bump | |
if: steps.check_changes.outputs.changes == 'true' | |
run: | | |
git config user.name "${GITHUB_ACTOR}" | |
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" | |
git commit -am "/version ${{ env.new_version }}" | |
git push | |
- name: Push Tag | |
env: | |
VERSION: ${{ env.new_version }} | |
if: | | |
github.ref == 'refs/heads/develop' || | |
github.ref == 'refs/heads/main' || | |
startsWith(github.ref, 'refs/heads/release') | |
run: | | |
git config user.name "${GITHUB_ACTOR}" | |
git config user.email "${GITHUB_ACTOR}@users.noreply.github.com" | |
git tag -a "${VERSION}" -m "Version ${VERSION}" | |
git push origin "${VERSION}" | |
- name: Create Zip Release | |
run: | | |
ls -al | |
cd terraform | |
ls -al | |
zip -r ../forge-py-terraform-${{ env.new_version }}.zip * | |
- name: Create and Upload Release | |
if: | | |
github.ref == 'refs/heads/develop' || | |
github.ref == 'refs/heads/main' || | |
startsWith(github.ref, 'refs/heads/release') || | |
github.event.head_commit.message == '/deploy sit' || | |
github.event.head_commit.message == '/deploy uat' | |
uses: ncipollo/release-action@v1.14.0 | |
with: | |
tag: ${{ env.new_version }} | |
artifacts: "*.zip" | |
token: ${{ secrets.GITHUB_TOKEN }} | |
makeLatest: ${{ github.ref == 'refs/heads/main' }} | |
prerelease: ${{ github.ref != 'refs/heads/main' }} | |
body: "Version ${{ env.new_version }}" | |
- name: Publish to PyPI | |
if: | | |
github.ref == 'refs/heads/develop' || | |
github.ref == 'refs/heads/main' || | |
startsWith(github.ref, 'refs/heads/release/') | |
env: | |
POETRY_PYPI_TOKEN_PYPI: ${{ secrets.PYPI_API_TOKEN }} | |
POETRY_PYPI_TOKEN_TESTPYPI: ${{ secrets.TEST_PYPI_API_TOKEN }} | |
POETRY_REQUESTS_TIMEOUT: 60 | |
run: | | |
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then | |
poetry publish --skip-existing | |
else | |
poetry config repositories.testpypi https://test.pypi.org/legacy/ | |
poetry publish -r testpypi | |
fi | |
- name: Wait for package | |
if: | | |
github.ref == 'refs/heads/develop' || | |
github.ref == 'refs/heads/main' || | |
startsWith(github.ref, 'refs/heads/release/') | |
id: check_publish | |
run: | | |
pip install tenacity logging | |
python3 ${GITHUB_WORKSPACE}/.github/workflows/wait-for-pypi.py ${{ env.pyproject_name }}==${{ env.new_version }} | |
publish: | |
name: Build & Publish Docker | |
needs: build | |
if: | | |
success() && ( | |
github.ref == 'refs/heads/develop' || | |
github.ref == 'refs/heads/main' || | |
startsWith(github.ref, 'refs/heads/release') || | |
github.event.head_commit.message == '/deploy sit' || | |
github.event.head_commit.message == '/deploy uat' | |
) | |
runs-on: ubuntu-latest | |
permissions: | |
packages: write | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Setup Python and Poetry | |
uses: ./.github/workflows/setup-python-poetry | |
with: | |
python-version: ${{ env.PYTHON_VERSION }} | |
poetry-version: ${{ env.POETRY_VERSION }} | |
- name: Set up QEMU | |
uses: docker/setup-qemu-action@v3 | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@v3 | |
- name: Build Package | |
run: poetry build | |
- name: Set Environment Variables | |
run: | | |
if [[ "${{ github.ref }}" == "refs/heads/develop" ]]; then | |
echo "TARGET_ENV_UPPERCASE=SIT" >> $GITHUB_ENV | |
elif [[ "${{ github.ref }}" =~ ^refs/heads/release/ ]]; then | |
echo "TARGET_ENV_UPPERCASE=UAT" >> $GITHUB_ENV | |
elif [[ "${{ github.ref }}" == "refs/heads/main" ]]; then | |
echo "TARGET_ENV_UPPERCASE=OPS" >> $GITHUB_ENV | |
fi | |
- name: Deploy Env Override | |
if: | | |
github.event.head_commit.message == '/deploy sit' || | |
github.event.head_commit.message == '/deploy uat' | |
run: | | |
message="${{ github.event.head_commit.message }}" | |
trimmed_message=${message:1} # Remove leading slash | |
override_env=$(echo "$trimmed_message" | grep -oE '[^[:space:]]+$') | |
override_env_upper=$(echo "$trimmed_message" | awk '{print toupper($NF)}') | |
echo "TARGET_ENV_UPPERCASE=${override_env_upper}" >> $GITHUB_ENV | |
- name: Lower Case Target Env | |
run: | | |
original_env_value="${TARGET_ENV_UPPERCASE}" | |
lowercase_value=$(echo "${original_env_value}" | tr '[:upper:]' '[:lower:]') | |
echo "TARGET_ENV_LOWERCASE=${lowercase_value}" >> $GITHUB_ENV | |
- name: Extract metadata (tags, labels) for Docker | |
id: meta | |
uses: docker/metadata-action@v5 | |
with: | |
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} | |
flavor: | | |
latest=${{ github.ref == 'refs/heads/main' }} | |
tags: | | |
type=pep440,pattern={{version}},value=${{ needs.build.outputs.version }} | |
type=raw,value=${{ env.TARGET_ENV_LOWERCASE }} | |
- name: Set Build Source | |
id: set-source | |
run: | | |
# Default build source for standard branches | |
echo "SOURCE=${{ needs.build.outputs.pyproject_name }}==${{ needs.build.outputs.version }}" >> $GITHUB_ENV | |
# Override source if deploying (find .whl file in dist/) | |
if [[ "${{ github.event.head_commit.message }}" == "/deploy sit" || | |
"${{ github.event.head_commit.message }}" == "/deploy uat" ]]; then | |
local_forge_py=$(find dist -type f -name "*.whl") | |
echo "SOURCE=${local_forge_py}" >> $GITHUB_ENV | |
echo "DIST_PATH=dist/" >> $GITHUB_ENV | |
fi | |
# Setup docker to build and push images | |
- name: Log in to the Container registry | |
uses: docker/login-action@v3 | |
with: | |
registry: ${{ env.REGISTRY }} | |
username: ${{ github.actor }} | |
password: ${{ secrets.GITHUB_TOKEN }} | |
- name: Build and Push Docker Image | |
uses: docker/build-push-action@v6 | |
with: | |
context: . | |
file: ./docker/lambdaDockerfileArm | |
push: true | |
pull: true | |
tags: ${{ steps.meta.outputs.tags }} | |
labels: ${{ steps.meta.outputs.labels }} | |
platforms: linux/arm64 | |
build-args: | | |
SOURCE=${{ env.SOURCE }} | |
DIST_PATH=${{ env.DIST_PATH || '' }} | |
cache-from: type=registry,ref=ghcr.io/${{ github.repository }}/cache:forge-py-cache | |
cache-to: type=registry,ref=ghcr.io/${{ github.repository }}/cache:forge-py-cache,mode=max |