Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0f793b9
Apply new templates
AndrewSazonov Feb 19, 2026
bd2c6fd
Reapply templates
AndrewSazonov Feb 19, 2026
f3522b2
Make setup docs admonitions collapsible
AndrewSazonov Feb 19, 2026
7615f18
Update docs; remove app docs link
AndrewSazonov Feb 19, 2026
562f109
Fix docs formatting for Pixi setup
AndrewSazonov Feb 19, 2026
3d79426
Bump copier template; set release PR name
AndrewSazonov Feb 19, 2026
a8cbc89
Add branch protection rulesets and tasks
AndrewSazonov Feb 19, 2026
06225b2
Add issue label checks; rename PR labels workflow
AndrewSazonov Feb 19, 2026
f9bf2e1
Bump template; enforce 1 review on develop
AndrewSazonov Feb 19, 2026
a70ee72
Add GitHub Pages config and repo setup tasks
AndrewSazonov Feb 19, 2026
85f9fd3
Enable GitHub Discussions in repo config
AndrewSazonov Feb 23, 2026
e8ef8a0
Update backmerge workflow and labels
AndrewSazonov Feb 23, 2026
5682ff3
Move GH config files; modularize backmerge issue
AndrewSazonov Feb 25, 2026
5bc7b37
Add runtime environment detection utilities
AndrewSazonov Feb 25, 2026
e3659af
Add tests for environment module
AndrewSazonov Feb 25, 2026
f20cd8b
Refactor environment tests for robustness
AndrewSazonov Feb 25, 2026
321aeae
Enable Ruff linting; adjust docstrings and tests
AndrewSazonov Feb 25, 2026
941d720
Add environment module docs to API reference
AndrewSazonov Feb 25, 2026
d570d0a
Remove GSL dependency
AndrewSazonov Feb 25, 2026
cf040f7
Update release label; fix backmerge script path
AndrewSazonov Feb 25, 2026
8631de1
Narrow exception handling in IPython checks
AndrewSazonov Feb 25, 2026
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 .copier-answers.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# WARNING: Do not edit this file manually.
# Any changes will be overwritten by Copier.
_commit: v0.4.7
_commit: v0.5.0-9-g8a8e235
_src_path: gh:easyscience/templates
lib_docs_url: https://easyscience.github.io/utils
lib_doi: 10.5281/zenodo.18163581
Expand All @@ -10,8 +10,8 @@ lib_python_min: '3.11'
lib_repo_name: utils
project_contact_email: support@easyscience.org
project_copyright_years: '2026'
project_extended_description: For sharing utilities, including reusable classes and
functions, to be used across EasyScience modules
project_extended_description: A shared library of utility classes and helper functions
used across the EasyScience framework
project_homepage_url: https://easyscience.github.io/utils
project_name: EasyUtilities
project_repo_name: utils
Expand Down
1 change: 0 additions & 1 deletion .github/actions/publish-to-pypi/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,3 @@ runs:
- uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ${{ inputs.packages_dir }}
attestations: false
6 changes: 6 additions & 0 deletions .github/configs/pages-deployment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"source": {
"branch": "gh-pages",
"path": "/"
}
}
37 changes: 37 additions & 0 deletions .github/configs/rulesets-develop.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "develop branch",
"target": "branch",
"enforcement": "active",
"conditions": {
"ref_name": {
"include": ["refs/heads/develop"],
"exclude": []
}
},
"bypass_actors": [
{
"actor_id": 2476259,
"actor_type": "Integration",
"bypass_mode": "always"
}
],
"rules": [
{
"type": "non_fast_forward"
},
{
"type": "deletion"
},
{
"type": "pull_request",
"parameters": {
"allowed_merge_methods": ["squash"],
"dismiss_stale_reviews_on_push": false,
"require_code_owner_review": false,
"require_last_push_approval": false,
"required_approving_review_count": 1,
"required_review_thread_resolution": false
}
}
]
}
19 changes: 19 additions & 0 deletions .github/configs/rulesets-gh-pages.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "gh-pages branch",
"target": "branch",
"enforcement": "active",
"conditions": {
"ref_name": {
"include": ["refs/heads/gh-pages"],
"exclude": []
}
},
"rules": [
{
"type": "non_fast_forward"
},
{
"type": "deletion"
}
]
}
30 changes: 30 additions & 0 deletions .github/configs/rulesets-master.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "master branch",
"target": "branch",
"enforcement": "active",
"conditions": {
"ref_name": {
"include": ["~DEFAULT_BRANCH"],
"exclude": []
}
},
"rules": [
{
"type": "non_fast_forward"
},
{
"type": "deletion"
},
{
"type": "pull_request",
"parameters": {
"allowed_merge_methods": ["merge"],
"dismiss_stale_reviews_on_push": false,
"require_code_owner_review": false,
"require_last_push_approval": false,
"required_approving_review_count": 0,
"required_review_thread_resolution": false
}
}
]
}
69 changes: 69 additions & 0 deletions .github/scripts/backmerge-conflict-issue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
module.exports = async ({ github, context, core }) => {
// Repo context
const owner = context.repo.owner
const repo = context.repo.repo

// Link to the exact workflow run that detected the conflict
const runUrl = `${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`

// We use a *stable title* so we can find/reuse the same "conflict tracker" issue
// instead of creating a new issue on every failed run.
const title = 'Backmerge conflict: master → develop'

// Comment/issue body includes the run URL so maintainers can jump straight to logs.
const body = [
'Automatic backmerge failed due to merge conflicts.',
'',
`Workflow run: ${runUrl}`,
'',
'Manual resolution required.',
].join('\n')

// Label applied to the tracker issue (assumed to already exist in the repo).
const label = '[bot] backmerge'

// Search issues by title across *open and closed* issues.
// Why: if the conflict was resolved previously and the issue was closed,
// we prefer to reopen it and append a new comment instead of creating duplicates.
const q = `repo:${owner}/${repo} is:issue in:title "${title}"`
const search = await github.rest.search.issuesAndPullRequests({
q,
per_page: 10,
})

// Pick the first exact-title match (search can return partial matches).
const existing = search.data.items.find((i) => i.title === title)

if (existing) {
// If a tracker issue exists, reuse it:
// - reopen it if needed
// - add a comment with the new run URL
if (existing.state === 'closed') {
await github.rest.issues.update({
owner,
repo,
issue_number: existing.number,
state: 'open',
})
}

await github.rest.issues.createComment({
owner,
repo,
issue_number: existing.number,
body,
})

core.notice(`Conflict issue updated: #${existing.number}`)
return
}

// No tracker issue exists yet -> create the first one.
await github.rest.issues.create({
owner,
repo,
title,
body,
labels: [label],
})
}
101 changes: 62 additions & 39 deletions .github/workflows/backmerge.yml
Original file line number Diff line number Diff line change
@@ -1,34 +1,29 @@
# This workflow automatically merges `master` into `develop` whenever a
# new version tag is pushed (v*).
#
# Key points:
# - Directly merges master into develop without creating a PR.
# - Skips CI on the merge commit using [skip ci] in the commit message.
# - The code being merged has already been tested as part of the release process.
# - This ensures develop stays up-to-date with release changes (version bumps, etc.).
#
# Required organization config:
# https://github.com/organizations/easyscience/settings/secrets/actions
# https://github.com/organizations/easyscience/settings/variables/actions
# - Actions secret: EASYSCIENCE_APP_KEY (GitHub App private key PEM)
# - Actions variable: EASYSCIENCE_APP_ID (GitHub App ID)
#
# IMPORTANT:
# The GitHub App must be added to the develop branch ruleset bypass list.

name: Backmerge (master -> develop)
# new version release with a tag is published. It can also be triggered
# manually via workflow_dispatch for cases where an automatic backmerge
# is needed outside of the standard release process.
# If a merge conflict occurs, the workflow creates an issue to notify
# maintainers for manual resolution.

name: Backmerge (master → develop)

on:
push:
tags: ['v*']
release:
types: [published, prereleased]
workflow_dispatch:
Comment on lines 1 to 13
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

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

This PR is titled "Add runtime environment detection utilities", but it also introduces/changes multiple GitHub operational workflows and branch protection rulesets. Consider splitting the GitHub automation/ruleset changes into a separate PR so the environment-utility change can be reviewed and released independently.

Copilot uses AI. Check for mistakes.

permissions:
contents: write
issues: write

concurrency:
group: backmerge-master-into-develop
cancel-in-progress: false

jobs:
backmerge:
runs-on: ubuntu-latest
timeout-minutes: 10

steps:
- name: Checkout repository (for local actions)
Expand All @@ -53,34 +48,62 @@ jobs:
git config user.name "easyscience[bot]"
git config user.email "${{ vars.EASYSCIENCE_APP_ID }}+easyscience[bot]@users.noreply.github.com"

- name: Merge master into develop
- name: Set merge message
run: |
set -euo pipefail
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
MESSAGE="Backmerge: master into develop (manual) [skip ci]"
else
TAG="${{ github.event.release.tag_name }}"
MESSAGE="Backmerge: master (${TAG}) into develop [skip ci]"
fi

echo "Fetching develop branch"
git fetch origin develop:develop
echo "MESSAGE=$MESSAGE" >> "$GITHUB_ENV"
echo "message=$MESSAGE" >> "$GITHUB_OUTPUT"
echo "📝 Merge message: $MESSAGE" | tee -a "$GITHUB_STEP_SUMMARY"

echo "Switching to develop branch"
git checkout develop
- name: Prepare branches
run: |
git fetch origin master develop
git checkout -B develop origin/develop

echo "Checking if already up-to-date"
- name: Check if develop is already up-to-date
id: up_to_date
run: |
if git merge-base --is-ancestor origin/master develop; then
echo "ℹ️ Develop is already up-to-date with master"
exit 0
echo "value=true" >> "$GITHUB_OUTPUT"
echo "ℹ️ Develop is already up-to-date with master" | tee -a "$GITHUB_STEP_SUMMARY"
else
echo "value=false" >> "$GITHUB_OUTPUT"
fi

echo "Preparing merge message"
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
MESSAGE="Backmerge: master into develop (manual) [skip ci]"
else
TAG="${{ github.ref_name }}"
MESSAGE="Backmerge: ${TAG} from master into develop [skip ci]"
- name: Try merge master into develop
id: merge
if: steps.up_to_date.outputs.value == 'false'
continue-on-error: true
run: |
if ! git merge origin/master --no-ff -m "${MESSAGE}"; then
echo "conflict=true" >> "$GITHUB_OUTPUT"
echo "❌ Backmerge conflict detected." | tee -a "$GITHUB_STEP_SUMMARY"
git status --porcelain || true
exit 0
fi

echo "Merging master into develop"
git merge origin/master --no-ff -m "${MESSAGE}"
echo "conflict=false" >> "$GITHUB_OUTPUT"
echo "✅ Merge commit created." | tee -a "$GITHUB_STEP_SUMMARY"

echo "Pushing to develop"
- name: Push to develop (if merge succeeded)
if:
steps.up_to_date.outputs.value == 'false' && steps.merge.outputs.conflict ==
'false'
run: |
git push origin develop
echo "🚀 Backmerge successful: master → develop" | tee -a "$GITHUB_STEP_SUMMARY"

echo "✅ Successfully merged master into develop"
- name: Create issue (if merge failed with conflicts)
if: steps.merge.outputs.conflict == 'true'
uses: ./.github/actions/github-script
with:
github-token: ${{ steps.bot.outputs.token }}
script: |
const run = require('./.github/scripts/backmerge-conflict-issue.js')
await run({ github, context, core })
39 changes: 39 additions & 0 deletions .github/workflows/issues-labels.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Verifies if an issue has at least one of the `[scope]` and one of the
# `[priority]` labels. If not, the bot adds labels with a warning emoji
# to indicate that those labels need to be added.

name: Issue labels check

on:
issues:
types: [opened, labeled, unlabeled]

jobs:
check-labels:
runs-on: ubuntu-latest

steps:
- name: Setup easyscience[bot]
id: bot
uses: ./.github/actions/setup-easyscience-bot
with:
app-id: ${{ vars.EASYSCIENCE_APP_ID }}
private-key: ${{ secrets.EASYSCIENCE_APP_KEY }}

- name: Check for required [scope] label
uses: trstringer/require-label-prefix@v1
with:
secret: ${{ steps.bot.outputs.token }}
prefix: '[scope]'
labelSeparator: ' '
addLabel: true
defaultLabel: '[scope] ⚠️ label needed'

- name: Check for required [priority] label
uses: trstringer/require-label-prefix@v1
with:
secret: ${{ steps.bot.outputs.token }}
prefix: '[priority]'
labelSeparator: ' '
addLabel: true
defaultLabel: '[priority] ⚠️ label needed'
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Verifies if a pull request has at least one label from a set of valid
# labels before it can be merged.

name: PR label checks
name: PR labels check

on:
pull_request_target:
Expand All @@ -11,16 +11,17 @@ permissions:
pull-requests: read

jobs:
require-label:
check-labels:
runs-on: ubuntu-latest

steps:
- name: Validate required labels
- name: Check for valid labels
run: |
PR_LABELS=$(echo '${{ toJson(github.event.pull_request.labels.*.name) }}' | jq -r '.[]')

echo "Current PR labels: $PR_LABELS"
VALID_LABELS=(
"[bot] pull request"
"[bot] release"
"[scope] bug"
"[scope] documentation"
"[scope] enhancement"
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/pypi-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ jobs:
# Repository name: utils
# Workflow name: pypi-publish.yml
- name: Publish to PyPI
#uses: ./.github/actions/publish-to-pypi
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: 'dist'
Loading
Loading