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
6 changes: 3 additions & 3 deletions .github/workflows/build-test-distribute.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ name: Build Test Distribute

# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the master branch
# Triggers the workflow on push or pull request events for master and release branches
push:
branches: [ master ]
branches: [ master, 'release/**' ]
pull_request:
branches: [ master ]
branches: [ master, 'release/**' ]
Comment on lines +7 to +9

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mb make the rule more strict?


# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand Down
31 changes: 23 additions & 8 deletions .github/workflows/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,10 @@ on:
value: ${{ github.event_name == 'schedule' || jobs.prepare-config.outputs.tag-full-ci == 'true' || jobs.prepare-config.outputs.tag-build-release-windows == 'true' }}
test_pip_build:
description:
value: ${{ jobs.prepare-config.outputs.tag-test-pip-build == 'true' }}
value: ${{ jobs.prepare-config.outputs.tag-test-pip-build == 'true' || ( github.event_name == 'push' && startsWith(github.ref_name, 'release/') ) }}
build-release-win:
description: "True when full-ci, scheduled, or tag-build-release-windows is set"
value: ${{ github.event_name == 'schedule' || jobs.prepare-config.outputs.tag-full-ci == 'true' || jobs.prepare-config.outputs.tag-build-release-windows == 'true' }}
description: "True when full-ci, scheduled, tag-build-release-windows is set, or on a release branch"
value: ${{ github.event_name == 'schedule' || jobs.prepare-config.outputs.tag-full-ci == 'true' || jobs.prepare-config.outputs.tag-build-release-windows == 'true' || ( github.event_name == 'push' && startsWith(github.ref_name, 'release/') ) }}
# flags for disabling builds for different systems
build_enable_ubuntu_arm64:
description:
Expand Down Expand Up @@ -230,9 +230,13 @@ jobs:
- name: Select Docker image tag
id: select-docker-image-tag
run: |
if [ "${{ github.event_name }}" = "pull_request" ] && [ "${CAN_PUSH_DOCKER_TAGS}" = "true" ]; then
# Only master writes `latest`: a release branch's docker sources freeze
# while master moves on, so it would point master at an older image.
if { [ "${{ github.event_name }}" = "pull_request" ] || \
[ "${{ startsWith(github.ref_name, 'release/') }}" = "true" ] ; } && \
[ "${CAN_PUSH_DOCKER_TAGS}" = "true" ]; then
# https://stackoverflow.com/q/58033366/7325599
IMAGE_TAG=$(echo "${{ github.head_ref }}" | sed -r 's/[^a-zA-Z0-9._-]+/-/g')
IMAGE_TAG=$(echo "${{ github.head_ref || github.ref_name }}" | sed -r 's/[^a-zA-Z0-9._-]+/-/g')
else
IMAGE_TAG="latest"
fi
Expand All @@ -247,8 +251,10 @@ jobs:
- name: Select vcpkg Docker image tag
id: select-vcpkg-docker-image-tag
run: |
if [ "${{ github.event_name }}" = "pull_request" ] && [ "${CAN_PUSH_DOCKER_TAGS}" = "true" ]; then
IMAGE_TAG=$(echo "${{ github.head_ref }}" | sed -r 's/[^a-zA-Z0-9._-]+/-/g')
if { [ "${{ github.event_name }}" = "pull_request" ] || \
[ "${{ startsWith(github.ref_name, 'release/') }}" = "true" ] ; } && \
[ "${CAN_PUSH_DOCKER_TAGS}" = "true" ]; then
IMAGE_TAG=$(echo "${{ github.head_ref || github.ref_name }}" | sed -r 's/[^a-zA-Z0-9._-]+/-/g')
else
IMAGE_TAG="latest"
fi
Expand Down Expand Up @@ -283,7 +289,16 @@ jobs:
id: version-tag
run: |
version=${{ steps.version.outputs.version }}
echo "release_tag=${version}" >> $GITHUB_OUTPUT
# Both lines version off the same baseline, so the same vA.B.C.N comes up
# on each; -rc keeps their tags apart. Publishing drops it.
if [ "${{ github.event_name }}" = "push" ] && \
[ "${{ startsWith(github.ref_name, 'release/') }}" = "true" ] ; then
# %%-* first, so a pr-test namespace can't yield -pr-test-rc
release_tag="${version%%-*}-rc"
else
release_tag="${version}"
fi
echo "release_tag=${release_tag}" >> $GITHUB_OUTPUT
echo "app_version=${version%%-*}" >> $GITHUB_OUTPUT

- name: Set matrix for ubuntu-x64 builds
Expand Down
14 changes: 3 additions & 11 deletions .github/workflows/pip-build.yml
Original file line number Diff line number Diff line change
@@ -1,19 +1,16 @@
name: Build Pip Wheels

# When ran from the github UI, we build the target commit exactly.
# When ran on release, we use the latest tagged commit in the `master` branch.
# This doesn't run directly on pull request, because it's impossible to disable the whole file
# with a single condition (specific label present). Because of that, we conditionally run this from a separate `.yml` file.

on:
release:
types: [ published ]
Comment on lines -9 to -10

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

who runs it?

# This is the manual run from the UI.
workflow_dispatch:
inputs:
vcpkg_docker_image_tag:
# Empty string means the same thing as "latest", but we use an empty string here to ensure this works,
# because `types: [published]` can't have any inputs, so there we are forced to use an empty string, so it needs to work.
# because a `workflow_call` from a release path can't pass inputs, so it needs to work.
default: ""
required: false
type: string
Expand Down Expand Up @@ -95,7 +92,7 @@ jobs:
version_tag: ${{ steps.get-latest-tag.outputs.tag }}
build-matrix: ${{ steps.build-matrix.outputs.matrix }}
test-matrix: ${{ steps.test-matrix.outputs.matrix }}
publish_prod: ${{ github.event_name == 'release' || inputs.publish == 'publish-prod' }}
publish_prod: ${{ inputs.publish == 'publish-prod' }}
publish_test: ${{ inputs.publish == 'publish-test' }}
build_ref: ${{ inputs.ref || steps.get-latest-tag.outputs.tag }}
release_tag: ${{ inputs.release_tag || steps.release-for-ref.outputs.tag }}
Expand All @@ -107,7 +104,7 @@ jobs:
# Disabling this with an `if:` results in `steps.get-latest-tag.outputs.tag` being empty.
# Passing that to `ref:` makes it default to the current commit, which is exactly what we need.
- uses: actions-ecosystem/action-get-latest-tag@v1
if: ${{ github.event_name == 'release' || inputs.publish == 'publish-prod' }}
if: ${{ inputs.publish == 'publish-prod' }}
id: get-latest-tag

# Attach to a release that already exists for this ref; never create one. No match leaves the
Expand Down Expand Up @@ -952,11 +949,6 @@ jobs:
- name: Upload to TestPyPI
run: twine upload --repository-url https://test.pypi.org/legacy/ ./meshlib*.whl -u __token__ -p ${{ secrets.TEST_PYPI_TOKEN }} --skip-existing

post-release-test:
if: ${{ needs.setup.outputs.publish_prod == 'true' }}
needs: [setup, upload-to-release]
uses: MeshInspector/MeshLib/.github/workflows/release-tests.yml@master

delete-artifacts:
timeout-minutes: 5
runs-on: ubuntu-latest
Expand Down
48 changes: 48 additions & 0 deletions .github/workflows/publish-docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
name: Publish documentation

on:
release:
types: [ released ]
workflow_dispatch:
inputs:
release_tag:
description: Tag of the release to publish the documentation of
required: true
type: string

permissions:
contents: read
actions: read # list workflow runs, and download artifacts from another run

jobs:
# The binding artifacts live on the build run, not on the release, and
# `download-artifact` only reaches another run by id.
find-build-run:
timeout-minutes: 5
runs-on: ubuntu-latest
outputs:
run_id: ${{ steps.find.outputs.run_id }}
steps:
- name: Find the build that produced this release
id: find
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ inputs.release_tag || github.event.release.tag_name }}
run: |
set -euo pipefail
sha=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${TAG}" --jq .sha)
run_id=$(
gh api "repos/${GITHUB_REPOSITORY}/actions/workflows/build-test-distribute.yml/runs?head_sha=${sha}&status=success" \
--jq '[ .workflow_runs[] | .id ] | max // empty'
)
[ -n "${run_id}" ] || { echo "no successful build for ${TAG} (${sha})" >&2 ; exit 1 ; }
echo "${TAG} -> ${sha} -> run ${run_id}"
echo "run_id=${run_id}" >> $GITHUB_OUTPUT

update-documentation:
needs: find-build-run
uses: ./.github/workflows/update-docs.yml
with:
output_folder: MeshLib
run_id: ${{ needs.find-build-run.outputs.run_id }}
secrets: inherit
42 changes: 42 additions & 0 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Publish to PyPI

on:
release:
types: [ released ]
workflow_dispatch:
inputs:
release_tag:
description: Tag of the release whose wheels to publish
required: true
type: string

permissions:
contents: read

jobs:
publish:
timeout-minutes: 30
runs-on: ubuntu-latest
steps:
# The wheels attached to the release are the ones that were built and
# tested on that commit; nothing is rebuilt here.
- name: Download wheels from the release
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ inputs.release_tag || github.event.release.tag_name }}
run: |
gh release download "${TAG}" --repo "${GITHUB_REPOSITORY}" --pattern '*.whl' --clobber
ls -1 meshlib*.whl

- name: Install twine
run: python3 -m pip install --upgrade pip twine packaging

- name: Upload to Production PyPi
run: twine upload ./meshlib*.whl -u __token__ -p ${{ secrets.PYPI_MESHINSPECTOR_TOKEN }} --skip-existing

post-release-test:
needs: publish
uses: ./.github/workflows/release-tests.yml
with:
version_tag: ${{ inputs.release_tag || github.event.release.tag_name }}
secrets: inherit
89 changes: 89 additions & 0 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Publish release

# Run it from the release branch whose newest draft should be published.
on:
workflow_dispatch:

permissions:
contents: write

jobs:
publish-release:
timeout-minutes: 10
runs-on: ubuntu-latest
steps:
- name: Publish
shell: bash
env:
GH_TOKEN: ${{ github.token }}
BRANCH: ${{ github.ref_name }}
run: |
set -euo pipefail

series=$(echo "${BRANCH}" | sed -n 's|^release/\([0-9]\{1,\}\.[0-9]\{1,\}\).*|\1|p')
[ -n "${series}" ] || { echo "expected release/<major>.<minor>[...], got '${BRANCH}'" >&2 ; exit 1 ; }

gh api "repos/${GITHUB_REPOSITORY}/releases" --paginate > releases.json

# A draft has no git tag, so GET /releases/tags/<tag> cannot find it.
# The branch's drafts are the -rc ones on its own major.minor series.
drafts=$(
jq -r --arg p "v${series}." '
.[] | select(.draft and (.tag_name | startswith($p) and endswith("-rc")))
| "\(.tag_name)\t\(.id)\t\(.target_commitish)"' releases.json
)
[ -n "${drafts}" ] || { echo "no -rc draft on ${BRANCH}" >&2 ; exit 1 ; }
IFS=$'\t' read -r draft_tag release_id target \
<<< "$(printf '%s\n' "${drafts}" | sort -V | tail -n1)"

version="${draft_tag%-rc}" # v3.1.4.7-rc -> v3.1.4.7
baseline="${version%.*}" # v3.1.4.7 -> v3.1.4
echo "${version}" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' \
|| { echo "unexpected version shape ${version}" >&2 ; exit 1 ; }

sha=$(gh api "repos/${GITHUB_REPOSITORY}/commits/${target}" --jq .sha)

# Guards against tagging a commit the draft was never built from.
status=$(gh api "repos/${GITHUB_REPOSITORY}/compare/${BRANCH}...${sha}" --jq .status)
case "${status}" in
identical|behind) ;;
*) echo "${draft_tag} targets ${sha}, which is ${status} ${BRANCH}" >&2 ; exit 1 ;;
esac

# The baseline tag goes on before publishing: publishing fires the
# release workflows, and they must not see a half-tagged release.
if existing=$(gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/${baseline}" --jq .object.sha 2>/dev/null) ; then
[ "${existing}" = "${sha}" ] \
|| { echo "${baseline} already exists on ${existing}, not ${sha}" >&2 ; exit 1 ; }
echo "${baseline} already points at ${sha}"
else
gh api -X POST "repos/${GITHUB_REPOSITORY}/git/refs" \
-f "ref=refs/tags/${baseline}" -f "sha=${sha}"
fi

# Notes cover this patch only, so diff against the previous release on
# the same line rather than letting GitHub pick one across lines. The
# release being published is still a draft, so it is not a candidate.
previous=$(
jq -r --arg p "v${series}." '.[] | select( ( .draft | not ) and ( .tag_name | startswith($p) ) ) | .tag_name' \
releases.json | sort -V | tail -n1
)
notes=$(
gh api -X POST "repos/${GITHUB_REPOSITORY}/releases/generate-notes" \
-f "tag_name=${version}" -f "target_commitish=${sha}" \
${previous:+-f "previous_tag_name=${previous}"} --jq .body
) || notes=""
echo "notes generated against ${previous:-<no previous release>}"

# Renaming the tag drops the -rc; publishing creates it on ${sha}.
# %details_after_publish% is left for release-body-update.yml.
if [ -n "${notes}" ] ; then
gh api -X PATCH "repos/${GITHUB_REPOSITORY}/releases/${release_id}" \
-f "tag_name=${version}" -F draft=false \
-f "body=${notes}"$'\n\n'"%details_after_publish%"
else
gh api -X PATCH "repos/${GITHUB_REPOSITORY}/releases/${release_id}" \
-f "tag_name=${version}" -F draft=false
fi

echo "published ${version} from ${BRANCH}, baseline ${baseline} -> ${sha}"
Loading