Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions .github/workflows/shared-publish-to-maven-versioned.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,15 @@ on:
default: ''

env:
IS_RELEASE: ${{ (inputs.release_type == 'Major' || inputs.release_type == 'Minor' || inputs.release_type == 'Patch') && (github.event.repository.default_branch == github.ref_name ) }}
REPO: ${{ github.event.repository.name }}

jobs:
release:
# The release/pre-release boolean is inlined here (rather than referencing
# steps.checkRelease.outputs.is_release) because job-level expressions are
# evaluated before any step runs. Every other "is this a release?" check
# in this file uses steps.checkRelease.outputs.is_release — keep this in
# sync if the condition ever changes. See UID2-7069.
name: ${{ ((inputs.release_type == 'Major' || inputs.release_type == 'Minor' || inputs.release_type == 'Patch') && (github.event.repository.default_branch == github.ref_name )) && 'Create Release' || 'Publish Pre-release' }}
runs-on: ubuntu-latest
environment: ${{ inputs.merge_environment }}
Expand Down Expand Up @@ -161,12 +165,14 @@ jobs:

- name: Extract Maven artifactId
id: package_name
if: ${{ steps.checkRelease.outputs.is_release == 'true' }}
run: |
# Maven artifactId comes from pom.xml, not the github repo name
# (e.g. uid2-attestation-azure repo publishes the `attestation-azure`
# artifact). Use `mvn help:evaluate` as the canonical source so
# release-notes install snippets match what `mvn deploy` actually
# published.
# published. Gated on is_release to avoid running on Snapshot builds
# where shared_create_releases is a no-op.
artifact_id=$(mvn -B -f "${{ inputs.working_dir }}/pom.xml" help:evaluate -Dexpression=project.artifactId -q -DforceStdout)
if [ -z "$artifact_id" ]; then
echo "ERROR: could not extract artifactId from ${{ inputs.working_dir }}/pom.xml" >&2
Expand All @@ -178,7 +184,7 @@ jobs:
- name: Create Release
uses: IABTechLab/uid2-shared-actions/actions/shared_create_releases@v3
with:
is_release: ${{ env.IS_RELEASE }}
is_release: ${{ steps.checkRelease.outputs.is_release }}
new_version: ${{ steps.version.outputs.new_version }}
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_platform: Maven
Expand Down
33 changes: 32 additions & 1 deletion .github/workflows/shared-publish-to-nuget-versioned.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,42 @@ jobs:
tag: v${{ steps.version.outputs.new_version }}
github_token: ${{ inputs.merge_environment != '' && secrets.GH_MERGE_TOKEN || '' }}

- name: Install xmllint
if: ${{ steps.checkRelease.outputs.is_release == 'true' }}
run: sudo apt-get update -qq && sudo apt-get install -y -qq libxml2-utils

- name: Extract NuGet package id
id: package_name
if: ${{ steps.checkRelease.outputs.is_release == 'true' }}
run: |
# NuGet package id comes from the <id> element in the .nuspec, not
# the github repo name. Use xmllint's local-name() XPath so we
# ignore the default xmlns the nuspec schema declares. Dependencies
# use an `id` attribute (<dependency id="..."/>), not an <id>
# element, so this XPath matches only the package id.
#
# xmllint (libxml2-utils) is NOT preinstalled on ubuntu-latest as
# of 2026 — installed explicitly in the previous step.
#
# NOTE: the .nuspec file path itself is still hardcoded throughout
# this workflow (UID2.Client.nuspec). Fixing the package id only
# solves half of the single-tenancy problem flagged in UID2-7069 —
# a follow-up should parameterise the .nuspec filename via a
# workflow input.
nuspec="${{ inputs.working_dir }}/UID2.Client.nuspec"
package_id=$(xmllint --xpath 'string(//*[local-name()="package"]/*[local-name()="metadata"]/*[local-name()="id"])' "$nuspec")
if [ -z "$package_id" ]; then
echo "ERROR: could not extract <id> from $nuspec" >&2
exit 1
fi
echo "Extracted NuGet package id: $package_id"
echo "name=$package_id" >> "$GITHUB_OUTPUT"

- name: Create Release
uses: IABTechLab/uid2-shared-actions/actions/shared_create_releases@v3
with:
is_release: ${{ steps.checkRelease.outputs.is_release }}
new_version: ${{ steps.version.outputs.new_version }}
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_platform: NuGet
repo: UID2.Client
repo: ${{ steps.package_name.outputs.name }}
26 changes: 21 additions & 5 deletions .github/workflows/shared-publish-to-pypi-versioned.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,30 @@ jobs:

- name: Extract PyPI package name
id: package_name
if: ${{ steps.checkRelease.outputs.is_release == 'true' }}
run: |
# PyPI package name comes from pyproject.toml, not the github repo name
# (e.g. uid2-client-python repo publishes the `uid2-client` package).
# Read the top-level `name = "..."` field so release-notes install snippets
# match the real PyPI package, not the git repo.
name=$(grep -E '^\s*name\s*=' "${{ inputs.working_dir }}/pyproject.toml" | head -1 | cut -d '"' -f 2)
# (e.g. uid2-client-python repo publishes the `uid2_client` package).
# Use tomllib so we correctly handle both single- and double-quoted
# values, ignore unrelated `name =` keys in earlier tables (e.g.
# dependency tables), and fail fast if [project].name is missing.
# Gated on is_release to avoid running on Snapshot builds where
# shared_create_releases is a no-op.
#
# REQUIRES Python 3.11+ (tomllib is stdlib from 3.11). ubuntu-latest
# currently ships Python 3.12, so this is safe today; if a caller
# ever forks the workflow onto ubuntu-22.04 (Python 3.10), add an
# actions/setup-python step before this one or fall back to `tomli`.
#
# Assumes PEP 621 layout — i.e. the package name lives at
# [project].name. Poetry-style projects with [tool.poetry] would
# need a different key path (e.g. ['tool']['poetry']['name']);
# the KeyError this would raise is loud but unhelpful. No current
# PyPI consumer uses Poetry, so leaving the PEP 621 assumption
# in place.
name=$(python3 -c "import sys, tomllib; print(tomllib.load(open(sys.argv[1], 'rb'))['project']['name'])" "${{ inputs.working_dir }}/pyproject.toml")
if [ -z "$name" ]; then
echo "ERROR: could not extract 'name' from ${{ inputs.working_dir }}/pyproject.toml" >&2
echo "ERROR: could not extract [project].name from ${{ inputs.working_dir }}/pyproject.toml" >&2
exit 1
fi
echo "Extracted PyPI package name: $name"
Expand Down
218 changes: 155 additions & 63 deletions actions/shared_create_releases/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,78 +31,170 @@ runs:
using: "composite"

steps:
- name: Build Docker Changelog
id: github_release_docker
if: ${{ inputs.is_release == 'true' && inputs.publish_platform == 'Docker' }}
uses: mikepenz/release-changelog-builder-action@32e3c96f29a6532607f638797455e9e98cfc703d # v4
with:
toTag: v${{ inputs.new_version }}
fromTag: ${{ inputs.from_tag }}
configurationJson: |
{
"template": "#{{CHANGELOG}}\n## Installation\n```\ndocker pull ${{ inputs.tags }}\n```\n\n## Image reference to deploy: \n```\n${{ inputs.image_tag }}\n```\n\n## Changelog\n#{{UNCATEGORIZED}}",
"pr_template": " - #{{TITLE}} - ( PR: ##{{NUMBER}} )"
}
# Fail fast on a typo in publish_platform. Without this guard, an unknown
# value (e.g. 'docker' lowercase) silently skips every Build Changelog
# step, lets Delete Draft Releases run, and creates a draft release with
# an empty body. See UID2-7069.
#
# Validation is done in bash (case statement) rather than via
# `contains(fromJSON([...]), inputs.publish_platform)` because GitHub
# Actions' contains() is case-INSENSITIVE — `contains(['Docker',...],
# 'docker')` returns true, so the expression form silently lets the
# exact typo we're trying to catch slip through. Bash `case` is
# case-sensitive by default.
#
# Intentionally NOT gated on is_release — typos should be loud on
# Snapshot runs too, so they're caught before someone tries to cut
# a real release with the same misconfiguration.
- name: Validate publish_platform
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.github_token }}
PLATFORM: ${{ inputs.publish_platform }}
run: |
case "$PLATFORM" in
Docker|Maven|PyPI|NuGet|iOS)
;;
*)
echo "::error::Unsupported publish_platform '$PLATFORM'. Must be one of [Docker, Maven, PyPI, NuGet, iOS]."
exit 1
;;
esac

- name: Build Maven Changelog
id: github_release_maven
if: ${{ inputs.is_release == 'true' && inputs.publish_platform == 'Maven' }}
uses: mikepenz/release-changelog-builder-action@32e3c96f29a6532607f638797455e9e98cfc703d # v4
with:
toTag: v${{ inputs.new_version }}
fromTag: ${{ inputs.from_tag }}
configurationJson: |
{
"template": "#{{CHANGELOG}}\n## Maven\n```\n<dependency>\n <groupId>com.uid2</groupId>\n <artifactId>${{ inputs.repo }}</artifactId>\n <version>${{ inputs.new_version }}</version>\n</dependency>\n```\n\n## Jar Files\n- [${{ inputs.repo }}-${{ inputs.new_version }}.jar](https://repo1.maven.org/maven2/com/uid2/${{ inputs.repo }}/${{ inputs.new_version }}/${{ inputs.repo }}-${{ inputs.new_version }}.jar)\n\n## Changelog\n#{{UNCATEGORIZED}}",
"pr_template": " - #{{TITLE}} - ( PR: ##{{NUMBER}} )"
}
# Build the mikepenz configurationJson for the chosen platform. One step
# replaces what used to be five near-identical Build X Changelog steps —
# future changes (mikepenz SHA bump, template tweak) now happen in one
# place. See UID2-7069.
- name: Prepare changelog template
id: changelog_config
if: ${{ inputs.is_release == 'true' }}
shell: bash
env:
GITHUB_TOKEN: ${{ inputs.github_token }}
PLATFORM: ${{ inputs.publish_platform }}
REPO: ${{ inputs.repo }}
VERSION: ${{ inputs.new_version }}
TAGS: ${{ inputs.tags }}
IMAGE_TAG: ${{ inputs.image_tag }}
run: |
# Heredocs use quoted EOF so backticks and $ stay literal — no shell
# expansion inside the template body. We then substitute the four
# placeholders via bash parameter expansion.
#
# Heredoc body lines sit at YAML's common-prefix indent (8 spaces)
# so YAML's literal-block-scalar dedent leaves them flush-left in
# the actual bash script — that's what lets the closing EOF marker
# match. If you re-indent the heredoc body, the heredoc breaks.
case "$PLATFORM" in
Docker)
template=$(cat <<'EOF'
#{{CHANGELOG}}
## Installation
```
docker pull __TAGS__
```

- name: Build PyPI Changelog
id: github_release_pypi
if: ${{ inputs.is_release == 'true' && inputs.publish_platform == 'PyPI' }}
uses: mikepenz/release-changelog-builder-action@32e3c96f29a6532607f638797455e9e98cfc703d # v4
with:
toTag: v${{ inputs.new_version }}
fromTag: ${{ inputs.from_tag }}
configurationJson: |
{
"template": "#{{CHANGELOG}}\n## PyPI\n```\npip install ${{ inputs.repo }}==${{ inputs.new_version }}\n```\n\n## PyPI page\n- [${{ inputs.repo }} ${{ inputs.new_version }}](https://pypi.org/project/${{ inputs.repo }}/${{ inputs.new_version }}/)\n\n## Changelog\n#{{UNCATEGORIZED}}",
"pr_template": " - #{{TITLE}} - ( PR: ##{{NUMBER}} )"
}
env:
GITHUB_TOKEN: ${{ inputs.github_token }}
## Image reference to deploy:
```
__IMAGE_TAG__
```

- name: Build NuGet Changelog
id: github_release_nuget
if: ${{ inputs.is_release == 'true' && inputs.publish_platform == 'NuGet' }}
uses: mikepenz/release-changelog-builder-action@32e3c96f29a6532607f638797455e9e98cfc703d # v4
with:
toTag: v${{ inputs.new_version }}
fromTag: ${{ inputs.from_tag }}
configurationJson: |
{
"template": "#{{CHANGELOG}}\n## NuGet\n```\ndotnet add package ${{ inputs.repo }} --version ${{ inputs.new_version }}\n```\n\n## NuGet page\n- [${{ inputs.repo }} ${{ inputs.new_version }}](https://www.nuget.org/packages/${{ inputs.repo }}/${{ inputs.new_version }})\n\n## Changelog\n#{{UNCATEGORIZED}}",
"pr_template": " - #{{TITLE}} - ( PR: ##{{NUMBER}} )"
}
env:
GITHUB_TOKEN: ${{ inputs.github_token }}
## Changelog
#{{UNCATEGORIZED}}
EOF
)
;;
Maven)
template=$(cat <<'EOF'
#{{CHANGELOG}}
## Maven
```
<dependency>
<groupId>com.uid2</groupId>
<artifactId>__REPO__</artifactId>
<version>__VERSION__</version>
</dependency>
```

## Jar Files
- [__REPO__-__VERSION__.jar](https://repo1.maven.org/maven2/com/uid2/__REPO__/__VERSION__/__REPO__-__VERSION__.jar)

## Changelog
#{{UNCATEGORIZED}}
EOF
)
;;
PyPI)
template=$(cat <<'EOF'
#{{CHANGELOG}}
## PyPI
```
pip install __REPO__==__VERSION__
```

- name: Build iOS Changelog
id: github_release_ios
if: ${{ inputs.is_release == 'true' && inputs.publish_platform == 'iOS' }}
## PyPI page
- [__REPO__ __VERSION__](https://pypi.org/project/__REPO__/__VERSION__/)

## Changelog
#{{UNCATEGORIZED}}
EOF
)
;;
NuGet)
template=$(cat <<'EOF'
#{{CHANGELOG}}
## NuGet
```
dotnet add package __REPO__ --version __VERSION__
```

## NuGet page
- [__REPO__ __VERSION__](https://www.nuget.org/packages/__REPO__/__VERSION__)

## Changelog
#{{UNCATEGORIZED}}
EOF
)
;;
iOS)
template=$(cat <<'EOF'
#{{CHANGELOG}}
## Changelog
#{{UNCATEGORIZED}}
EOF
)
;;
esac

# Placeholder tokens (__TAGS__, __IMAGE_TAG__, __REPO__, __VERSION__)
# are reserved — no input value should contain them. Substitution is
# order-dependent: if e.g. $TAGS expanded to literal `__REPO__`, the
# next line would re-substitute it. All inputs currently come from
# trusted CI sources (docker/metadata-action outputs, semver), so
# this is theoretical. Keep the tokens unique-looking if you add
# more.
template="${template//__TAGS__/$TAGS}"
template="${template//__IMAGE_TAG__/$IMAGE_TAG}"
template="${template//__REPO__/$REPO}"
template="${template//__VERSION__/$VERSION}"

# Compact JSON (single line) keeps the step output value on one line —
# simpler to pass into mikepenz's configurationJson input via a
# GitHub Actions expression (no multi-line $GITHUB_OUTPUT delimiter
# needed downstream).
config=$(jq -nc \
--arg t "$template" \
--arg p ' - #{{TITLE}} - ( PR: ##{{NUMBER}} )' \
'{template: $t, pr_template: $p}')

echo "json=$config" >> "$GITHUB_OUTPUT"

- name: Build changelog
id: changelog
if: ${{ inputs.is_release == 'true' }}
uses: mikepenz/release-changelog-builder-action@32e3c96f29a6532607f638797455e9e98cfc703d # v4
with:
toTag: v${{ inputs.new_version }}
fromTag: ${{ inputs.from_tag }}
configurationJson: |
{
"template": "#{{CHANGELOG}}\n## Changelog\n#{{UNCATEGORIZED}}",
"pr_template": " - #{{TITLE}} - ( PR: ##{{NUMBER}} )"
}
configurationJson: ${{ steps.changelog_config.outputs.json }}
env:
GITHUB_TOKEN: ${{ inputs.github_token }}

Expand All @@ -115,5 +207,5 @@ runs:
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
with:
name: v${{ inputs.new_version }}
body: ${{ inputs.publish_platform == 'Docker' && steps.github_release_docker.outputs.changelog || inputs.publish_platform == 'Maven' && steps.github_release_maven.outputs.changelog || inputs.publish_platform == 'PyPI' && steps.github_release_pypi.outputs.changelog || inputs.publish_platform == 'NuGet' && steps.github_release_nuget.outputs.changelog || steps.github_release_ios.outputs.changelog }}
body: ${{ steps.changelog.outputs.changelog }}
draft: true
Loading