diff --git a/.github/workflows/backend-ci.yml b/.github/workflows/backend-ci.yml index 9b36c2a..f52ad4e 100644 --- a/.github/workflows/backend-ci.yml +++ b/.github/workflows/backend-ci.yml @@ -8,6 +8,14 @@ on: # run CI before doing whatever task they're doing. Like the release workflow. workflow_call: +concurrency: + # On a pull request, group by the PR so a new push supersedes the matrix + # still running for the previous one. Any other event -- notably the + # workflow_call from the release -- keys the group on the unique run id + # instead, so release runs never queue behind or cancel each other. + group: ${{ github.workflow }}-backend-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + defaults: run: working-directory: "./backend-plugin-sample" diff --git a/.github/workflows/frontend-ci.yml b/.github/workflows/frontend-ci.yml new file mode 100644 index 0000000..4499281 --- /dev/null +++ b/.github/workflows/frontend-ci.yml @@ -0,0 +1,48 @@ +name: Frontend CI + +on: + pull_request: + branches: + - "**" + # So the release workflow can run these checks before it publishes anything. + workflow_call: + +concurrency: + # See backend-ci.yml for why non-pull_request events key on the run id. + group: ${{ github.workflow }}-frontend-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +defaults: + run: + working-directory: "./frontend-plugin-sample" + +jobs: + build: + name: build + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Setup Node.js + uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version-file: './frontend-plugin-sample/.nvmrc' + cache: 'npm' + cache-dependency-path: './frontend-plugin-sample/package-lock.json' + + # `npm ci` rather than `npm install`: it installs the lockfile exactly + # and fails if the lockfile and package.json have drifted apart, instead + # of quietly reconciling them. + - name: Install dependencies + run: npm ci + + # The package has no lint or test suite yet, so compiling is the only + # check available. It is still the one that matters most: until now the + # first and only build of this package happened inside the publish job, + # after the GitHub release and both PyPI uploads had already gone out. + - name: Build + run: npm run build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f03a32f..dce5ac3 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,8 +8,18 @@ jobs: run_backend_tests: uses: ./.github/workflows/backend-ci.yml + run_frontend_tests: + uses: ./.github/workflows/frontend-ci.yml + + run_tutor_tests: + uses: ./.github/workflows/tutor-ci.yml + release: - needs: run_backend_tests + # Every package this workflow publishes has to build before we tag + # anything. The GitHub release and the PyPI uploads cannot be taken back, + # so a package that only fails to build in its publish job would leave the + # release half-finished. + needs: [run_backend_tests, run_frontend_tests, run_tutor_tests] runs-on: ubuntu-latest if: github.ref_name == 'main' concurrency: @@ -132,8 +142,6 @@ jobs: uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 with: packages-dir: backend-plugin-sample/dist - user: __token__ - password: ${{ secrets.PYPI_UPLOAD_TOKEN }} publish_tutor_plugin_to_pypi: runs-on: ubuntu-latest @@ -155,8 +163,6 @@ jobs: uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0 with: packages-dir: tutor-contrib-sample/dist - user: __token__ - password: ${{ secrets.PYPI_UPLOAD_TOKEN }} publish_to_npm: runs-on: ubuntu-latest @@ -179,8 +185,8 @@ jobs: - name: Update the package version and publish run: | - npm install --include=dev - npm version ${{ needs.release.outputs.version }} + npm ci + npm version --no-git-tag-version ${{ needs.release.outputs.version }} npm run build npm publish working-directory: './frontend-plugin-sample' diff --git a/.github/workflows/tutor-ci.yml b/.github/workflows/tutor-ci.yml new file mode 100644 index 0000000..df2a706 --- /dev/null +++ b/.github/workflows/tutor-ci.yml @@ -0,0 +1,54 @@ +name: Tutor Plugin CI + +on: + pull_request: + branches: + - "**" + # So the release workflow can run these checks before it publishes anything. + workflow_call: + +concurrency: + # See backend-ci.yml for why non-pull_request events key on the run id. + group: ${{ github.workflow }}-tutor-${{ github.event_name == 'pull_request' && github.ref || github.run_id }} + cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +defaults: + run: + working-directory: "./tutor-contrib-sample" + +jobs: + build: + name: build + runs-on: ubuntu-latest + + permissions: + contents: read + + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # setuptools-scm derives the version from git tags, and this project + # sets no fallback_version, so it needs the history and tags rather + # than the default shallow clone. + fetch-depth: 0 + + - name: setup python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.12" + + - name: Install uv + uses: astral-sh/setup-uv@20cfd1bf945f4377ade1205e4dbc17946fc9a30d # v10.0.1 + with: + cache-suffix: tutor + + # Until now this package was first built inside the release job, so a + # broken pyproject.toml surfaced only after the GitHub release and the + # backend PyPI upload had already been published. + - name: Build + run: uv run --with build python -m build + + # Catches metadata that PyPI would reject or render badly -- the long + # description is read dynamically from README.md, so it is worth checking. + - name: Check distribution metadata + run: uv run --with twine twine check dist/* diff --git a/backend-plugin-sample/setup.cfg b/backend-plugin-sample/setup.cfg index d782599..da0309e 100644 --- a/backend-plugin-sample/setup.cfg +++ b/backend-plugin-sample/setup.cfg @@ -5,6 +5,3 @@ line_length = 120 multi_line_output = 3 skip= migrations - -[wheel] -universal = 1 diff --git a/frontend-plugin-sample/package.json b/frontend-plugin-sample/package.json index f62a827..4ee0c68 100644 --- a/frontend-plugin-sample/package.json +++ b/frontend-plugin-sample/package.json @@ -3,7 +3,11 @@ "version": "__semantically__released__", "main": "dist/index.js", "files": ["dist"], - "repository": "https://github.com/openedx/sample-plugin", + "repository": { + "type": "git", + "url": "git+https://github.com/openedx/sample-plugin.git", + "directory": "frontend-plugin-sample" + }, "scripts": { "build": "fedx-scripts babel src --out-dir dist --source-maps --ignore **/*.test.jsx,**/*.test.js" }, diff --git a/tutor-contrib-sample/LICENSE.txt b/tutor-contrib-sample/LICENSE.txt new file mode 100644 index 0000000..28ba471 --- /dev/null +++ b/tutor-contrib-sample/LICENSE.txt @@ -0,0 +1,180 @@ + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + diff --git a/tutor-contrib-sample/pyproject.toml b/tutor-contrib-sample/pyproject.toml index 8792b69..db18bb5 100644 --- a/tutor-contrib-sample/pyproject.toml +++ b/tutor-contrib-sample/pyproject.toml @@ -16,6 +16,7 @@ classifiers = [ "Intended Audience :: Developers", "Natural Language :: English", "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", ] keywords = ["tutor", "openedx", "plugin"]