Skip to content

Migration Guide: 0.5.0 → 0.6.0

Status: Released. This guide covers upgrading from 0.5.0 to the 0.6.x line and documents every breaking change introduced by PRs #81-#94, so 0.5.0 users can upgrade with a single read. If you are already on any 0.6.x release, no further migration is required — this guide is retained as a historical reference for the 0.5.0 → 0.6.0 jump.

0.6.0 is a hardening release. It tightens default security posture, fixes a packaging mismatch that prevented install via the documented command, and ships several CLI quality-of-life improvements. There are several breaking changes; all are documented below with migration steps.


TL;DR

Change Impact Action
PyPI package renamed: azure-functions-scaffold-pythonazure-functions-scaffold Old install command stops working (returns 404) pip install azure-functions-scaffold
Sibling deps in generated pyproject.toml lose -python suffix New scaffolds only; existing projects unaffected None for existing projects
Default auth_level flipped from ANONYMOUS to FUNCTION for business endpoints New scaffolds expose endpoints requiring function key Set keys, or downgrade explicitly per-route
Webhook handlers fail closed without WEBHOOK_SECRET New scaffolds 503 until secret is configured Add WEBHOOK_SECRET to local.settings.json and app settings
function_app.py marker comments renamed Existing scaffolds keep working via legacy-marker shim Optional: update marker comment for cleanliness
Identifier validation rejects Python keywords / invalid identifiers afs api add if etc. now errors out instead of generating broken code Pick a valid Python identifier
--overwrite requires TTY confirmation or explicit --yes Scripted use of --overwrite without --yes now blocks Add --yes to non-interactive invocations
azure-functions-scaffold-python long-form CLI entry removed Use afs short form, or azure-functions-scaffold long form s/azure-functions-scaffold-python/afs/g in your scripts
add and profiles commands replaced; deprecation shims forward Shims emit a deprecation warning Migrate to the modern command names listed by the warning

If you only do one thing: re-install with the new name and re-read your generated local.settings.json.example.


1. Packaging rename (PR #90)

What changed

  • pyproject.toml [project].name is now azure-functions-scaffold (was azure-functions-scaffold-python).
  • The wheel filename is now azure_functions_scaffold-0.6.0-py3-none-any.whl (was azure_functions_scaffold_python-…).
  • The long-form CLI entry point is now azure-functions-scaffold (was azure-functions-scaffold-python). The short alias afs is unchanged.
  • Every generated project's pyproject.toml now depends on the unsuffixed sibling packages: azure-functions-logging, azure-functions-openapi, azure-functions-validation, azure-functions-doctor, azure-functions-db. The -python-suffixed names were never published on PyPI and would 404.
  • Marker comments in generated function_app.py are now # azure-functions-scaffold: … (was # azure-functions-scaffold-python: …). The generator recognizes both legacy and new markers — see §5.

Why

The PyPI package azure-functions-scaffold-python does not exist. The package owner published azure-functions-scaffold v0.5.0. Anyone following 0.5.0's pip install azure-functions-scaffold-python instruction got a 404. Same problem for every sibling reference.

Migration

# Old (does not work)
pip install azure-functions-scaffold-python

# New
pip install azure-functions-scaffold

If your scripts invoke azure-functions-scaffold-python as a CLI long-form, switch to afs (preferred) or azure-functions-scaffold:

# Old
azure-functions-scaffold-python new my-api

# New
afs new my-api
# or
azure-functions-scaffold new my-api

For existing scaffolded projects: no action required. The -python-suffixed dep names were never resolvable, so your pip install -e . was already failing or pinned to local copies. Update the dep names in your project's pyproject.toml when convenient:

# Old
dependencies = [
  "azure-functions-logging-python>=0.5.0",
  "azure-functions-openapi-python>=0.17.0",
]

# New
dependencies = [
  "azure-functions-logging>=0.5.0",
  "azure-functions-openapi>=0.17.0",
]

The GitHub repository name (azure-functions-scaffold-python) and docs URL are unchanged; only the PyPI package name is unsuffixed.


2. Secure default auth (PR #83)

What changed

  • All business-endpoint templates now default to func.AuthLevel.FUNCTION (was ANONYMOUS).
  • The webhook handler refuses to start without WEBHOOK_SECRET. Missing secret produces an HTTP 503 and a RuntimeError in logs.
  • local.settings.json.example ships with a WEBHOOK_SECRET placeholder.

The only endpoints that remain ANONYMOUS are the OpenAPI spec / Swagger UI surfaces (/api/openapi.json, /api/openapi.yaml, /api/docs) and the /api/health endpoint, which are intentionally public.

Why

Generating a project that exposes business endpoints with auth_level=ANONYMOUS is a security regression by default. Most Azure Functions deployments are public-internet-facing. Anonymous business endpoints are almost always wrong; users can opt out per-endpoint when they actually want anonymous (e.g., public webhooks with HMAC verification done in-handler).

Migration

For new scaffolds: add a function key in the Azure Portal or local.settings.json, and pass it as ?code=<key> or x-functions-key: <key> when calling the endpoint.

For existing scaffolds that you regenerate with 0.6.0 overlays: review every blueprint route. If you genuinely want ANONYMOUS, set it explicitly:

@app.route(route="public-endpoint", auth_level=func.AuthLevel.ANONYMOUS)
def public_endpoint(req): ...

For webhook endpoints, the new fail-closed behavior requires:

# local.settings.json
{
  "Values": {
    "WEBHOOK_SECRET": "your-shared-secret-here"
  }
}

In production, set WEBHOOK_SECRET as an app setting in the Function App configuration. Without it, the endpoint returns 503 instead of silently accepting unverified payloads.


3. Marker comment rename (PR #81 + PR #90)

What changed

function_app.py marker comments used by afs api add, afs api add-route, afs api add-resource, and afs advanced add are now:

# azure-functions-scaffold: function imports
# azure-functions-scaffold: function registrations

Was:

# azure-functions-scaffold-python: function imports
# azure-functions-scaffold-python: function registrations

Why

Aligns with the unsuffixed package name. A separate fix in PR #81 first caught a long-standing drift between the generator's marker constants and the templates' actual comments — the markers had silently been broken in production while unit tests stayed green.

Migration

The generator recognizes BOTH the new marker and the legacy azure-functions-scaffold-python: marker. Existing scaffolds continue to work without change. afs api add and friends find either marker and insert near it.

If you want the cosmetic update for new-installs consistency:

# In your scaffolded project's function_app.py
sed -i 's/# azure-functions-scaffold-python: /# azure-functions-scaffold: /g' function_app.py

4. Identifier validation (PR #82)

What changed

afs api add, afs api add-route, afs api add-resource, afs advanced add, and project-creation commands now reject:

  • Python hard keywords (if, class, return, …)
  • Soft keywords (match, case, type, …)
  • Strings that aren't valid Python identifiers (123foo, my-route, …)

Previously these would silently generate broken code that failed at import time.

Why

afs api add if produced a file app/functions/if.py containing def if(req): … — a SyntaxError. Better to error early with a clear message.

Migration

Use a valid Python identifier. If you previously got away with naming a function after a keyword, rename it. Example error:

Error: 'if' is a Python keyword and cannot be used as a function name.
       Pick a name that is a valid Python identifier (e.g., 'check_if').

5. --overwrite safety guard (PR #89)

What changed

When afs new / afs api new / afs advanced new is invoked with --overwrite against a non-empty target directory, the CLI:

  1. Refuses if the target contains a .git/ directory.
  2. Prompts for y/N confirmation if stdin is a TTY.
  3. Refuses with a non-zero exit if stdin is not a TTY and --yes was not provided.

A new --yes / -y flag short-circuits the prompt for scripted use.

Why

--overwrite against a populated directory was a footgun. Deleting a developer's git repo by typo is unacceptable.

Migration

For scripted / CI use, add --yes (or -y):

# Old
afs new my-api --overwrite

# New (scripted)
afs new my-api --overwrite --yes

For interactive use, no change — you'll be prompted.

If the target directory is a git repo, you must remove it manually first; --overwrite will refuse to delete it under any flag.


6. Python 3.14 Preview status (PR #91)

What changed

Selecting --python-version 3.14 now emits a yellow stderr warning informing you that 3.14 is Preview on Azure Functions today, with limited regional / plan / Flex Consumption support.

3.14 is still accepted; the warning is informational only.

Why

Azure Functions' GA support for Python 3.14 is incomplete at the time of this writing. Users picking 3.14 today routinely hit deployment surprises.

Migration

None required. If you want to silence the warning for a CI lane, redirect stderr or downgrade the chosen version:

# Recommended for production today
afs new my-api --python-version 3.12

The recommended default in Quick Start examples is now 3.12.


7. CLI ergonomic changes

afs with no subcommand prints help (PR #86)

Was: silent / undefined. Now: afs --help is printed.

afs add / afs profiles are deprecation shims (PR #87)

These commands still work but print a one-time stderr deprecation warning pointing to the modern command name. They will be removed in a future major release.

DeprecationWarning: 'afs add' is deprecated; use 'afs api add' instead.

Migrate to: - afs addafs api add (or the appropriate intent group) - afs profilesafs presets

Flag/template compatibility validation (PR #88)

afs advanced new rejects invalid feature-flag combinations before generating any files. Example: --with-openapi against the langgraph template errors out cleanly instead of producing a half-generated project.

Atomic generation (PR #85)

afs api add, afs advanced add, afs api add-resource, and afs api add-route now use a two-phase commit internally. If any step fails (e.g., disk full mid-write), no partial files are left behind. Rollback is automatic.

ADDABLE_TRIGGERS split (PR #84)

The CLI's --trigger help string now correctly lists only the triggers that afs … add can extend an existing project with, separately from the broader set of triggers used at scaffold time.


8. Generated project quality (PR #93)

What changed

Every generated project's pyproject.toml now includes:

[tool.pytest.ini_options]
pythonpath = ["."]
testpaths = ["tests"]

Why

Without pythonpath = ["."], pytest 8+ fails at collection time:

ModuleNotFoundError: No module named 'app.functions.timer'

This was broken in every template in 0.5.0. The new generated-project smoke E2E workflow (PR #94) now catches this class of bug in CI.

Migration

For existing scaffolds: edit your project's pyproject.toml:

[tool.pytest.ini_options]
pythonpath = ["."]   # add this line
testpaths = ["tests"]

Or run pytest with PYTHONPATH=.:

PYTHONPATH=. pytest

9. CI infrastructure (PR #94)

A new workflow templates-smoke.yml scaffolds every template on every PR that touches src/azure_functions_scaffold/templates/** and runs the generated project's own compileall, ruff, mypy, and pytest. This is internal infrastructure — no migration impact for users — but it is the reason §2, §6, and §8 surfaced as fixes in this release.


Verification checklist

After upgrading:

  • [ ] pip install azure-functions-scaffold succeeds (use the new name).
  • [ ] afs --version prints a 0.6.x version (e.g. 0.6.1).
  • [ ] If you use webhooks, WEBHOOK_SECRET is configured in local.settings.json and Azure app settings.
  • [ ] Existing scaffolded projects still respond to afs api add etc. (legacy marker shim).
  • [ ] Scripted --overwrite invocations include --yes.
  • [ ] Generated pyproject.toml has pythonpath = ["."] (re-run afs api add ping or just edit manually for old scaffolds).
  • [ ] You aren't pinning --python-version 3.14 in production unless you've verified Preview support for your region/plan.

Reporting issues

If you hit something this guide didn't cover, open an issue at https://github.com/yeongseon/azure-functions-scaffold-python/issues with the label 0.6.0-migration.