diff --git a/.github/actions/add-version-to-channel/action.yml b/.github/actions/add-version-to-channel/action.yml new file mode 100644 index 00000000..9349dc88 --- /dev/null +++ b/.github/actions/add-version-to-channel/action.yml @@ -0,0 +1,41 @@ +name: 'Add version to release channel' +description: | + Appends the specified version to the end of the specified release channel if + it wasn't already part of that channel. + +inputs: + release_type: + description: 'Release type (firmware, gui, docs, internal-docs).' + required: true + channel: + description: 'The channel on which to register this version' + required: true + version: + description: 'The version name (commit hash or semantic version name)' + required: true + odrive_api_key: + description: 'Key to our release index server' + required: true + +runs: + using: "composite" + steps: + - name: Register on release server + shell: python + run: | + import asyncio + import sys + import aiohttp + + sys.path.insert(0, '${{ github.workspace }}/.github/actions/upload-release') + from odrive.api_client import ApiClient + from private_release_api import PrivateReleaseApi + + async def main(): + async with aiohttp.ClientSession() as session: + api_client = ApiClient(session, key='${{ inputs.odrive_api_key }}') + release_api = PrivateReleaseApi(api_client) + await release_api.append_to_channel('${{ inputs.release_type }}', "${{ inputs.channel }}", "${{ inputs.version }}") + await release_api.refresh_routes('${{ inputs.release_type }}') + + asyncio.run(main()) diff --git a/.github/actions/upload-release/action.yml b/.github/actions/upload-release/action.yml index b37c68d9..a84d306d 100644 --- a/.github/actions/upload-release/action.yml +++ b/.github/actions/upload-release/action.yml @@ -2,11 +2,14 @@ name: 'Upload (Pre)release' description: | Pushes the specified local directory to our release file server and registers the new content on our release index server. - Whether the release will be public depends on the channel and its settings. + The version will not yet be associated with a channel. inputs: release_type: - description: 'Release type (firmware, gui, docs, internal-docs).' # TODO: Currently only firmware is supported. + description: 'Release type (firmware, gui, docs, internal-docs).' # TODO: Currently only firmware and docs is supported. + required: true + version: + description: 'The version name (commit hash or semantic version name)' required: true src_dir: description: 'The source directory on the local system.' @@ -27,7 +30,7 @@ inputs: description: 'Firmware app name (default, bootloader) (for firmware releases only).' required: false variant: - description: 'Variant (for docs releases only).' + description: 'Variant (public or internal).' required: false runs: @@ -101,10 +104,9 @@ runs: from private_release_api import PrivateReleaseApi from odrive.crypto import safe_b64decode - channel="0.5.4" + version="${{ inputs.version }}" - print("Channel: ", channel) - print("Commit hash: ", '${{ github.sha }}') + print("Version: ", version) print("Content key: ", '${{ steps.load-content-key.outputs.content-key }}') async def main(): @@ -121,8 +123,12 @@ runs: qualifiers['variant'] = '${{ inputs.variant }}' content_key = safe_b64decode('${{ steps.load-content-key.outputs.content-key }}') - await release_api.register_content('${{ inputs.release_type }}', '${{ github.sha }}', content_key, **qualifiers) - await release_api.register_commit('${{ inputs.release_type }}', channel, '${{ github.sha }}') - await release_api.refresh_routes('${{ inputs.release_type }}') + + # Content can only be registered once, afterwards the indicated_commit cannot be changed + if "${{ steps.load-content-key.outputs.needs-upload}}" == 'true': + await release_api.register_content('${{ inputs.release_type }}', content_key, '${{ github.sha }}') + + # Can be called multiple times with same or different parameters. No effect if called twice with the same parameters. + await release_api.register_version('${{ inputs.release_type }}', version, content_key, **qualifiers) asyncio.run(main()) diff --git a/.github/actions/upload-release/private_release_api.py b/.github/actions/upload-release/private_release_api.py index c75f61ea..269892ac 100644 --- a/.github/actions/upload-release/private_release_api.py +++ b/.github/actions/upload-release/private_release_api.py @@ -48,19 +48,25 @@ class PrivateReleaseApi(): }) return outputs - async def register_content(self, release_type: str, commit_hash: str, content_key: bytes, **qualifiers): - args = { - 'commit_hash': commit_hash, + async def register_content(self, release_type: str, content_key: bytes, indicated_commit: str): + outputs = await self._api_client.call('PUT', PrivateReleaseApi.BASE_URL + '/' + release_type + '/content', inputs={ 'content_key': b64encode(content_key), - **qualifiers - } - outputs = await self._api_client.call('PUT', PrivateReleaseApi.BASE_URL + '/' + release_type + '/content', inputs=args) + 'indicated_commit': indicated_commit, + }) return outputs['created'] - async def register_commit(self, release_type: str, channel: str, commit_hash: str): - outputs = await self._api_client.call('PUT', PrivateReleaseApi.BASE_URL + '/' + release_type + '/commit', inputs={ - 'commit_hash': commit_hash, - 'channel': channel + async def register_version(self, release_type: str, version: str, content_key: bytes, **qualifiers): + outputs = await self._api_client.call('PUT', PrivateReleaseApi.BASE_URL + '/' + release_type + '/version', inputs={ + 'version': version, + 'content_key': b64encode(content_key), + **qualifiers + }) + return outputs['created'] + + async def append_to_channel(self, release_type: str, channel: str, version: str): + outputs = await self._api_client.call('PUT', PrivateReleaseApi.BASE_URL + '/' + release_type + '/channel', inputs={ + 'channel': channel, + 'version': version, }) return outputs['published'] diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index f957a612..5ff5da14 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -2,7 +2,7 @@ name: Build and publish HTML documentation website on: push: - branches: [ master ] + branches: [ 'docs-v**' ] paths: ['docs/**', '.github/**'] jobs: @@ -10,6 +10,18 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 + + - name: Get release name and channel + id: release-info + shell: python + run: | + channel = "master" + version = "${{ github.ref }}" + assert version.startswith("refs/heads/docs-v0.5.") + version = version[len("refs/heads/docs-v"):] + + print("::set-output name=channel::" + channel) + print("::set-output name=version::" + version) - name: Cache pip uses: actions/cache@v2 @@ -32,8 +44,17 @@ jobs: uses: ./.github/actions/upload-release with: release_type: docs + version: ${{ steps.release-info.outputs.version }} src_dir: docs/_build/html do_access_key: ${{ secrets.DIGITALOCEAN_ACCESS_KEY }} do_secret_key: ${{ secrets.DIGITALOCEAN_SECRET_KEY }} odrive_api_key: ${{ secrets.ODRIVE_API_KEY }} variant: public + + - name: Add version to release channel + uses: ./.github/actions/add-version-to-channel + with: + release_type: docs + channel: ${{ steps.release-info.outputs.channel }} + version: ${{ steps.release-info.outputs.version }} + odrive_api_key: ${{ secrets.ODRIVE_API_KEY }} diff --git a/docs/conf.py b/docs/conf.py index d9c63ace..7490c08d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -25,9 +25,6 @@ project = 'ODrive Documentation' copyright = '2021, ODrive Robotics' author = 'ODrive Robotics' -# The full version, including alpha/beta/rc tags -release = '0.0' - # -- General configuration --------------------------------------------------- @@ -61,6 +58,11 @@ exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] # # html_theme = 'alabaster' html_theme = "sphinx_rtd_theme" +html_theme_options = { + 'analytics_id':'UA-93396600-3', + 'style_external_links': True, + 'display_version': True, +} # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, @@ -72,3 +74,10 @@ fibre_interface_files = ['../Firmware/odrive-interface.yaml'] autosummary_generate = False intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} + +html_js_files = [ + 'https://docs.odriverobotics.com/docsInject.js' +] + +version = "0.5.4" +release = version