Skip to content
Open
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
19 changes: 19 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Normalize all text files to LF in the repository.
# Contributors on Windows get CRLF in their working tree via core.autocrlf,
# but the repo itself always stores LF.
* text=auto eol=lf

# Ensure these are always treated as text (LF in repo).
*.py text eol=lf
*.toml text eol=lf
*.yaml text eol=lf
*.yml text eol=lf
*.md text eol=lf
*.sh text eol=lf
*.json text eol=lf

# Binary files — do not normalize.
*.png binary
*.jpg binary
*.gif binary
*.ico binary
67 changes: 67 additions & 0 deletions .github/actions/code-artifact/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
name: CodeArtifact credentials
description: >
Retrieves an authorization token and constructs index/publish URLs for AWS
CodeArtifact. Assumes AWS credentials are already configured in the job.

inputs:
aws_account_id:
description: AWS account ID that owns the CodeArtifact domain.
required: false
default: "505071440022"
aws_region:
description: AWS region where the CodeArtifact repository is hosted.
required: false
default: us-west-2
domain:
description: CodeArtifact domain name.
required: false
default: overture-pypi
repository:
description: CodeArtifact repository name.
required: false
default: overture

outputs:
token:
description: CodeArtifact authorization token (masked in logs).
value: ${{ steps.creds.outputs.token }}
index_url:
description: >
Full index URL with embedded credentials, suitable for
`--index-url` / `--extra-index-url` in pip/uv.
value: ${{ steps.creds.outputs.index_url }}
publish_url:
description: >
Publish endpoint URL (no credentials embedded — pass token separately).
value: ${{ steps.creds.outputs.publish_url }}

runs:
using: composite
steps:
- name: Get CodeArtifact credentials
id: creds
shell: bash
env:
AWS_ACCOUNT_ID: ${{ inputs.aws_account_id }}
AWS_REGION: ${{ inputs.aws_region }}
DOMAIN: ${{ inputs.domain }}
REPOSITORY: ${{ inputs.repository }}
run: |
set -euo pipefail

token=$(aws codeartifact get-authorization-token \
--region "$AWS_REGION" \
--domain "$DOMAIN" \
--domain-owner "$AWS_ACCOUNT_ID" \
--query authorizationToken \
--output text)
echo "::add-mask::${token}"
echo "token=${token}" >> "$GITHUB_OUTPUT"

base_url="https://${DOMAIN}-${AWS_ACCOUNT_ID}.d.codeartifact.${AWS_REGION}.amazonaws.com/pypi/${REPOSITORY}"

index_url="https://aws:${token}@${DOMAIN}-${AWS_ACCOUNT_ID}.d.codeartifact.${AWS_REGION}.amazonaws.com/pypi/${REPOSITORY}/simple/"
echo "::add-mask::${index_url}"
echo "index_url=${index_url}" >> "$GITHUB_OUTPUT"

echo "publish_url=${base_url}" >> "$GITHUB_OUTPUT"
114 changes: 114 additions & 0 deletions .github/actions/compute-version/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
name: Compute package version
description: >
Computes the version string for a package given branch context.

Contexts:
- `vnext`: `<last-published>+dev.<run_number>` (PEP 440 local version).
Falls back to `<major>.<minor>.0+dev.<run_number>` if never published.
Local versions are rejected by PyPI — only suitable for private indexes
like CodeArtifact.
- `main`: `<major>.<minor>.<next-patch>` — increments the highest
published patch for the same major.minor series.
- `main-bump`: `<major>.<minor>.0` — used when a major/minor bump commit
lands on main (patch resets to 0).

Prerequisites: repo must be checked out and `uv` must be available.

inputs:
package:
description: Distribution package name (e.g. overture-schema-common).
required: true
context:
description: >
Branch context controlling the version formula.
Supported values: `vnext`, `main`, `main-bump`.
required: true
index_url:
description: >
PyPI simple index URL with embedded credentials for querying
CodeArtifact. Obtain via the `.github/actions/code-artifact` action's
`index_url` output after configuring AWS credentials.
required: true

outputs:
version:
description: Computed version string (PEP 440).
value: ${{ steps.compute.outputs.version }}

runs:
using: composite
steps:
- name: Compute version
id: compute
shell: bash
env:
PACKAGE: ${{ inputs.package }}
CONTEXT: ${{ inputs.context }}
INDEX_URL: ${{ inputs.index_url }}
RUN_NUMBER: ${{ github.run_number }}
run: |
set -euo pipefail

# --- Read seed version from pyproject.toml ---
SEED=$(cd "packages/${PACKAGE}" && uv version --short)
MAJOR_MINOR=$(echo "$SEED" | grep -oE '^[0-9]+\.[0-9]+')
echo "Seed version for ${PACKAGE}: ${SEED} (major.minor: ${MAJOR_MINOR})"

# --- Query CodeArtifact for the latest published version ---
# uv pip compile resolves the latest matching version from the index.
# We constrain to the current major.minor series for `main` context.
resolve_latest() {
local constraint="$1"
local output
# uv pip compile exits non-zero on network/auth errors; let those surface.
# "Could not find a version" is a normal empty-result — grep returns 1, which is OK.
output=$(echo "$constraint" \
| uv pip compile - --index-url "$INDEX_URL" --no-deps --quiet 2>&1) || {
echo "ERROR: uv pip compile failed for '${constraint}':" >&2
echo "$output" >&2
exit 1
}
echo "$output" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true
}

# --- Compute version based on context ---
case "$CONTEXT" in
vnext)
LATEST=$(resolve_latest "$PACKAGE")
if [ -n "$LATEST" ]; then
BASE="$LATEST"
echo "Latest published version: ${LATEST}"
else
BASE="${MAJOR_MINOR}.0"
echo "No published version found — falling back to ${BASE}"
fi
VERSION="${BASE}+dev.${RUN_NUMBER}"
;;

main)
# Resolve the highest patch within the current major.minor series.
LATEST_IN_SERIES=$(resolve_latest "${PACKAGE}>=${MAJOR_MINOR}.0,<${MAJOR_MINOR}.99999")
if [ -n "$LATEST_IN_SERIES" ]; then
CURRENT_PATCH=$(echo "$LATEST_IN_SERIES" | grep -oE '[0-9]+$')
NEXT_PATCH=$((CURRENT_PATCH + 1))
echo "Latest in ${MAJOR_MINOR}.x series: ${LATEST_IN_SERIES} → next patch: ${NEXT_PATCH}"
else
NEXT_PATCH=0
echo "No published version in ${MAJOR_MINOR}.x series — starting at patch 0"
fi
VERSION="${MAJOR_MINOR}.${NEXT_PATCH}"
;;

main-bump)
VERSION="${MAJOR_MINOR}.0"
echo "Major/minor bump — patch resets to 0"
;;

*)
echo "::error::Unknown context '${CONTEXT}'. Supported: vnext, main, main-bump."
exit 1
;;
esac

echo "Computed version for ${PACKAGE} (${CONTEXT}): ${VERSION}"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
2 changes: 0 additions & 2 deletions .github/workflows/check-python-package-versions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ on:
pull_request:
paths:
- '**/pyproject.toml'
- 'packages/**/__about__.py'

permissions:
contents: read

Expand Down
124 changes: 124 additions & 0 deletions .github/workflows/compute-versions-dry-run.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
name: Compute versions (dry run)

# Runs on pushes to vnext and main. Computes and logs the version that would
# be published for each affected package — but does not build or publish.
# Remove this workflow once Phase 3 publish workflows are live.

on:
push:
branches: [main, vnext]
paths:
- '**/pyproject.toml'
workflow_dispatch:
inputs:
context:
description: "Version context to simulate"
type: choice
options: [vnext, main, main-bump]
default: vnext

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
compute-versions:
name: Compute versions
if: github.event.repository.full_name == github.repository
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for OIDC authentication to AWS

steps:
- name: Install uv
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
with:
version: latest

- name: Check out code
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

- name: Determine context
id: context
env:
INPUT_CONTEXT: ${{ inputs.context }}
REF_NAME: ${{ github.ref_name }}
run: |
if [ -n "$INPUT_CONTEXT" ]; then
echo "value=$INPUT_CONTEXT" >> "$GITHUB_OUTPUT"
elif [ "$REF_NAME" = "vnext" ]; then
echo "value=vnext" >> "$GITHUB_OUTPUT"
else
echo "value=main" >> "$GITHUB_OUTPUT"
fi

- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@d979d5b3a71173a29b74b5b88418bfda9437d885 # v6.1.1
with:
aws-region: us-west-2
role-to-assume: arn:aws:iam::505071440022:role/GithubActions_Schema_CodeArtifact_ReadOnly
role-session-name: GitHubActions_${{github.job}}_${{github.run_id}}

- name: Get CodeArtifact credentials
id: ca
uses: ./.github/actions/code-artifact

- name: Compute version for each package
env:
CONTEXT: ${{ steps.context.outputs.value }}
INDEX_URL: ${{ steps.ca.outputs.index_url }}
run: |
echo "## Computed versions (context: ${CONTEXT})" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "| Package | Version |" >> "$GITHUB_STEP_SUMMARY"
echo "|---------|---------|" >> "$GITHUB_STEP_SUMMARY"

for pkg_dir in packages/overture-schema*/; do
pkg=$(basename "$pkg_dir")
[ -f "${pkg_dir}/pyproject.toml" ] || continue

SEED=$(cd "$pkg_dir" && uv version --short)
MAJOR_MINOR=$(echo "$SEED" | grep -oE '^[0-9]+\.[0-9]+')

# Resolve latest from CA
resolve_latest() {
local output
output=$(echo "$1" \
| uv pip compile - --index-url "$INDEX_URL" --no-deps --quiet 2>&1) || {
echo "ERROR: uv pip compile failed for '$1':" >&2
echo "$output" >&2
exit 1
}
echo "$output" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1 || true
}

case "$CONTEXT" in
vnext)
LATEST=$(resolve_latest "$pkg")
BASE="${LATEST:-${MAJOR_MINOR}.0}"
VERSION="${BASE}+dev.${GITHUB_RUN_NUMBER}"
;;
main)
LATEST_IN_SERIES=$(resolve_latest "${pkg}>=${MAJOR_MINOR}.0,<${MAJOR_MINOR}.99999")
if [ -n "$LATEST_IN_SERIES" ]; then
CURRENT_PATCH=$(echo "$LATEST_IN_SERIES" | grep -oE '[0-9]+$')
NEXT_PATCH=$((CURRENT_PATCH + 1))
else
NEXT_PATCH=0
fi
VERSION="${MAJOR_MINOR}.${NEXT_PATCH}"
;;
main-bump)
VERSION="${MAJOR_MINOR}.0"
;;
esac

echo "| \`${pkg}\` | \`${VERSION}\` |" >> "$GITHUB_STEP_SUMMARY"
echo " ${pkg} → ${VERSION}"
done
12 changes: 2 additions & 10 deletions .github/workflows/publish-python-packages.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ on:
branches: [main]
paths:
- '**/pyproject.toml'
- 'packages/**/__about__.py'
workflow_dispatch:
inputs:
aws_iam_role_name:
Expand Down Expand Up @@ -75,16 +74,9 @@ jobs:
role-to-assume: arn:aws:iam::505071440022:role/GithubActions_Schema_CodeArtifact_Publish
role-session-name: GitHubActions_${{github.job}}_${{github.run_id}}

- name: Get CodeArtifact publish URL
- name: Get CodeArtifact credentials
id: get-code-artifact-params
run: |
token=$(./.github/workflows/scripts/code-artifact.sh token \
505071440022 us-west-2 overture-pypi)
echo "::add-mask::${token}"
echo "token=${token}" >> $GITHUB_OUTPUT
publish_url=$(./.github/workflows/scripts/code-artifact.sh publish-url \
505071440022 us-west-2 overture-pypi overture)
echo "publish_url=${publish_url}" >> $GITHUB_OUTPUT
uses: ./.github/actions/code-artifact

- name: Publish package ${{ matrix.package }} version ${{ matrix.after }} to PyPI
env:
Expand Down
17 changes: 6 additions & 11 deletions .github/workflows/reusable-check-python-package-versions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -133,17 +133,12 @@ jobs:
- name: Get CodeArtifact index URL
id: get-code-artifact-index-url
if: steps.save-changes.outputs.num_changed_packages > 0
env:
AWS_ACCOUNT_ID: ${{ inputs.aws_account_id }}
AWS_REGION: ${{ inputs.aws_region }}
DOMAIN: ${{ inputs.domain }}
REPOSITORY: ${{ inputs.repository }}
run: |
index_url=$(./.github/workflows/scripts/code-artifact.sh index-url \
"$AWS_ACCOUNT_ID" "$AWS_REGION" \
"$DOMAIN" "$REPOSITORY")
echo "::add-mask::${index_url}"
echo "index_url=${index_url}" >> $GITHUB_OUTPUT
uses: ./.github/actions/code-artifact
with:
aws_account_id: ${{ inputs.aws_account_id }}
aws_region: ${{ inputs.aws_region }}
domain: ${{ inputs.domain }}
repository: ${{ inputs.repository }}

- name: Fail if any of the new versions already exist in the repo
if: steps.save-changes.outputs.num_changed_packages > 0
Expand Down
Loading
Loading