Skip to content

Commit 185b300

Browse files
authored
chore: add CI artifacts and improve build consistency (#290)
fixes #292 prep for #289 Signed-off-by: Jan Kowalleck <jan.kowalleck@gmail.com>
1 parent 1b6e042 commit 185b300

File tree

5 files changed

+196
-34
lines changed

5 files changed

+196
-34
lines changed

.github/workflows/docker.yml

Lines changed: 53 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ on:
1010
workflow_dispatch:
1111

1212
env:
13+
REPORTS_DIR: CI_reports
1314
PYTHON_VERISON: "3.10"
1415
POETRY_VERSION: "1.1.11"
1516

@@ -19,35 +20,79 @@ jobs:
1920
runs-on: ubuntu-latest
2021
timeout-minutes: 30
2122
env:
23+
REPORTS_ARTIFACT: 'docker-image-bom'
2224
DOCKER_TAG: 'cdx-python-testing:${{ github.run_id }}.${{ github.run_number }}.${{ github.run_attempt }}'
2325
steps:
2426
- name: Checkout code
2527
# see https://github.com/actions/checkout
2628
uses: actions/checkout@v2.4.0
2729
with:
2830
fetch-depth: 0
31+
- name: setup reports-dir
32+
run: mkdir "$REPORTS_DIR"
33+
2934
- name: Setup python ${{ env.PYTHON_VERISON }}
3035
# see https://github.com/actions/setup-python
3136
uses: actions/setup-python@v2
3237
with:
3338
python-version: ${{ env.PYTHON_VERISON }}
34-
- name: Install poetry
39+
- name: Setup poetry ${{ env.POETRY_VERSION }}
3540
# see https://github.com/marketplace/actions/setup-poetry
3641
uses: Gr1N/setup-poetry@v7
3742
with:
3843
poetry-version: ${{ env.POETRY_VERSION }}
3944

4045
- name: Poetry build
4146
run: poetry build
42-
- name: get version
43-
run: poetry version -s
47+
- name: Artifact python dist
48+
if: |
49+
!failure() && !cancelled() &&
50+
steps.after-release.outputs.released
51+
# see https://github.com/actions/upload-artifact
52+
uses: actions/upload-artifact@v2
53+
with:
54+
name: ${{ env.RUN_ARTIFACT_PYTHON_DIST }}
55+
path: ${{ env.DIST_SOURCE_DIR }}/
56+
if-no-files-found: warn
4457

45-
- name: Build Docker image
58+
- name: post-hook
59+
id: after-build
4660
run: |
47-
VERSION=`poetry version -s`
48-
docker build -f Dockerfile --build-arg "VERSION=$VERSION" -t "$DOCKER_TAG" .
49-
- name: Test Docker image
50-
run: docker run --rm "$DOCKER_TAG" -h
61+
VERSION="$(poetry version --short --no-interaction --no-ansi)"
62+
echo "::set-output name=version::$VERSION"
63+
64+
- name: Build Docker image
65+
env:
66+
VERSION: ${{ steps.after-build.outputs.version }}
67+
run: >
68+
docker build -f Dockerfile
69+
--build-arg "VERSION=$VERSION"
70+
-t "$DOCKER_TAG"
71+
.
72+
73+
- name: Build own SBoM (XML)
74+
run: >
75+
docker run --rm "$DOCKER_TAG"
76+
--environment
77+
--format=xml
78+
--output=-
79+
> "$REPORTS_DIR/docker-image.bom.xml"
80+
- name: Build own SBoM (JSON)
81+
run: >
82+
docker run --rm "$DOCKER_TAG"
83+
--environment
84+
--format=json
85+
--output=-
86+
> "$REPORTS_DIR/docker-image.bom.json"
87+
- name: Artifact reports
88+
if: ${{ ! cancelled() }}
89+
# see https://github.com/actions/upload-artifact
90+
uses: actions/upload-artifact@v2
91+
with:
92+
name: ${{ env.REPORTS_ARTIFACT }}
93+
path: ${{ env.REPORTS_DIR }}
94+
if-no-files-found: error
95+
5196
- name: Destroy Docker image
5297
# run regardless of outcome
5398
if: ${{ always() }}

.github/workflows/manual-release-candidate.yml

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@ on:
88
required: true
99
type: string
1010

11+
env:
12+
REPORTS_DIR: CI_reports
13+
DIST_DIR: dist
14+
DIST_ARTIFACT: python-dist
15+
PYTHON_VERISON: "3.10"
16+
POETRY_VERSION: "1.1.11"
17+
1118
jobs:
1219
release_candidate:
1320
runs-on: ubuntu-latest
@@ -19,10 +26,10 @@ jobs:
1926
fetch-depth: 0
2027
- uses: actions/setup-python@v2
2128
with:
22-
python-version: 3.9
29+
python-version: ${{ env.PYTHON_VERISON }}
2330
- name: Install dependencies
2431
run: |
25-
python -m pip install poetry --upgrade pip
32+
python -m pip install poetry=="$POETRY_VERSION" --upgrade pip
2633
poetry config virtualenvs.create false
2734
poetry install
2835
python -m pip install python-semantic-release
@@ -32,7 +39,15 @@ jobs:
3239
echo "RC Version will be: ${RC_VERSION}"
3340
poetry version ${RC_VERSION}
3441
poetry build
42+
- name: Artifact python dist
43+
# see https://github.com/actions/upload-artifact
44+
uses: actions/upload-artifact@v2
45+
with:
46+
name: ${{ env.DIST_ARTIFACT }}
47+
path: ${{ env.DIST_DIR }}/
48+
if-no-files-found: error
3549
- name: Publish Pre Release 📦 to PyPI
50+
# see https://github.com/pypa/gh-action-pypi-publish
3651
uses: pypa/gh-action-pypi-publish@master
3752
with:
3853
password: ${{ secrets.PYPI_TOKEN }}

.github/workflows/python.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ on:
2424
pull_request:
2525
push:
2626
tags: [ 'v*.*.*' ] # run again on release tags to have tools mark them
27-
branches: [ 'master']
27+
branches: [ 'master' ]
2828

2929
env:
3030
REPORTS_DIR: CI_reports

.github/workflows/release.yml

Lines changed: 122 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -26,56 +26,155 @@ on:
2626
workflow_dispatch:
2727

2828
env:
29+
REPORTS_DIR: CI_reports
30+
DIST_DIR: dist
31+
DIST_ARTIFACT: python-dist
2932
PYTHON_VERISON: "3.10"
3033
POETRY_VERSION: "1.1.11"
3134

3235
jobs:
33-
release:
36+
release-PyPI:
37+
name: "Release: GitHub, PyPI"
3438
# https://github.community/t/how-do-i-specify-job-dependency-running-in-another-workflow/16482
3539
# limit this to being run on regular commits, not the commits that semantic-release will create
36-
if: github.ref == 'refs/heads/master' && !contains(github.event.head_commit.message, 'chore(release):')
40+
if: |
41+
github.ref == 'refs/heads/master' &&
42+
!contains(github.event.head_commit.message, 'chore(release):')
3743
runs-on: ubuntu-latest
38-
concurrency: release
44+
concurrency: release-PyPI # one release at a time, prevent hickups
45+
outputs:
46+
version-before: ${{ steps.before-release.outputs.version }} # version may be empty
47+
released: ${{ steps.after-release.outputs.released }} # optional bool-ish string
48+
version-after: ${{ steps.after-release.outputs.version }} # version may still be empty
3949
steps:
4050
- name: Checkout code
4151
# see https://github.com/actions/checkout
4252
uses: actions/checkout@v2.4.0
4353
with:
44-
fetch-depth: 0
54+
fetch-depth: 0 # action `relekang/python-semantic-release` requires all git history
4555
- name: Setup python ${{ env.PYTHON_VERISON }}
4656
# see https://github.com/actions/setup-python
4757
uses: actions/setup-python@v2
4858
with:
4959
python-version: ${{ env.PYTHON_VERISON }}
50-
- name: Install poetry
60+
- name: Setup poetry ${{ env.POETRY_VERSION }}
5161
# see https://github.com/marketplace/actions/setup-poetry
5262
uses: Gr1N/setup-poetry@v7
5363
with:
5464
poetry-version: ${{ env.POETRY_VERSION }}
55-
65+
- name: pre-hook
66+
id: before-release
67+
run: |
68+
VERSION="$(poetry version --short --no-interaction --no-ansi)"
69+
# version may be empty at first
70+
echo "::set-output name=version::$VERSION"
5671
- name: Python Semantic Release
72+
id: semantic-release
73+
# see https://python-semantic-release.readthedocs.io/en/latest/automatic-releases/github-actions.html
5774
uses: relekang/python-semantic-release@master
5875
with:
5976
github_token: ${{ secrets.GITHUB_TOKEN }}
6077
pypi_token: ${{ secrets.PYPI_TOKEN }}
61-
62-
- name: Poetry build
63-
run: poetry build
64-
- name: get version
65-
run: poetry version -s
66-
67-
- name: Build Docker Image
68-
env:
69-
REPO: cyclonedx/cyclonedx-python
78+
- name: post-hook
79+
id: after-release
7080
run: |
71-
VERSION=`poetry version -s`
72-
docker build -f Dockerfile --build-arg "VERSION=$VERSION" -t "$REPO:$VERSION" -t "$REPO:latest" .
81+
VERSION="$(poetry version --short --no-interaction --no-ansi)"
82+
# version may still be empty
83+
echo "::set-output name=version::$VERSION"
84+
if [ "$VERSION" != "$VERSION_PRE" ]
85+
then
86+
echo "::set-output name=released::true"
87+
fi
88+
env:
89+
VERSION_PRE: ${{ steps.before-release.outputs.version }}
90+
- name: Artifact python dist
91+
if: |
92+
!failure() && !cancelled() &&
93+
steps.after-release.outputs.released
94+
# see https://github.com/actions/upload-artifact
95+
uses: actions/upload-artifact@v2
96+
with:
97+
name: ${{ env.DIST_ARTIFACT }}
98+
path: ${{ env.DIST_DIR }}/
99+
if-no-files-found: error
100+
# Dist results are required for further processing.
101+
# Therefore, make sure that python-semantic-release is configuret to keep dist.
102+
# see https://python-semantic-release.readthedocs.io/en/latest/configuration.html?highlight=remove_dist#remove-dist
73103

104+
release-DockerHub:
105+
name: "Release: DockerHub"
106+
needs:
107+
- release-PyPI
108+
if: |
109+
!failure() && !cancelled() &&
110+
needs.release-PyPI.result == 'success' &&
111+
needs.release-PyPI.outputs.released &&
112+
needs.release-PyPI.outputs.version-after
113+
runs-on: ubuntu-latest
114+
concurrency: release-DockerHub # because of the 'latest' tag
115+
env:
116+
VERSION: ${{ needs.release-PyPI.outputs.version-after }}
117+
ARTIFACT_DOCKER_SBOM: 'docker-image-bom'
118+
DOCKER_REPO: cyclonedx/cyclonedx-python
119+
steps:
120+
- name: Checkout code (tags/v${{ env.VERSION }})
121+
# see https://github.com/actions/checkout
122+
uses: actions/checkout@v2.4.0
123+
with:
124+
ref: tags/v${{ env.VERSION }}
125+
- name: setup dirs
126+
run: |
127+
mkdir "$REPORTS_DIR"
128+
mkdir "$DIST_DIR"
129+
- name: Fetch python dist artifact
130+
# see https://github.com/actions/download-artifact
131+
uses: actions/download-artifact@v2
132+
with:
133+
name: ${{ env.DIST_ARTIFACT }}
134+
path: ${{ env.DIST_DIR }}/
135+
- name: Build Docker Image (${{ env.VERSION }})
136+
run: >
137+
docker build -f Dockerfile
138+
--build-arg "VERSION=$VERSION"
139+
-t "$DOCKER_REPO:$VERSION"
140+
-t "$DOCKER_REPO:latest"
141+
.
142+
- name: Build own SBoM (XML)
143+
run: >
144+
docker run --rm "$DOCKER_REPO:$VERSION"
145+
--environment
146+
--format=xml
147+
--output=-
148+
> "$REPORTS_DIR/$ARTIFACT_DOCKER_SBOM.bom.xml"
149+
- name: Build own SBoM (JSON)
150+
run: >
151+
docker run --rm "$DOCKER_REPO:$VERSION"
152+
--environment
153+
--format=json
154+
--output=-
155+
> "$REPORTS_DIR/$ARTIFACT_DOCKER_SBOM.bom.json"
156+
- name: Artifact reports
157+
if: ${{ ! cancelled() }}
158+
# see https://github.com/actions/upload-artifact
159+
uses: actions/upload-artifact@v2
160+
with:
161+
name: ${{ env.ARTIFACT_DOCKER_SBOM }}
162+
path: ${{ env.REPORTS_DIR }}/*.bom.*
163+
if-no-files-found: error
164+
# publish AFTER the boms were build, as the bom-generation is kind of a test if the image works
74165
- name: Publish Docker Image(s)
75-
env:
76-
REPO: 'cyclonedx/cyclonedx-python'
77166
run: |
78-
VERSION=`poetry version -s`
79-
docker login --username '${{ secrets.DOCKERHUB_USERNAME }}' --password '${{ secrets.DOCKERHUB_TOKEN }}'
80-
docker push "$REPO:latest"
81-
docker push "$REPO:$VERSION"
167+
docker login --username "$DOCKERHUB_USERNAME" --password "$DOCKERHUB_TOKEN"
168+
docker push "$DOCKER_REPO:$VERSION"
169+
docker push "$DOCKER_REPO:latest"
170+
env:
171+
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
172+
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
173+
# TODO: publish all files in $REPORTS_DIR as release assets - see https://github.com/actions/upload-release-asset
174+
- name: Destroy Docker image
175+
# run regardless of outcome
176+
if: ${{ always() }}
177+
run: >
178+
docker rmi -f
179+
"$DOCKER_REPO:$VERSION"
180+
"$DOCKER_REPO:latest"

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,13 @@ requires = ["poetry-core>=1.0.0"]
4545
build-backend = "poetry.core.masonry.api"
4646

4747
[tool.semantic_release]
48+
# https://python-semantic-release.readthedocs.io/en/latest/configuration.html
4849
version_variable = [
4950
"pyproject.toml:version"
5051
]
5152
branch = "master"
5253
upload_to_pypi = true
54+
upload_to_repository = true
5355
upload_to_release = true
5456
build_command = "pip install poetry && poetry build"
57+
remove_dist = false # dist results required for some CI automation

0 commit comments

Comments
 (0)