diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5a079137..5040cda7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,7 +16,7 @@ permissions: jobs: prepare: name: Prepare release branch - if: ${{ !(github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release-') && github.actor == 'github-actions[bot]') }} + if: ${{ github.repository == 'kubeflow/sdk' && !(github.event_name == 'push' && startsWith(github.ref, 'refs/heads/release-') && github.actor == 'github-actions[bot]') }} runs-on: ubuntu-latest outputs: version: ${{ steps.vars.outputs.version }} diff --git a/.github/workflows/welcome-new-contributors.yaml b/.github/workflows/welcome-new-contributors.yaml index 8a71091b..0e9b768f 100644 --- a/.github/workflows/welcome-new-contributors.yaml +++ b/.github/workflows/welcome-new-contributors.yaml @@ -1,7 +1,10 @@ name: Welcome new contributors on: - pull_request_target: + pull_request: + types: + - opened + issues: types: - opened @@ -10,11 +13,28 @@ jobs: runs-on: ubuntu-latest permissions: pull-requests: write + issues: write steps: - uses: actions/first-interaction@v3 with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - pr-message: | + repo_token: ${{ secrets.GITHUB_TOKEN }} + issue_message: | + 🎉 **Welcome to the Kubeflow SDK!** 🎉 + + Thanks for opening your first issue! We're happy to have you as part of our community 🚀 + + **Here's what happens next:** + + - Our team will review your issue soon! cc @kubeflow/kubeflow-sdk-team + - If you'd like to contribute to this issue, check out our [Contributing Guide](https://github.com/kubeflow/sdk/blob/main/CONTRIBUTING.md) for repo-specific guidelines and the [Kubeflow Contributor Guide](https://www.kubeflow.org/docs/about/contributing/) for general community standards + + **Join the community:** + - **Slack**: Join our [#kubeflow-ml-experience](https://www.kubeflow.org/docs/about/community/#kubeflow-slack-channels) and [#kubeflow-trainer](https://www.kubeflow.org/docs/about/community/#kubeflow-slack-channels) Slack channels + - **Meetings**: Attend the [Kubeflow SDK and ML Experience](https://bit.ly/kf-ml-experience) bi-weekly meetings + + Feel free to ask questions in the comments if you need any help or clarification! + Thanks again for contributing to Kubeflow! 🙏 + pr_message: | 🎉 **Welcome to the Kubeflow SDK!** 🎉 Thanks for opening your first PR! We're happy to have you as part of our community 🚀 diff --git a/CHANGELOG/CHANGELOG-0.1.md b/CHANGELOG/CHANGELOG-0.1.md new file mode 100644 index 00000000..13a59159 --- /dev/null +++ b/CHANGELOG/CHANGELOG-0.1.md @@ -0,0 +1,59 @@ +# [0.1.0](https://github.com/kubeflow/sdk/releases/tag/0.1.0) (2025-09-23) + +## New Features + +- feat(ci): Add automated release CI job ([#65](https://github.com/kubeflow/sdk/pull/65)) by @kramaranya +- feat: Implement TrainerClient Backends & Local Process ([#33](https://github.com/kubeflow/sdk/pull/33)) by @szaher +- feat: KEP-2 Local Execution Mode Proposal ([#34](https://github.com/kubeflow/sdk/pull/34)) by @szaher +- feat(trainer): Add support for param unpacking in the training function call ([#62](https://github.com/kubeflow/sdk/pull/62)) by @briangallagher +- feat: Support multiple pip index URLs in CustomTrainer ([#79](https://github.com/kubeflow/sdk/pull/79)) by @wassimbensalem +- feat(trainer): Refactor get_job_logs() API with Iterator ([#83](https://github.com/kubeflow/sdk/pull/83)) by @andreyvelich +- feat: Implement Kubernetes Backend ([#68](https://github.com/kubeflow/sdk/pull/68)) by @szaher +- feat(docs): add ROADMAP of Kubeflow SDK ([#44](https://github.com/kubeflow/sdk/pull/44)) by @kramaranya +- feat(trainer): Add `get_runtime_packages()` API ([#57](https://github.com/kubeflow/sdk/pull/57)) by @andreyvelich +- feat(trainer): Support Framework Labels in Runtimes ([#56](https://github.com/kubeflow/sdk/pull/56)) by @andreyvelich +- feat(trainer): Add environment variables argument to CustomTrainer ([#54](https://github.com/kubeflow/sdk/pull/54)) by @astefanutti +- feat(trainer): Add `wait_for_job_status()` API ([#52](https://github.com/kubeflow/sdk/pull/52)) by @andreyvelich +- feat(ci): Add GitHub action to verify PR titles ([#42](https://github.com/kubeflow/sdk/pull/42)) by @andreyvelich + +## Bug Fixes + +- fix(scripts): Use previous stable tag for changelog ([#103](https://github.com/kubeflow/sdk/pull/103)) by @kramaranya +- fix(docs): Update links before SDK release ([#98](https://github.com/kubeflow/sdk/pull/98)) by @kramaranya +- fix: trainer client backend public ([#78](https://github.com/kubeflow/sdk/pull/78)) by @jaiakash +- fix(trainer): Keep the original runtime command in get_runtime_packages() API ([#64](https://github.com/kubeflow/sdk/pull/64)) by @andreyvelich +- fix(trainer): fix __all__ import. ([#43](https://github.com/kubeflow/sdk/pull/43)) by @Electronic-Waste +- fix: Expose BuiltinTrainer API to users ([#28](https://github.com/kubeflow/sdk/pull/28)) by @Electronic-Waste + +## Maintenance + +- chore: Ignore PRs titles with area/release labels in CI ([#101](https://github.com/kubeflow/sdk/pull/101)) by @kramaranya +- chore: Add proper ruff configuration ([#69](https://github.com/kubeflow/sdk/pull/69)) by @szaher +- chore: Update CONTRIBUTING.md to use uv ([#41](https://github.com/kubeflow/sdk/pull/41)) by @szaher +- chore: Add welcome new contributors CI ([#82](https://github.com/kubeflow/sdk/pull/82)) by @kramaranya +- chore(trainer): Use explicit exception chaining ([#80](https://github.com/kubeflow/sdk/pull/80)) by @andreyvelich +- chore: Nominate @kramaranya and @szaher as Kubeflow SDK reviewers ([#76](https://github.com/kubeflow/sdk/pull/76)) by @andreyvelich +- chore: Enable parallel builds for coveralls ([#81](https://github.com/kubeflow/sdk/pull/81)) by @kramaranya +- chore: Remove tool.hatch.build.targets from pyproject ([#73](https://github.com/kubeflow/sdk/pull/73)) by @kramaranya +- chore: Move dev extras to dependency-groups ([#71](https://github.com/kubeflow/sdk/pull/71)) by @kramaranya +- chore: Update README.md ([#67](https://github.com/kubeflow/sdk/pull/67)) by @kramaranya +- chore: move pyproject.toml to root ([#61](https://github.com/kubeflow/sdk/pull/61)) by @kramaranya +- chore(ci): Align Kubernetes versions from Trainer for e2e tests ([#58](https://github.com/kubeflow/sdk/pull/58)) by @astefanutti +- chore(ci): Add dev tests with master dependencies ([#55](https://github.com/kubeflow/sdk/pull/55)) by @kramaranya +- chore(docs): Add Coveralls Badge to the README ([#53](https://github.com/kubeflow/sdk/pull/53)) by @andreyvelich +- chore(trainer): Remove accelerator label from the runtimes ([#51](https://github.com/kubeflow/sdk/pull/51)) by @andreyvelich + +## Other Changes + +- Kubeflow SDK Official Release 0.1.0rc1 ([#100](https://github.com/kubeflow/sdk/pull/100)) by @kramaranya +- add unit test for trainer sdk ([#17](https://github.com/kubeflow/sdk/pull/17)) by @briangallagher +- add e2e notebook tests ([#27](https://github.com/kubeflow/sdk/pull/27)) by @briangallagher +- Update pyproject.toml project links ([#40](https://github.com/kubeflow/sdk/pull/40)) by @szaher +- Add support for UV & Ruff ([#38](https://github.com/kubeflow/sdk/pull/38)) by @szaher +- Step down from sdk ownership role ([#37](https://github.com/kubeflow/sdk/pull/37)) by @tenzen-y +- Add CONTRIBUTING.md ([#30](https://github.com/kubeflow/sdk/pull/30)) by @abhijeet-dhumal +- Reflect owners updates from KF Trainer ([#32](https://github.com/kubeflow/sdk/pull/32)) by @tenzen-y +- Consume Trainer models from external package kubeflow_trainer_api ([#15](https://github.com/kubeflow/sdk/pull/15)) by @kramaranya +- Add pre-commit and flake8 configs ([#6](https://github.com/kubeflow/sdk/pull/6)) by @eoinfennessy +- Add Stale GitHub action ([#7](https://github.com/kubeflow/sdk/pull/7)) by @kramaranya +- Add GitHub issue and PR templates ([#5](https://github.com/kubeflow/sdk/pull/5)) by @eoinfennessy diff --git a/README.md b/README.md index f5272161..bf9a4eee 100644 --- a/README.md +++ b/README.md @@ -73,12 +73,13 @@ print("\n".join(TrainerClient().get_job_logs(name=job_id))) ## Supported Kubeflow Projects -| Project | Status | Version Support | Description | -| --------------------------- | ---------------- |-----------------| ---------------------------------------------------------- | -| **Kubeflow Trainer** | ✅ **Available** | v2.0.0+ | Train and fine-tune AI models with various frameworks | -| **Kubeflow Katib** | 🚧 Planned | TBD | Hyperparameter optimization | -| **Kubeflow Pipelines** | 🚧 Planned | TBD | Build, run, and track AI workflows | -| **Kubeflow Model Registry** | 🚧 Planned | TBD | Manage model artifacts, versions and ML artifacts metadata | +| Project | Status | Version Support | Description | +| --------------------------- | ---------------- | --------------- | -------------------------------------------------------------------- | +| **Kubeflow Trainer** | ✅ **Available** | v2.0.0+ | Train and fine-tune AI models with various frameworks | +| **Kubeflow Katib** | 🚧 Planned | TBD | Hyperparameter optimization | +| **Kubeflow Pipelines** | 🚧 Planned | TBD | Build, run, and track AI workflows | +| **Kubeflow Model Registry** | 🚧 Planned | TBD | Manage model artifacts, versions and ML artifacts metadata | +| **Kubeflow Spark Operator** | 🚧 Planned | TBD | Manage Spark applications for data processing and feature engineering | ## Community diff --git a/kubeflow/__init__.py b/kubeflow/__init__.py index 42b5dad5..6f406353 100644 --- a/kubeflow/__init__.py +++ b/kubeflow/__init__.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "0.1.0rc1" +__version__ = "0.1.0" diff --git a/scripts/gen-changelog.py b/scripts/gen-changelog.py index ca5c96af..c3604e9a 100755 --- a/scripts/gen-changelog.py +++ b/scripts/gen-changelog.py @@ -15,16 +15,16 @@ def categorize_pr(title: str) -> str: title = title.lower().strip() - if title.startswith('feat'): - return 'feat' - elif title.startswith('fix'): - return 'fix' - elif title.startswith('chore'): - return 'chore' - elif title.startswith('revert'): - return 'revert' + if title.startswith("feat"): + return "feat" + elif title.startswith("fix"): + return "fix" + elif title.startswith("chore"): + return "chore" + elif title.startswith("revert"): + return "revert" else: - return 'misc' + return "misc" def get_initial_commit(github_repo): @@ -48,12 +48,14 @@ def main(): try: tags = list(github_repo.get_tags()) - if not tags: + stable_tags = [t for t in tags if not re.search(r"rc\d+$", t.name)] + if stable_tags: + previous_release = stable_tags[0].name + else: print("First release - using full history") previous_release = get_initial_commit(github_repo) - else: - previous_release = tags[0].name - print(f"Generating changelog: {previous_release} → {current_release}") + + print(f"Generating changelog: {previous_release} → {current_release}") except Exception as e: print(f"Error finding previous release: {e}") sys.exit(1) @@ -63,15 +65,9 @@ def main(): if not commits: print("No commits found in range") - sys.exit(1) + return - categories = { - 'feat': [], - 'fix': [], - 'chore': [], - 'revert': [], - 'misc': [] - } + categories = {"feat": [], "fix": [], "chore": [], "revert": [], "misc": []} pr_set = set() for commit in reversed(commits): @@ -81,46 +77,43 @@ def main(): pr_set.add(pr.number) category = categorize_pr(pr.title) - pr_entry = (f"- {pr.title} ([#{pr.number}]({pr.html_url})) " - f"by @{pr.user.login}") + pr_entry = f"- {pr.title} ([#{pr.number}]({pr.html_url})) by @{pr.user.login}" categories[category].append(pr_entry) if not pr_set: print("No PRs found in range") - sys.exit(1) + return release_date = str(commits[-1].commit.author.date).split(" ")[0] release_url = f"https://github.com/{REPO_NAME}/releases/tag/{current_release}" - major_minor_parts = current_release.split('.')[:2] - major_minor = '.'.join(major_minor_parts) + major_minor_parts = current_release.split(".")[:2] + major_minor = ".".join(major_minor_parts) changelog_file = os.path.join(CHANGELOG_DIR, f"CHANGELOG-{major_minor}.md") os.makedirs(CHANGELOG_DIR, exist_ok=True) - changelog_content = [ - f"# [{current_release}]({release_url}) ({release_date})\n\n" - ] + changelog_content = [f"# [{current_release}]({release_url}) ({release_date})\n\n"] - if categories['feat']: + if categories["feat"]: changelog_content.append("## New Features\n\n") - changelog_content.append("\n".join(categories['feat']) + "\n\n") + changelog_content.append("\n".join(categories["feat"]) + "\n\n") - if categories['fix']: + if categories["fix"]: changelog_content.append("## Bug Fixes\n\n") - changelog_content.append("\n".join(categories['fix']) + "\n\n") + changelog_content.append("\n".join(categories["fix"]) + "\n\n") - if categories['chore']: + if categories["chore"]: changelog_content.append("## Maintenance\n\n") - changelog_content.append("\n".join(categories['chore']) + "\n\n") + changelog_content.append("\n".join(categories["chore"]) + "\n\n") - if categories['revert']: + if categories["revert"]: changelog_content.append("## Reverts\n\n") - changelog_content.append("\n".join(categories['revert']) + "\n\n") + changelog_content.append("\n".join(categories["revert"]) + "\n\n") - if categories['misc']: + if categories["misc"]: changelog_content.append("## Other Changes\n\n") - changelog_content.append("\n".join(categories['misc']) + "\n\n") + changelog_content.append("\n".join(categories["misc"]) + "\n\n") try: with open(changelog_file) as f: @@ -128,16 +121,16 @@ def main(): except FileNotFoundError: existing_content = "" - lines = existing_content.split('\n') if existing_content else [] + lines = existing_content.split("\n") if existing_content else [] - new_content = ''.join(changelog_content) + new_content = "".join(changelog_content) if lines: - new_lines = new_content.rstrip().split('\n') + [''] + lines + new_lines = new_content.rstrip().split("\n") + [""] + lines else: - new_lines = new_content.rstrip().split('\n') + new_lines = new_content.rstrip().split("\n") with open(changelog_file, "w") as f: - f.write('\n'.join(new_lines)) + f.write("\n".join(new_lines)) print(f"Changelog has been updated: {changelog_file}") print(f"Found {len(pr_set)} PRs for {current_release}")