diff --git a/.github/workflows/build-all-images.yaml b/.github/workflows/build-all-images.yaml index 08b2bbb..1d546a9 100644 --- a/.github/workflows/build-all-images.yaml +++ b/.github/workflows/build-all-images.yaml @@ -62,6 +62,12 @@ jobs: platform: [linux/amd64, linux/arm64] ros-distro: [humble, jazzy] steps: + - name: Checkout OpenADKit repository + uses: actions/checkout@v6 + + - name: Free Disk Space (Ubuntu) + uses: ./.github/actions/free-disk-space + - name: Install jq and vcs2l run: | sudo apt-get update @@ -69,9 +75,6 @@ jobs: pipx install vcs2l shell: bash - - name: Checkout OpenADKit repository - uses: actions/checkout@v6 - - name: Checkout Autoware repository uses: actions/checkout@v6 with: @@ -159,6 +162,8 @@ jobs: *.platform=${{ matrix.platform }} *.args.ROS_DISTRO=${{ matrix.ros-distro }} *.args.BASE_IMAGE=ros:${{ matrix.ros-distro }}-ros-base-${{ matrix.ros-distro == 'jazzy' && 'noble' || 'jammy' }} + *.labels."org.opencontainers.image.build-tag"=${{ needs.prepare.outputs.build_tag }} + *.labels."org.opencontainers.image.run-id"=${{ github.run_id }} *.cache-from=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:common-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-main *.cache-to=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:common-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-main,mode=max @@ -178,6 +183,8 @@ jobs: *.platform=${{ matrix.platform }} *.args.ROS_DISTRO=${{ matrix.ros-distro }} *.args.BASE_IMAGE=ros:${{ matrix.ros-distro }}-ros-base-${{ matrix.ros-distro == 'jazzy' && 'noble' || 'jammy' }} + *.labels."org.opencontainers.image.build-tag"=${{ needs.prepare.outputs.build_tag }} + *.labels."org.opencontainers.image.run-id"=${{ github.run_id }} *.cache-from=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:common-cuda-${{ matrix.ros-distro }}-main *.cache-to=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:common-cuda-${{ matrix.ros-distro }}-main,mode=max @@ -213,6 +220,12 @@ jobs: ros-distro: jazzy target: sensing-perception-cuda steps: + - name: Checkout OpenADKit repository + uses: actions/checkout@v6 + + - name: Free Disk Space (Ubuntu) + uses: ./.github/actions/free-disk-space + - name: Install jq and vcs2l run: | sudo apt-get update @@ -220,9 +233,6 @@ jobs: pipx install vcs2l shell: bash - - name: Checkout OpenADKit repository - uses: actions/checkout@v6 - - name: Checkout Autoware repository uses: actions/checkout@v6 with: @@ -274,6 +284,8 @@ jobs: *.args.COMMON_BASE_CUDA_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:base-cuda-amd64-${{ matrix.ros-distro }}-${{ needs.prepare.outputs.build_tag }} *.args.COMMON_DEVEL_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:devel-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-${{ needs.prepare.outputs.build_tag }} *.args.COMMON_DEVEL_CUDA_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:devel-cuda-amd64-${{ matrix.ros-distro }}-${{ needs.prepare.outputs.build_tag }} + *.labels."org.opencontainers.image.build-tag"=${{ needs.prepare.outputs.build_tag }} + *.labels."org.opencontainers.image.run-id"=${{ github.run_id }} *.cache-from=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:${{ matrix.target }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-main *.cache-to=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:${{ matrix.target }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-main,mode=max @@ -374,6 +386,8 @@ jobs: *.args.API_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:api-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-${{ needs.prepare.outputs.build_tag }} *.args.VISUALIZER_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:visualizer-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-${{ needs.prepare.outputs.build_tag }} *.args.SIMULATOR_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:simulator-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-${{ needs.prepare.outputs.build_tag }} + *.labels."org.opencontainers.image.build-tag"=${{ needs.prepare.outputs.build_tag }} + *.labels."org.opencontainers.image.run-id"=${{ github.run_id }} *.cache-from=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:${{ matrix.target }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-main *.cache-to=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:${{ matrix.target }}-${{ matrix.platform == 'linux/amd64' && 'amd64' || 'arm64' }}-${{ matrix.ros-distro }}-main,mode=max @@ -417,3 +431,44 @@ jobs: universe universe-cuda token: ${{ secrets.GITHUB_TOKEN }} + + summarize: + runs-on: ubuntu-latest + needs: [prepare, create-manifests] + if: success() + steps: + - name: Write job summary + run: | + { + echo "## Build Complete" + echo "| Key | Value |" + echo "|-----|-------|" + echo "| **build_tag** | \`${{ needs.prepare.outputs.build_tag }}\` |" + echo "| **autoware_ref** | \`${{ needs.prepare.outputs.autoware_ref }}\` |" + echo "" + echo "To release this build:" + echo "1. Go to **Actions → release → Run workflow**" + echo "2. Set \`build_tag\` to \`${{ needs.prepare.outputs.build_tag }}\`" + } >> $GITHUB_STEP_SUMMARY + + notify-failure: + runs-on: ubuntu-latest + needs: [prepare, build-common, build-components, build-universe, create-manifests] + if: failure() && github.event_name == 'schedule' + permissions: + issues: write + steps: + - name: Create failure issue + uses: actions/github-script@v7 + with: + script: | + await github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: `Scheduled build failed (${new Date().toISOString().split('T')[0]})`, + body: [ + '**Scheduled build-all-images workflow failed.**', + '', + `Run: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`, + ].join('\n'), + }) diff --git a/.github/workflows/deploy-docs.yaml b/.github/workflows/deploy-docs.yaml index 60034e7..fa8397f 100644 --- a/.github/workflows/deploy-docs.yaml +++ b/.github/workflows/deploy-docs.yaml @@ -36,17 +36,7 @@ jobs: python-version: '3.11' - name: Install dependencies - run: | - pip install mkdocs-material - pip install mkdocs-awesome-pages-plugin - pip install mkdocs-exclude - pip install mkdocs-macros-plugin - pip install mkdocs-same-dir - pip install pymdown-extensions - pip install python-markdown-math - pip install mdx-truly-sane-lists - pip install plantuml-markdown - pip install mkdocs-mermaid2-plugin + run: pip install -r docs/requirements.txt - name: Build with MkDocs run: mkdocs build --clean --verbose diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..b78b315 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,19 @@ +name: lint + +on: + pull_request: + paths: + - '**/*.sh' + +jobs: + shellcheck: + runs-on: ubuntu-latest + continue-on-error: true + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Run ShellCheck + uses: ludeeus/action-shellcheck@2.0.0 + with: + severity: error diff --git a/.github/workflows/release-all-images.yaml b/.github/workflows/release-all-images.yaml deleted file mode 100644 index 9356760..0000000 --- a/.github/workflows/release-all-images.yaml +++ /dev/null @@ -1,366 +0,0 @@ -name: release-all-images - -on: - schedule: - - cron: "0 */6 * * *" - workflow_dispatch: - inputs: - autoware_tag: - description: The Autoware tag to release - required: true - -env: - REGISTRY: ghcr.io - IMAGE_PREFIX_COMMON: ghcr.io/${{ github.repository_owner }}/openadkit-common - IMAGE_PREFIX_COMPONENT: ghcr.io/${{ github.repository_owner }}/openadkit - BAKE_FILE: components/docker-bake.hcl - -jobs: - detect-autoware-tag: - name: Detect latest Autoware release tag - runs-on: ubuntu-latest - permissions: - contents: read - outputs: - autoware_tag: ${{ steps.latest.outputs.tag }} - should_run: ${{ steps.decide.outputs.should_run }} - steps: - - name: Install jq - run: | - sudo apt-get update - sudo apt-get install -y jq - - - name: Validate manual tag format - if: github.event_name == 'workflow_dispatch' - run: | - echo "${{ inputs.autoware_tag }}" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \ - || (echo "Invalid tag format '${{ inputs.autoware_tag }}': must be X.Y.Z" && exit 1) - - - name: Get latest upstream semver tag (e.g. 1.2.3) - id: latest - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - set -euo pipefail - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - tag="${{ inputs.autoware_tag }}" - else - tags_json=$(curl -fsSL -H "Authorization: Bearer $GH_TOKEN" "https://api.github.com/repos/autowarefoundation/autoware/tags?per_page=3") - tag=$( - echo "$tags_json" \ - | jq -r '.[].name' \ - | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' \ - | sort -V \ - | tail -n 1 - ) - fi - [ -n "$tag" ] || (echo "No semver tag found" && exit 1) - echo "tag=$tag" >> "$GITHUB_OUTPUT" - echo "Tag: $tag" - - - name: Cache lookup for processed tag - id: cache - uses: actions/cache@v4 - with: - path: .autoware-tag-marker - key: autoware-tag-${{ steps.latest.outputs.tag }} - restore-keys: | - autoware-tag- - - - name: Decide whether to run - id: decide - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "should_run=true" >> "$GITHUB_OUTPUT" - echo "Manual dispatch — forcing run for tag ${{ steps.latest.outputs.tag }}" - elif [ "${{ steps.cache.outputs.cache-hit }}" = "true" ]; then - echo "should_run=false" >> "$GITHUB_OUTPUT" - echo "Already processed tag ${{ steps.latest.outputs.tag }}" - else - echo "should_run=true" >> "$GITHUB_OUTPUT" - echo "New tag detected: ${{ steps.latest.outputs.tag }}" - fi - - - name: Create marker (so cache gets saved) - if: steps.decide.outputs.should_run == 'true' - run: | - mkdir -p .autoware-tag-marker - echo "${{ steps.latest.outputs.tag }}" > .autoware-tag-marker/tag.txt - - # ============================================================================= - # Stage 1: Build common images - # ============================================================================= - build-common: - runs-on: ubuntu-22.04 - needs: detect-autoware-tag - if: needs.detect-autoware-tag.outputs.should_run == 'true' - permissions: - contents: read - packages: write - steps: - - name: Install jq and vcs2l - run: | - sudo apt-get update - sudo apt-get install -y jq python3-pip - pip install --no-cache-dir vcs2l - shell: bash - - - name: Checkout OpenADKit repository - uses: actions/checkout@v6 - - - name: Checkout Autoware repository - uses: actions/checkout@v6 - with: - repository: autowarefoundation/autoware - ref: ${{ needs.detect-autoware-tag.outputs.autoware_tag }} - path: autoware - fetch-depth: 1 - - - name: Pull Autoware Source - run: | - mkdir -p autoware/src - vcs import --shallow autoware/src < autoware/repositories/autoware.repos - shell: bash - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata for openadkit-common:base - id: meta-common-base - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_PREFIX_COMMON }} - bake-target: docker-metadata-action-common-base - tags: | - type=raw,value=base-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - flavor: | - latest=false - - - name: Extract metadata for openadkit-common:base-cuda - id: meta-common-base-cuda - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_PREFIX_COMMON }} - bake-target: docker-metadata-action-common-base-cuda - tags: | - type=raw,value=base-cuda-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - flavor: | - latest=false - - - name: Extract metadata for openadkit-common:devel - id: meta-common-devel - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_PREFIX_COMMON }} - bake-target: docker-metadata-action-common-devel - tags: | - type=raw,value=devel-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - flavor: | - latest=false - - - name: Extract metadata for openadkit-common:devel-cuda - id: meta-common-devel-cuda - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_PREFIX_COMMON }} - bake-target: docker-metadata-action-common-devel-cuda - tags: | - type=raw,value=devel-cuda-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - flavor: | - latest=false - - - name: Build and push common images - uses: docker/bake-action@v5 - with: - files: | - ${{ env.BAKE_FILE }} - ${{ steps.meta-common-base.outputs.bake-file }} - ${{ steps.meta-common-base-cuda.outputs.bake-file }} - ${{ steps.meta-common-devel.outputs.bake-file }} - ${{ steps.meta-common-devel-cuda.outputs.bake-file }} - targets: | - common-base - common-base-cuda - common-devel - common-devel-cuda - push: true - set: | - *.cache-from=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:common-main - *.cache-to=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:common-main,mode=max - - # ============================================================================= - # Stage 2: Build component images (parallel) - # ============================================================================= - build-components: - runs-on: ubuntu-22.04 - needs: [build-common, detect-autoware-tag] - if: needs.detect-autoware-tag.outputs.should_run == 'true' - permissions: - contents: read - packages: write - strategy: - fail-fast: false - matrix: - include: - - target: sensing-perception - - target: sensing-perception-cuda - - target: localization-mapping - - target: planning-control - - target: vehicle-system - - target: api - - target: visualizer - - target: simulator - steps: - - name: Install jq and vcs2l - run: | - sudo apt-get update - sudo apt-get install -y jq python3-pip - pip install --no-cache-dir vcs2l - shell: bash - - - name: Checkout OpenADKit repository - uses: actions/checkout@v6 - - - name: Checkout Autoware repository - uses: actions/checkout@v6 - with: - repository: autowarefoundation/autoware - ref: ${{ needs.detect-autoware-tag.outputs.autoware_tag }} - path: autoware - fetch-depth: 1 - - - name: Pull Autoware Source - run: | - mkdir -p autoware/src - vcs import --shallow autoware/src < autoware/repositories/autoware.repos - shell: bash - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata for ${{ matrix.target }} - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_PREFIX_COMPONENT }} - bake-target: docker-metadata-action-${{ matrix.target }} - tags: | - type=raw,value=${{ matrix.target }}-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - flavor: | - latest=false - - - name: Build and push ${{ matrix.target }} - uses: docker/bake-action@v5 - with: - files: | - ${{ env.BAKE_FILE }} - ${{ steps.meta.outputs.bake-file }} - targets: ${{ matrix.target }} - push: true - set: | - *.args.COMMON_BASE_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:base-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.COMMON_BASE_CUDA_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:base-cuda-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.COMMON_DEVEL_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:devel-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.COMMON_DEVEL_CUDA_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:devel-cuda-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.cache-from=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:${{ matrix.target }}-main - *.cache-to=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:${{ matrix.target }}-main,mode=max - - # ============================================================================= - # Stage 3: Build universe and universe-cuda images (parallel) - # ============================================================================= - build-universe: - runs-on: ubuntu-22.04 - needs: [detect-autoware-tag, build-common, build-components] - if: needs.detect-autoware-tag.outputs.should_run == 'true' - permissions: - contents: read - packages: write - strategy: - fail-fast: false - matrix: - include: - - target: universe - - target: universe-cuda - steps: - - name: Install jq and vcs2l - run: | - sudo apt-get update - sudo apt-get install -y jq python3-pip - pip install --no-cache-dir vcs2l - shell: bash - - - name: Checkout OpenADKit repository - uses: actions/checkout@v6 - - - name: Checkout Autoware repository - uses: actions/checkout@v6 - with: - repository: autowarefoundation/autoware - ref: ${{ needs.detect-autoware-tag.outputs.autoware_tag }} - path: autoware - fetch-depth: 1 - - - name: Pull Autoware Source - run: | - mkdir -p autoware/src - vcs import --shallow autoware/src < autoware/repositories/autoware.repos - shell: bash - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - - - name: Log in to Container Registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Extract metadata for ${{ matrix.target }} - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.IMAGE_PREFIX_COMPONENT }} - bake-target: docker-metadata-action-${{ matrix.target }} - tags: | - type=raw,value=${{ matrix.target }}-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - flavor: | - latest=false - - - name: Build and push ${{ matrix.target }} - uses: docker/bake-action@v5 - with: - files: | - ${{ env.BAKE_FILE }} - ${{ steps.meta.outputs.bake-file }} - targets: ${{ matrix.target }} - push: true - set: | - *.args.COMMON_BASE_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:base-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.COMMON_BASE_CUDA_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:base-cuda-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.COMMON_DEVEL_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:devel-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.COMMON_DEVEL_CUDA_IMAGE=${{ env.IMAGE_PREFIX_COMMON }}:devel-cuda-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.SENSING_PERCEPTION_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:sensing-perception-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.SENSING_PERCEPTION_CUDA_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:sensing-perception-cuda-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.LOCALIZATION_MAPPING_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:localization-mapping-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.PLANNING_CONTROL_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:planning-control-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.VEHICLE_SYSTEM_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:vehicle-system-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.API_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:api-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.VISUALIZER_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:visualizer-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.args.SIMULATOR_IMAGE=${{ env.IMAGE_PREFIX_COMPONENT }}:simulator-${{ needs.detect-autoware-tag.outputs.autoware_tag }} - *.cache-from=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:${{ matrix.target }}-main - *.cache-to=type=registry,ref=ghcr.io/${{ github.repository_owner }}/openadkit-buildcache:${{ matrix.target }}-main,mode=max diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..c737988 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,178 @@ +name: release + +on: + workflow_dispatch: + inputs: + version: + description: 'Release version (e.g. v1.0.0)' + required: true + build_tag: + description: 'Build tag to promote (e.g. 20260422-123456789-1)' + required: true + +concurrency: + group: release + cancel-in-progress: false + +env: + REGISTRY: ghcr.io + IMAGE_PREFIX_COMMON: ghcr.io/${{ github.repository_owner }}/openadkit-common + IMAGE_PREFIX_COMPONENT: ghcr.io/${{ github.repository_owner }}/openadkit + +jobs: + # ============================================================================= + # Stage 1: Validate inputs before touching anything + # ============================================================================= + validate: + runs-on: ubuntu-22.04 + permissions: + actions: read + contents: read + packages: read + outputs: + sha: ${{ steps.get-sha.outputs.sha }} + steps: + - name: Validate version format + run: | + echo "${{ inputs.version }}" | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' \ + || (echo "Invalid version format '${{ inputs.version }}': must be vX.Y.Z" && exit 1) + + - name: Validate build_tag format + run: | + echo "${{ inputs.build_tag }}" | grep -E '^[0-9]{8}-[0-9]+-[0-9]+$' \ + || (echo "Invalid build_tag format '${{ inputs.build_tag }}': must be YYYYMMDD-RUNID-ATTEMPT" && exit 1) + + - name: Check release runs from main branch + run: | + [ "${{ github.ref }}" = "refs/heads/main" ] \ + || (echo "Release must be triggered from main branch (got ${{ github.ref }})" && exit 1) + + - name: Validate source build run + id: get-sha + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + set -euo pipefail + run_id=$(echo "${{ inputs.build_tag }}" | cut -d'-' -f2) + run_attempt=$(echo "${{ inputs.build_tag }}" | cut -d'-' -f3) + run_json=$(gh api repos/${{ github.repository }}/actions/runs/${run_id}/attempts/${run_attempt}) + + workflow_name=$(printf '%s' "$run_json" | jq -r '.name') + workflow_path=$(printf '%s' "$run_json" | jq -r '.path') + head_branch=$(printf '%s' "$run_json" | jq -r '.head_branch') + status=$(printf '%s' "$run_json" | jq -r '.status') + conclusion=$(printf '%s' "$run_json" | jq -r '.conclusion') + sha=$(printf '%s' "$run_json" | jq -r '.head_sha') + + [ "$workflow_name" = "build-all-images" ] || (echo "Expected build-all-images run, got '${workflow_name}'" && exit 1) + [ "$workflow_path" = ".github/workflows/build-all-images.yaml" ] || (echo "Unexpected workflow path '${workflow_path}'" && exit 1) + [ "$head_branch" = "main" ] || (echo "Source build must come from main branch (got '${head_branch}')" && exit 1) + [ "$status" = "completed" ] || (echo "Source build must be completed (got '${status}')" && exit 1) + [ "$conclusion" = "success" ] || (echo "Source build must succeed (got '${conclusion}')" && exit 1) + + [ -n "$sha" ] || (echo "Could not resolve SHA for run_id ${run_id} attempt ${run_attempt}" && exit 1) + echo "sha=${sha}" >> "$GITHUB_OUTPUT" + + - name: Check git tag does not already exist + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + if gh api repos/${{ github.repository }}/git/refs/tags/${{ inputs.version }} 2>/dev/null; then + echo "Tag ${{ inputs.version }} already exists — aborting to prevent duplicate release" + exit 1 + fi + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Verify build_tag exists in registry + run: | + docker buildx imagetools inspect \ + ${{ env.IMAGE_PREFIX_COMMON }}:base-humble-${{ inputs.build_tag }} \ + || (echo "build_tag '${{ inputs.build_tag }}' not found in registry" && exit 1) + + # ============================================================================= + # Stage 2: Promote all images to release tag + # ============================================================================= + release-images: + runs-on: ubuntu-22.04 + needs: validate + permissions: + contents: read + packages: write + steps: + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Promote all images to ${{ inputs.version }} + run: | + set -euo pipefail + BUILD_TAG="${{ inputs.build_tag }}" + VERSION="${{ inputs.version }}" + COMMON="${{ env.IMAGE_PREFIX_COMMON }}" + COMPONENT="${{ env.IMAGE_PREFIX_COMPONENT }}" + + DISTROS="humble jazzy" + COMMON_VARIANTS="base base-cuda devel devel-cuda" + COMPONENT_TARGETS="sensing-perception sensing-perception-cuda localization-mapping planning-control vehicle-system api visualizer simulator universe universe-cuda" + + for distro in ${DISTROS}; do + for variant in ${COMMON_VARIANTS}; do + echo "Promoting ${COMMON}:${variant}-${distro}-${BUILD_TAG} → ${VERSION}" + docker buildx imagetools create \ + -t "${COMMON}:${variant}-${distro}-${VERSION}" \ + "${COMMON}:${variant}-${distro}-${BUILD_TAG}" + done + for target in ${COMPONENT_TARGETS}; do + echo "Promoting ${COMPONENT}:${target}-${distro}-${BUILD_TAG} → ${VERSION}" + docker buildx imagetools create \ + -t "${COMPONENT}:${target}-${distro}-${VERSION}" \ + "${COMPONENT}:${target}-${distro}-${BUILD_TAG}" + done + done + + # ============================================================================= + # Stage 3: Create git tag and GitHub Release + # ============================================================================= + release-github: + runs-on: ubuntu-22.04 + needs: [validate, release-images] + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Create git tag + uses: actions/github-script@v7 + with: + script: | + await github.rest.git.createRef({ + owner: context.repo.owner, + repo: context.repo.repo, + ref: 'refs/tags/${{ inputs.version }}', + sha: '${{ needs.validate.outputs.sha }}' + }) + console.log('Created tag ${{ inputs.version }} at ${{ needs.validate.outputs.sha }}') + + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "${{ inputs.version }}" \ + --title "OpenADKit ${{ inputs.version }}" \ + --generate-notes diff --git a/.github/workflows/scan.yaml b/.github/workflows/scan.yaml new file mode 100644 index 0000000..4acc884 --- /dev/null +++ b/.github/workflows/scan.yaml @@ -0,0 +1,68 @@ +name: scan-images + +on: + workflow_run: + workflows: [build-all-images] + types: [completed] + schedule: + - cron: '0 6 * * 1' + workflow_dispatch: + +env: + REGISTRY: ghcr.io + IMAGE_PREFIX_COMPONENT: ghcr.io/${{ github.repository_owner }}/openadkit + +jobs: + scan: + if: ${{ github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' }} + runs-on: ubuntu-latest + permissions: + contents: read + packages: read + security-events: write + strategy: + fail-fast: false + matrix: + ros-distro: [humble, jazzy] + target: [universe, sensing-perception, localization-mapping, planning-control] + steps: + - name: Resolve image reference + id: image + shell: bash + run: | + set -euo pipefail + + if [ "${{ github.event_name }}" = "workflow_run" ]; then + run_started_at="${{ github.event.workflow_run.run_started_at }}" + if [ -z "$run_started_at" ]; then + run_started_at="${{ github.event.workflow_run.created_at }}" + fi + + build_date=$(date -u -d "$run_started_at" +%Y%m%d) + build_tag="${build_date}-${{ github.event.workflow_run.id }}-${{ github.event.workflow_run.run_attempt }}" + echo "image_ref=${{ env.IMAGE_PREFIX_COMPONENT }}:${{ matrix.target }}-${{ matrix.ros-distro }}-${build_tag}" >> "$GITHUB_OUTPUT" + else + echo "image_ref=${{ env.IMAGE_PREFIX_COMPONENT }}:${{ matrix.target }}-${{ matrix.ros-distro }}" >> "$GITHUB_OUTPUT" + fi + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Scan ${{ matrix.target }}-${{ matrix.ros-distro }} + uses: aquasecurity/trivy-action@0.30.0 + with: + image-ref: ${{ steps.image.outputs.image_ref }} + format: sarif + output: trivy-${{ matrix.target }}-${{ matrix.ros-distro }}.sarif + exit-code: '0' + severity: CRITICAL,HIGH + + - name: Upload scan results to GitHub Security + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: trivy-${{ matrix.target }}-${{ matrix.ros-distro }}.sarif + category: ${{ matrix.target }}-${{ matrix.ros-distro }} diff --git a/.github/workflows/setup-docker.yaml b/.github/workflows/setup-docker.yaml index babb45e..0bd2d9d 100644 --- a/.github/workflows/setup-docker.yaml +++ b/.github/workflows/setup-docker.yaml @@ -3,13 +3,15 @@ name: setup-docker on: workflow_dispatch: pull_request: + paths: + - 'setup.sh' jobs: setup-docker: runs-on: ubuntu-22.04 steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Run setup script run: | diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000..42c81be --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1,10 @@ +mkdocs-material~=9.5 +mkdocs-awesome-pages-plugin~=2.9 +mkdocs-exclude~=1.0 +mkdocs-macros-plugin~=1.3 +mkdocs-same-dir~=0.1 +pymdown-extensions~=10.11 +python-markdown-math~=0.8 +mdx-truly-sane-lists~=1.3 +plantuml-markdown~=3.9 +mkdocs-mermaid2-plugin~=1.1