Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
101 changes: 101 additions & 0 deletions .github/workflows/release-tags.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
name: Move release tags

on:
push:
branches:
- main
paths:
- .release-source.json

permissions:
contents: write

jobs:
move-release-tags:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Skip non-release commits
id: release-metadata
run: |
set -euo pipefail

if [[ ! -f .release-source.json ]]; then
echo "release_commit=false" >> "$GITHUB_OUTPUT"
exit 0
fi

version="$(jq -r '.version' .release-source.json)"
if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Invalid release version in .release-source.json: $version"
exit 1
fi

echo "release_commit=true" >> "$GITHUB_OUTPUT"
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "major=${version%%.*}" >> "$GITHUB_OUTPUT"
echo "minor=${version%.*}" >> "$GITHUB_OUTPUT"

- name: Update floating and exact version tags
if: ${{ steps.release-metadata.outputs.release_commit == 'true' }}
env:
VERSION: ${{ steps.release-metadata.outputs.version }}
MAJOR: ${{ steps.release-metadata.outputs.major }}
MINOR: ${{ steps.release-metadata.outputs.minor }}
run: |
set -euo pipefail

git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

git tag -fa "v${VERSION}" -m "Release v${VERSION}"
git tag -fa "v${MINOR}" -m "Release v${MINOR}"
git tag -fa "v${MAJOR}" -m "Release v${MAJOR}"

git push --force origin "refs/tags/v${VERSION}" "refs/tags/v${MINOR}" "refs/tags/v${MAJOR}"
Comment thread
jbeckwith-oai marked this conversation as resolved.

- name: Create or update GitHub release
if: ${{ steps.release-metadata.outputs.release_commit == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
VERSION: ${{ steps.release-metadata.outputs.version }}
run: |
set -euo pipefail

notes_file="$RUNNER_TEMP/release-notes.md"
awk -v version="$VERSION" '
$0 ~ "^## \\[" version "\\]" {
in_section=1
next
}
in_section && /^## \[/ {
exit
}
in_section {
print
}
' CHANGELOG.md > "$notes_file"

if [[ ! -s "$notes_file" ]]; then
printf 'Release v%s\n' "$VERSION" > "$notes_file"
fi

if gh release view "v${VERSION}" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then
gh release edit "v${VERSION}" \
--repo "$GITHUB_REPOSITORY" \
--title "v${VERSION}" \
--notes-file "$notes_file" \
--target "$GITHUB_SHA" \
--verify-tag
else
gh release create "v${VERSION}" \
--repo "$GITHUB_REPOSITORY" \
--title "v${VERSION}" \
--notes-file "$notes_file" \
--target "$GITHUB_SHA" \
--verify-tag
fi
109 changes: 109 additions & 0 deletions .github/workflows/validate-release-pr.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
name: Validate release PR

on:
pull_request:
branches:
- main

permissions:
contents: read

jobs:
validate-release-pr:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0

- name: Validate maintenance PR scope
if: ${{ !startsWith(github.head_ref, 'release/code-scan-action-v') }}
run: |
set -euo pipefail

while IFS= read -r file; do
[[ -z "$file" ]] && continue
if [[ ! "$file" =~ ^\.github/ ]]; then
echo "Maintenance PRs may only change .github/* files. Unexpected file: $file"
exit 1
fi
done < <(git diff --name-only origin/main...HEAD)

echo "Branch ${{ github.head_ref }} is not a generated release branch; artifact mirror files are unchanged."

- name: Validate generated release payload
if: ${{ startsWith(github.head_ref, 'release/code-scan-action-v') }}
env:
HEAD_REF: ${{ github.head_ref }}
run: |
set -euo pipefail

if [[ ! -f .release-source.json ]]; then
echo "Missing .release-source.json in generated release PR"
exit 1
fi

jq -e '
.repository == "promptfoo/promptfoo"
and .packagePath == "code-scan-action"
and (.sourceSha | test("^[0-9a-f]{40}$"))
and (.sourceTag | type == "string" and length > 0)
and (.version | test("^[0-9]+\\.[0-9]+\\.[0-9]+$"))
' .release-source.json > /dev/null

version="$(jq -r '.version' .release-source.json)"
source_sha="$(jq -r '.sourceSha' .release-source.json)"
source_tag="$(jq -r '.sourceTag' .release-source.json)"

if [[ "$HEAD_REF" != "release/code-scan-action-v${version}" ]]; then
echo "Branch name $HEAD_REF does not match release version $version"
exit 1
fi

if [[ "$source_tag" != "code-scan-action-${version}" ]]; then
echo "Source tag $source_tag does not match release version $version"
exit 1
fi

while IFS= read -r file; do
[[ -z "$file" ]] && continue
if [[ ! "$file" =~ ^(action\.yml|README\.md|CHANGELOG\.md|\.release-source\.json|dist(/.*)?)$ ]]; then
echo "Unexpected generated release file: $file"
exit 1
fi
done < <(git diff --name-only origin/main...HEAD)

source_dir="$RUNNER_TEMP/promptfoo-source"
expected_dir="$RUNNER_TEMP/code-scan-action-expected"

rm -rf "$source_dir" "$expected_dir"
git clone https://github.com/promptfoo/promptfoo.git "$source_dir"

cd "$source_dir"
git checkout --detach "$source_sha"
git merge-base --is-ancestor "$source_sha" origin/main

resolved_source_tag_sha="$(git rev-parse "${source_tag}^{commit}")"
if [[ "$resolved_source_tag_sha" != "$source_sha" ]]; then
echo "Source tag $source_tag points to $resolved_source_tag_sha, expected $source_sha"
exit 1
fi

npm install -g npm@latest
npm ci
npm ci --prefix code-scan-action
npm run tsc --prefix code-scan-action
npm run build --prefix code-scan-action

mkdir -p "$expected_dir"
cp code-scan-action/action.yml "$expected_dir/action.yml"
cp code-scan-action/README.md "$expected_dir/README.md"
cp code-scan-action/CHANGELOG.md "$expected_dir/CHANGELOG.md"
cp -R code-scan-action/dist "$expected_dir/dist"
cp "$GITHUB_WORKSPACE/.release-source.json" "$expected_dir/.release-source.json"

if ! diff -qr --exclude='.git' --exclude='.github' "$expected_dir" "$GITHUB_WORKSPACE"; then
Comment thread
jbeckwith-oai marked this conversation as resolved.
Outdated
echo "Generated mirror contents do not match promptfoo/promptfoo@$source_sha"
exit 1
fi
Loading