Skip to content

Commit bfc8304

Browse files
Chore: Update workflow/actions and bump version (#547)
Signed-off-by: Matthew Watkins <[email protected]>
1 parent eb57911 commit bfc8304

File tree

3 files changed

+270
-4
lines changed

3 files changed

+270
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
---
2+
# SPDX-License-Identifier: Apache-2.0
3+
# SPDX-FileCopyrightText: 2024 The Linux Foundation
4+
5+
# pypi-publish-action
6+
name: "📦 PyPI Publish Package"
7+
description: "Publishes a Python package to PyPI"
8+
9+
inputs:
10+
ENVIRONMENT:
11+
# Environment MUST match the trusted publishing setup in PyPI, if defined
12+
description: "Mandatory environment, e.g. development, production"
13+
type: string
14+
required: false
15+
default: "production"
16+
TAG:
17+
description: "Semantic tag for this release/build"
18+
type: string
19+
required: true
20+
ARTEFACT_PATH:
21+
description: "Path/location for build artefacts"
22+
type: string
23+
required: false
24+
default: "dist"
25+
ONE_PASSWORD_ITEM:
26+
description: "Path to 1Password vault credential for PyPI"
27+
type: string
28+
required: false
29+
OP_SERVICE_ACCOUNT_TOKEN:
30+
description: "1Password service account credential to access vault"
31+
required: false
32+
PYPI_CREDENTIAL:
33+
description: "PyPI API credential from GitHub secrets"
34+
required: false
35+
PUBLISH_DISABLE:
36+
description: "Disables the final publishing step that uploads packages"
37+
type: string
38+
required: false
39+
default: "false"
40+
ATTESTATIONS:
41+
description: "Enables upload/publishing support for attestations"
42+
type: string
43+
required: false
44+
default: "false"
45+
46+
runs:
47+
using: "composite"
48+
steps:
49+
# Need repository content to extract project name
50+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
51+
52+
- name: "Extract project/repository naming"
53+
id: naming
54+
# yamllint disable-line rule:line-length
55+
uses: lfit/releng-reusable-workflows/.github/actions/python-project-name-action@431c4e424c15544f98ec1321f6668f655c238d3a # 2025-02-10
56+
57+
- name: "⬇ Download build artefacts"
58+
uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8
59+
with:
60+
name: ${{ steps.naming.outputs.python_project_name }}
61+
path: ${{ inputs.artefact_path }}
62+
63+
- name: "Derive publishing parameters"
64+
id: parameters
65+
shell: bash
66+
run: |
67+
# Derive publishing parameters
68+
if [ -z ${{ inputs.ENVIRONMENT }} ]; then
69+
echo "Environment was NOT set explicitly ⚠️"
70+
echo "Using production publishing settings"
71+
ENVIRONMENT="production"
72+
else
73+
ENVIRONMENT=$(echo ${{ inputs.ENVIRONMENT }} | tr '[:upper:]' '[:lower:]')
74+
fi
75+
if [ ${{ inputs.ENVIRONMENT }} != "production" ]; then
76+
echo "base_url=https://test.pypi.org" >> "$GITHUB_ENV"
77+
echo "publish_url=https://test.pypi.org/legacy/" >> "$GITHUB_ENV"
78+
else
79+
echo "base_url=https://pypi.org" >> "$GITHUB_ENV"
80+
echo "publish_url=https://upload.pypi.org/legacy/" >> "$GITHUB_ENV"
81+
fi
82+
echo "ENVIRONMENT=$ENVIRONMENT" >> "$GITHUB_ENV"
83+
84+
- name: "Remove unsupported artefact file types"
85+
id: files
86+
shell: bash
87+
run: |
88+
# Remove unsupported artefact file types
89+
if [ ! -d ${{ inputs.artefact_path }} ]; then
90+
echo "Early exit; build artefacts path NOT found: ${{ inputs.artefact_path }}"
91+
exit 0
92+
fi
93+
if [ -f ${{ inputs.artefact_path }}/buildvars.txt ]; then
94+
rm ${{ inputs.artefact_path }}/buildvars.txt
95+
else
96+
echo "No buildvars.txt file to purge"
97+
fi
98+
# Remove outputs related to SigStore signing
99+
if test -n "$(find ${{ inputs.artefact_path }} \
100+
-maxdepth 1 -name '*.sigstore*' -print -quit)"
101+
then
102+
echo "Found SigStore signing artefacts to purge"
103+
rm ${{ inputs.artefact_path }}/*.sigstore*
104+
else
105+
echo "No SigStore signing artefacts to purge"
106+
fi
107+
108+
- name: "Checking package index for build/release"
109+
id: check-remote
110+
# yamllint disable-line rule:line-length
111+
uses: os-climate/osc-github-devops/.github/actions/pypi-version-check-action@main
112+
with:
113+
index_url: ${{ env.base_url }}/simple
114+
package_name: ${{ steps.naming.outputs.python_project_name }}
115+
package_version: ${{ inputs.tag }}
116+
environment: ${{ env.ENVIRONMENT }}
117+
118+
- name: "Determine publishing method"
119+
id: conditions
120+
shell: bash
121+
run: |
122+
# Determine publishing method
123+
if [ "${{ steps.check-remote.outputs.package_match }}" = "true" ]; then
124+
publish_method="Trusted Publishing"
125+
echo "Project previously published; using Trusted Publishing ✅"
126+
fi
127+
128+
if [ "${{ steps.check-remote.outputs.version_match }}" != 'true' ]; then
129+
echo "This build/release has NOT previously been published ✅"
130+
else
131+
echo "This build/release has already been published ❌"
132+
if [ "${{ env.ENVIRONMENT }}" = "production" ]; then
133+
# This is an error for production/tagged releases
134+
echo "This build/release has already been published ❌" >> "$GITHUB_STEP_SUMMARY"
135+
exit 1
136+
else
137+
# Publishing is skipped for non-production workflow runs
138+
publish_method="Skipped"
139+
exit 0
140+
fi
141+
fi
142+
143+
if [ "$publish_method" != "Trusted Publishing" ]; then
144+
echo "Trusted publishing NOT available, using fallback methods 👇🏻"
145+
146+
### 1Password Vault Credential ###
147+
148+
if [ -z "${{ inputs.OP_SERVICE_ACCOUNT_TOKEN }}" ] || \
149+
[ -z "${{ inputs.ONE_PASSWORD_ITEM }}" ]; then
150+
echo "Unable to use 1Password to retrieve publishing key ❌"
151+
echo "Two required parameters MUST be set/available"
152+
echo "Secret: OP_SERVICE_ACCOUNT_TOKEN"
153+
echo "Variable: ONE_PASSWORD_ITEM"
154+
else
155+
echo "Publishing will use 1Password vault ✅"
156+
publish_method="1Password Vault"
157+
fi
158+
159+
### GitHub Secret ###
160+
161+
if [ -z "${{ inputs.PYPI_CREDENTIAL }}" ]; then
162+
echo "GitHub credential NOT set/available: PYPI_CREDENTIAL"
163+
echo "Publishing cannot continue without a valid method ❌"
164+
echo "Publishing cannot continue without a valid method ❌" >> "$GITHUB_STEP_SUMMARY"
165+
exit 1
166+
elif [ "$publish_method" != "1Password Vault" ]; then
167+
echo "Publishing will use GitHub secret ✅"
168+
publish_method="GitHub Secret"
169+
fi
170+
171+
fi
172+
173+
echo "Publishing to: ${{ env.base_url }} [environment: ${{ env.ENVIRONMENT }}]"
174+
echo "publish_method=$publish_method" >> "$GITHUB_ENV"
175+
echo "publish_method=$publish_method" >> "$GITHUB_OUTPUT"
176+
177+
- name: "Publish PyPI [Trusted Publishing]"
178+
# v1.12.x has changed the docker container setup/creation process
179+
# Currently it causes failures, and will need careful testing
180+
# Also, be cautious pinning v1.12.x to a SHA commit value:
181+
# https://github.com/pypa/gh-action-pypi-publish/discussions/287
182+
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
183+
# yamllint disable-line rule:line-length
184+
if: env.publish_method == 'Trusted Publishing' && inputs.publish_disable == 'false'
185+
with:
186+
repository-url: ${{ env.publish_url }}
187+
packages-dir: ${{ inputs.artefact_path }}
188+
# We already validated earlier in the pipeline (twine)
189+
verify-metadata: false
190+
attestations: ${{ inputs.attestations }}
191+
# Show checksum values
192+
print-hash: true
193+
# Optional debugging, pretty much essential for information on failures
194+
verbose: true
195+
196+
- name: "Retrieve Credential [1Password]"
197+
id: one-password-pypi-test
198+
if: env.publish_method == '1Password Vault'
199+
uses: 1password/load-secrets-action@581a835fb51b8e7ec56b71cf2ffddd7e68bb25e0 # v2.0.0
200+
with:
201+
# Export loaded secrets as environment variables
202+
export-env: true
203+
env:
204+
PYPI_CREDENTIAL: ${{ inputs.ONE_PASSWORD_ITEM}}
205+
OP_SERVICE_ACCOUNT_TOKEN: ${{ inputs.OP_SERVICE_ACCOUNT_TOKEN }}
206+
207+
# Used only once prior to trusted publishing being configured
208+
- name: "Publish PyPI [1Password Credential]"
209+
# v1.12.x has changed the docker container setup/creation process
210+
# Currently it causes failures, and will need careful testing
211+
# Also, be cautious pinning v1.12.x to a SHA commit value:
212+
# https://github.com/pypa/gh-action-pypi-publish/discussions/287
213+
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
214+
# yamllint disable-line rule:line-length
215+
if: env.publish_method == '1Password Vault' && inputs.publish_disable == 'false'
216+
with:
217+
repository-url: ${{ env.publish_url }}
218+
packages-dir: ${{ inputs.artefact_path }}
219+
verify-metadata: false
220+
# Credential retrieved from 1Password using service account
221+
password: ${{ env.PYPI_CREDENTIAL}}
222+
attestations: ${{ inputs.attestations }}
223+
print-hash: true
224+
verbose: true
225+
226+
# Fallback method using credential stored as GitHub secret
227+
- name: "Publish PyPI [GitHub Secret]"
228+
# v1.12.x has changed the docker container setup/creation process
229+
# Currently it causes failures, and will need careful testing
230+
# Also, be cautious pinning v1.12.x to a SHA commit value:
231+
# https://github.com/pypa/gh-action-pypi-publish/discussions/287
232+
uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4
233+
if:
234+
# yamllint disable-line rule:line-length
235+
env.publish_method == 'GitHub Secret' && inputs.publish_disable == 'false'
236+
with:
237+
repository-url: ${{ env.publish_url }}
238+
packages-dir: ${{ inputs.artefact_path }}
239+
verify-metadata: false
240+
# Publishing API key stored as secret/variable in GitHub
241+
password: ${{ inputs.PYPI_CREDENTIAL }}
242+
attestations: ${{ inputs.attestations }}
243+
print-hash: true
244+
verbose: true
245+
246+
- name: "Print summary/job output"
247+
shell: bash
248+
# yamllint disable rule:line-length
249+
run: |
250+
# Print summary/job output
251+
if [ "${{ env.publish_disable }}" = "true" ]; then
252+
echo "### Publishing Disabled: Dry Run 🛑" >> "$GITHUB_STEP_SUMMARY"
253+
elif [ "${{ env.publish_method }}" = "Skipped" ]; then
254+
echo "### Publishing Skipped: Previously Released ⛔️" >> "$GITHUB_STEP_SUMMARY"
255+
elif [ ${{ env.base_url }} != "https://pypi.org" ]; then
256+
echo "# 🧪 Test PyPI Release" >> "$GITHUB_STEP_SUMMARY"
257+
else
258+
echo "# 🚀 PyPI Release" >> "$GITHUB_STEP_SUMMARY"
259+
fi
260+
echo "Authenticated using: ${{ env.publish_method }}" >> "$GITHUB_STEP_SUMMARY"
261+
if [ "${{ env.publish_disable }}" != "true" ]; then
262+
echo "🔗 ${{ env.base_url }}/project/${{ steps.naming.outputs.python_project_name }}/${{ inputs.tag }}/" >> "$GITHUB_STEP_SUMMARY"
263+
fi

.github/workflows/release.yaml

+6-3
Original file line numberDiff line numberDiff line change
@@ -114,9 +114,11 @@ jobs:
114114
# Note: environment must be specified at BOTH job level, and input to publish action
115115
environment: development
116116
steps:
117+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
118+
117119
- name: "Test Package Publishing"
118120
# yamllint disable-line rule:line-length
119-
uses: os-climate/osc-github-devops/.github/actions/pypi-publish-action@e40c93a51cc32cbddd4767a75e2209af971df9e0 # 2025-02-25
121+
uses: ./.github/actions/pypi-publish-action # Local copy of upstream 2025-02-25
120122
env:
121123
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
122124
with:
@@ -145,10 +147,11 @@ jobs:
145147
# Note: environment must be specified at BOTH job level, and input to publish action
146148
environment: production
147149
steps:
148-
# Need repository content to extract project name
150+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
151+
149152
- name: "Release to PyPI"
150153
# yamllint disable-line rule:line-length
151-
uses: os-climate/osc-github-devops/.github/actions/pypi-publish-action@e40c93a51cc32cbddd4767a75e2209af971df9e0 # 2025-02-25
154+
uses: ./.github/actions/pypi-publish-action # Local copy of upstream 2025-02-25
152155
env:
153156
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
154157
with:

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "ITR"
3-
version = "v1.1.7"
3+
version = "v1.1.8"
44
description = "Assess the temperature alignment of current targets, commitments, and investment and lending portfolios."
55
authors = [
66
{ name = "Michael Tiemann", email = "[email protected]" },

0 commit comments

Comments
 (0)