diff --git a/.github/workflows/pull-request-conditionals.yaml b/.github/workflows/pull-request-conditionals.yaml index 5148890b5c..9eacd11adc 100644 --- a/.github/workflows/pull-request-conditionals.yaml +++ b/.github/workflows/pull-request-conditionals.yaml @@ -6,8 +6,9 @@ name: Filter # This workflow is triggered on pull requests on: pull_request: - branches: [main] - # milestoned is added here as a workaround for release-please not triggering PR workflows (PRs should be added to a milestone to trigger the workflow). + branches: + - main + - "release/**" # milestoned is added here as a workaround for release-please not triggering PR workflows (PRs should be added to a milestone to trigger the workflow). # labeled is added to support renovate-ready labelling on PRs types: [milestoned, labeled, opened, reopened, synchronize] paths-ignore: @@ -87,6 +88,7 @@ jobs: outputs: combined: ${{ steps.combine-path-filters.outputs.combined }} distros: ${{ steps.path-filter-iac.outputs.changes }} + run_full_tests: ${{ steps.test-routing.outputs.run_full_tests }} steps: - name: Checkout the code @@ -131,11 +133,32 @@ jobs: echo combined=$COMBINED >> $GITHUB_OUTPUT echo The following packages will be triggered: $COMBINED + - name: Compute test routing + id: test-routing + run: | + BASE="${{ github.base_ref }}" + HEAD="${{ github.head_ref }}" + COMBINED='${{ steps.combine-path-filters.outputs.combined }}' + + RUN_FULL=false + + if [[ -n "$COMBINED" && "$COMBINED" != "[]" ]]; then + if [[ "$BASE" == "main" ]]; then + RUN_FULL=true + elif [[ "$BASE" == release/* ]]; then + if [[ "$HEAD" == release-please* ]]; then + RUN_FULL=true + fi + fi + fi + + echo "run_full_tests=$RUN_FULL" >> $GITHUB_OUTPUT + # @lulaStart 11948466-9230-4498-be44-dbac784d86d1 # This job triggers a separate workflow for each changed source package, if any. run-package-test: needs: check-paths - if: ${{ needs.check-paths.outputs.combined != '' && needs.check-paths.outputs.combined != '[]' }} + if: ${{ needs.check-paths.outputs.run_full_tests == 'true' }} name: Schedule strategy: matrix: @@ -148,4 +171,21 @@ jobs: flavor: ${{ matrix.flavor }} test_type: ${{ matrix.test_type }} secrets: inherit # Inherits all secrets from the parent workflow. -# @lulaEnd 11948466-9230-4498-be44-dbac784d86d1 + # @lulaEnd 11948466-9230-4498-be44-dbac784d86d1 + + # Shim out required heavy tests for non-release-please PRs to release/*. + run-package-test-shim: + needs: check-paths + if: ${{ needs.check-paths.outputs.run_full_tests != 'true' }} + name: Schedule + strategy: + matrix: + package: [all] + flavor: [upstream, registry1, unicorn] + test_type: [install, upgrade] + uses: ./.github/workflows/test-shim.yaml + with: + package: ${{ matrix.package }} + flavor: ${{ matrix.flavor }} + test_type: ${{ matrix.test_type }} + secrets: inherit diff --git a/.github/workflows/pull-request-release.yaml b/.github/workflows/pull-request-release.yaml deleted file mode 100644 index a041cbdb38..0000000000 --- a/.github/workflows/pull-request-release.yaml +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -name: PR Backports - -# This workflow is triggered on pull requests targeting release/* -on: - pull_request: - branches: ["release/**"] - # milestoned is added here as a workaround for release-please not triggering PR workflows (PRs should be added to a milestone to trigger the workflow). - # labeled is added to support renovate-ready labelling on PRs - types: [milestoned, labeled, opened, reopened, synchronize] - -# Permissions for the GITHUB_TOKEN used by the workflow. -permissions: - id-token: write # Needed for OIDC-related operations. - contents: read # Allows reading the content of the repository. - pull-requests: write # Allows writing pull request metadata. - packages: read # Allows reading the published GHCR packages - -# Default settings for all run commands in the workflow jobs. -defaults: - run: - shell: bash -e -o pipefail {0} - -# Abort prior jobs in the same workflow / PR -concurrency: - group: test-${{ github.ref }} - cancel-in-progress: true - -jobs: - lint-check: - runs-on: ubuntu-latest - steps: - - name: "Stub: skip lint-check on fork" - if: ${{ github.repository_owner != 'defenseunicorns' }} - run: echo "[STUB] Skipping lint-check on fork" - - name: Checkout repository - if: ${{ github.repository_owner == 'defenseunicorns' }} - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: lint-check - if: ${{ github.repository_owner == 'defenseunicorns' }} - uses: ./.github/actions/lint-check - - autogenerated-check: - runs-on: ubuntu-latest - steps: - - name: "Stub: skip autogenerated-check on fork" - if: ${{ github.repository_owner != 'defenseunicorns' }} - run: echo "[STUB] Skipping autogenerated-check on fork" - - name: Checkout repository - if: ${{ github.repository_owner == 'defenseunicorns' }} - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: autogenerated-check - if: ${{ github.repository_owner == 'defenseunicorns' }} - uses: ./.github/actions/autogenerated-check - - unit-tests: - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - - name: unit-tests - uses: ./.github/actions/unit-tests - - # Full CI for Release PRs created by release-please (detect by head ref prefix) - run-package-test-full: - needs: [lint-check, autogenerated-check, unit-tests] - if: ${{ startsWith(github.head_ref, 'release-please--') }} - name: Schedule - strategy: - matrix: - package: [all] - flavor: [upstream] - test_type: [install, upgrade] - uses: ./.github/workflows/test.yaml - with: - package: ${{ matrix.package }} - flavor: ${{ matrix.flavor }} - test_type: ${{ matrix.test_type }} - target_version: ${{ github.base_ref }} - secrets: inherit - - # Shim out required heavy tests for all PRs to release/* - run-package-test-shim: - needs: [lint-check, autogenerated-check, unit-tests] - if: ${{ !startsWith(github.head_ref, 'release-please--') }} - name: Schedule - strategy: - matrix: - package: [all] - flavor: [upstream] - test_type: [install, upgrade] - uses: ./.github/workflows/test-shim.yaml - with: - package: ${{ matrix.package }} - flavor: ${{ matrix.flavor }} - test_type: ${{ matrix.test_type }} - secrets: inherit # Inherits all secrets from the parent workflow. diff --git a/.github/workflows/release-patch.yaml b/.github/workflows/release-patch.yaml deleted file mode 100644 index 7b051c623d..0000000000 --- a/.github/workflows/release-patch.yaml +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright 2024 Defense Unicorns -# SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial - -name: Patch Release UDS Core - -permissions: - contents: read - packages: read - id-token: write - -on: - push: - branches: - - "release/**" - -jobs: - tag-new-version: - permissions: write-all - runs-on: ubuntu-latest - outputs: - release_created: ${{ steps.release-flag.outputs.release_created }} - releases_created: ${{ steps.tag.outputs.releases_created }} - steps: - - name: Checkout - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 - with: - fetch-depth: 0 - - - name: Create release tag - id: tag - uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0 - with: - target-branch: ${{ github.ref_name }} - config-file: release-please-config.patch.json - - - id: release-flag - run: echo "release_created=${{ steps.tag.outputs.release_created || false }}" >> $GITHUB_OUTPUT - - publish-uds-core-release: - needs: tag-new-version - if: ${{ needs.tag-new-version.outputs.release_created == 'true'}} - permissions: - contents: write - packages: write - id-token: write - uses: ./.github/workflows/publish.yaml - with: - snapshot: false - secrets: inherit - - checkpoint-uds-core-release: - needs: publish-uds-core-release - permissions: - contents: read - packages: write - id-token: write - pull-requests: write - uses: ./.github/workflows/checkpoint.yaml - secrets: inherit diff --git a/.github/workflows/tag-and-release.yaml b/.github/workflows/tag-and-release.yaml index 6bc8b94a1d..9ff40930ea 100644 --- a/.github/workflows/tag-and-release.yaml +++ b/.github/workflows/tag-and-release.yaml @@ -13,6 +13,7 @@ on: push: branches: - main + - "release/**" jobs: # @lulaStart d364a8e6-95ab-448c-bb97-9f456c85b54f @@ -27,6 +28,9 @@ jobs: - name: Create release tag id: tag uses: googleapis/release-please-action@16a9c90856f42705d54a6fda1823352bdc62cf38 # v4.4.0 + with: + target-branch: ${{ github.ref_name }} + config-file: ${{ startsWith(github.ref, 'refs/heads/release/') && 'release-please-config.patch.json' || 'release-please-config.json' }} publish-uds-core-release: needs: tag-new-version @@ -43,7 +47,7 @@ jobs: scan-release: needs: publish-uds-core-release - if: ${{ github.repository_owner == 'defenseunicorns' }} + if: ${{ github.ref == 'refs/heads/main' }} permissions: contents: read packages: read @@ -66,8 +70,8 @@ jobs: secrets: inherit cut-release-branch: - needs: tag-new-version - if: ${{ needs.tag-new-version.outputs.release_created == 'true' }} + needs: publish-uds-core-release + if: ${{ github.ref == 'refs/heads/main' }} runs-on: ubuntu-latest permissions: contents: write diff --git a/tasks/backport.yaml b/tasks/backport.yaml index 15261dd771..5daa1def83 100644 --- a/tasks/backport.yaml +++ b/tasks/backport.yaml @@ -1,17 +1,20 @@ -# Copyright 2024 Defense Unicorns +# Copyright 2025 Defense Unicorns # SPDX-License-Identifier: AGPL-3.0-or-later OR LicenseRef-Defense-Unicorns-Commercial tasks: - name: backport description: "Create a backport branch from release/* and cherry-pick commits" inputs: - target_version: - description: "Target minor version (e.g., 0.54)" - commits: - description: "Comma-separated list of commit SHAs to cherry-pick, in order" - name: - description: "Optional short name to include in branch name (defaults to first SHA)" - default: "" + target_versions: + description: "Comma-separated target minor versions (e.g., 0.54,0.55)" + required: true + commit: + description: "Single commit SHA to cherry-pick" + required: true + auto_pr: + description: "Automatically open PRs for each backport branch" + default: "true" + actions: - description: "Create backport branch and cherry-pick commits" shell: @@ -25,52 +28,93 @@ tasks: echo "Working tree is dirty. Please commit or stash your changes before running the backport task." >&2 exit 1 fi - TV='${{ .inputs.target_version }}' - COMMITS='${{ .inputs.commits }}' - NAME_INPUT='${{ .inputs.name }}' + TVS='${{ .inputs.target_versions }}' + COMMIT='${{ .inputs.commit }}' + AUTO_PR='${{ .inputs.auto_pr }}' + NAME="$(echo "$COMMIT" | xargs)" - if [[ -z "$TV" ]]; then - echo "target_version input is required (e.g., 0.54)" >&2 - exit 1 - fi - - RB="release/${TV}" git fetch origin --tags - if ! git show-ref --verify --quiet "refs/remotes/origin/${RB}"; then - echo "Remote branch ${RB} not found. Ensure it exists (cut from v${TV}.0) or create it first." >&2 - exit 1 - fi - MINOR="$TV" + MINOR_LIST=() + IFS=',' read -ra MINOR_LIST <<< "$TVS" - if [[ -z "$COMMITS" ]]; then - echo "No commits specified. Provide 'prs' and/or 'commits'." >&2 - exit 1 - fi + for MINOR in "${MINOR_LIST[@]}"; do + MINOR="$(echo "$MINOR" | xargs)" + if [[ -z "$MINOR" ]]; then + continue + fi + RB="release/${MINOR}" + if ! git show-ref --verify --quiet "refs/remotes/origin/${RB}"; then + echo "Remote branch ${RB} not found. Ensure it exists (cut from v${MINOR}.0) or create it first." >&2 + exit 1 + fi - if [[ -z "$NAME_INPUT" ]]; then - NAME_INPUT="$(echo "$COMMITS" | cut -d',' -f1 | xargs)" - fi + BRANCH="backport/${NAME}-to-${MINOR}" + BRANCH="${BRANCH// /-}" + BRANCH="$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]')" + + echo "Creating branch: ${BRANCH} from ${RB}" + git switch -c "${BRANCH}" "origin/${RB}" + + C="$(echo "$COMMIT" | xargs)" + echo "Cherry-picking ${C} into ${BRANCH}..." + + # Suppress noisy git output; on failure, show clear next steps instead. + if ! git cherry-pick -x "$C" >/dev/null 2>&1; then + echo + echo "======================================================================" + echo "Backport to ${RB} hit conflicts while cherry-picking ${C}." + echo "You are now on branch: ${BRANCH}" + echo + echo "To resolve the conflicts and finish this backport, run (copy/paste):" + echo + echo " git status" + echo " # edit files to resolve conflicts" + echo " git add " + echo " git cherry-pick --continue" + echo " git push -u origin ${BRANCH}" + echo + DEFAULT_TITLE="$(git log -1 --pretty=%s "$COMMIT" 2>/dev/null || echo "")" + if [[ -z "${DEFAULT_TITLE}" ]]; then + DEFAULT_TITLE="chore: backport of ${COMMIT}" + fi + TITLE="${DEFAULT_TITLE} (backport-${MINOR})" + BODY="Backport of commit: ${COMMIT}" + + if command -v gh >/dev/null 2>&1; then + echo " gh pr create --title \"${TITLE}\" --body \"${BODY}\" --base \"${RB}\" --head \"${BRANCH}\"" + else + echo " # After pushing, open a PR with base=${RB} and compare=${BRANCH}" + fi - BRANCH="backport/${NAME_INPUT}-to-${MINOR}" - BRANCH="${BRANCH// /-}" - BRANCH="$(echo "$BRANCH" | tr '[:upper:]' '[:lower:]')" + if [[ -n "${CURR_BRANCH}" ]]; then + echo + echo "After finishing the backport and pushing, you can return to your original branch with:" + echo + echo " git switch ${CURR_BRANCH}" + fi + echo "======================================================================" + exit 1 + fi + + git push -u origin "${BRANCH}" >/dev/null 2>&1 + + DEFAULT_TITLE="$(git log -1 --pretty=%s "$COMMIT" 2>/dev/null || echo "")" + if [[ -z "${DEFAULT_TITLE}" ]]; then + DEFAULT_TITLE="chore: backport of ${COMMIT}" + fi + TITLE="${DEFAULT_TITLE} (backport-${MINOR})" + BODY="Backport of commit: ${COMMIT}" - echo "Creating branch: ${BRANCH} from ${RB}" - git switch -c "${BRANCH}" "origin/${RB}" + echo "✅ Backport branch created and pushed: ${BRANCH} (base: ${RB})" - IFS=',' read -ra ARR <<< "$COMMITS" - for C in "${ARR[@]}"; do - C="$(echo "$C" | xargs)" - if [[ -n "$C" ]]; then - echo "Cherry-picking ${C}" - git cherry-pick -x "$C" + if [[ "${AUTO_PR}" == "true" ]] && command -v gh >/dev/null 2>&1; then + gh pr create --title "${TITLE}" --body "${BODY}" --base "${RB}" --head "${BRANCH}" >/dev/null 2>&1 || true + else + echo " # After pushing, open a PR with base=${RB} and compare=${BRANCH}" fi done - git push -u origin "${BRANCH}" - echo "Backport branch created: ${BRANCH}" - echo "Open a PR with base=${RB} and compare=${BRANCH}" if [[ -n "$CURR_BRANCH" ]]; then git switch "$CURR_BRANCH" echo "Returned to branch: $CURR_BRANCH" diff --git a/tasks/deploy.yaml b/tasks/deploy.yaml index 6c1a32b215..39fe217c14 100644 --- a/tasks/deploy.yaml +++ b/tasks/deploy.yaml @@ -120,39 +120,25 @@ tasks: uds zarf package deploy build/zarf-package-core-${{ index .inputs "layer" }}-${UDS_ARCH}-${VERSION}.tar.zst --confirm --no-progress --components '*' fi - - name: latest-bundle-release - inputs: - configFile: - description: "UDS_CONFIG file to use for the deployment" + - name: resolve-latest-core-release actions: - task: utils:determine-repo - - description: "Get latest tag version from OCI (optionally pinned to TARGET_VERSION minor stream)" + - description: "Get latest tag version from OCI (conditionally pinned to TARGET_VERSION minor stream)" shell: darwin: bash linux: bash cmd: | - if [ "${STUB_MODE}" = "true" ]; then - if [ -n "${TARGET_VERSION}" ]; then - echo "[STUB] TARGET_VERSION='${TARGET_VERSION}'" - echo "[STUB] Command: uds zarf tools registry ls ${TARGET_REPO}/core | grep \"${FLAVOR}\" | grep -E \"^${TARGET_VERSION}\\.\" | sort -V | tail -1" - else - echo "[STUB] TARGET_VERSION is unset" - echo "[STUB] Command: uds zarf tools registry ls ${TARGET_REPO}/core | grep \"${FLAVOR}\" | sort -V | tail -1" - fi - echo "unknown-latest-${FLAVOR}" + BRANCH="${GITHUB_HEAD_REF:-${GITHUB_REF_NAME:-$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")}}" + + TARGET_VERSION="" + if [[ "$BRANCH" == release-please--branches--release/* ]]; then + TARGET_VERSION="${BRANCH#release-please--branches--release/}" + fi + + if [ -n "${TARGET_VERSION}" ]; then + uds zarf tools registry ls ${TARGET_REPO}/core | grep "${FLAVOR}" | grep -E "^${TARGET_VERSION}\\." | sort -V | tail -1 else - set +e - if [ -n "${TARGET_VERSION}" ]; then - RES=$(uds zarf tools registry ls ${TARGET_REPO}/core 2>/dev/null | grep "${FLAVOR}" | grep -E "^${TARGET_VERSION}\\." | sort -V | tail -1) - else - RES=$(uds zarf tools registry ls ${TARGET_REPO}/core 2>/dev/null | grep "${FLAVOR}" | sort -V | tail -1) - fi - set -e - if [ -z "$RES" ]; then - echo "unknown-latest-${FLAVOR}" - else - echo "$RES" - fi + uds zarf tools registry ls ${TARGET_REPO}/core | grep "${FLAVOR}" | sort -V | tail -1 fi setVariables: - name: LATEST_VERSION @@ -160,9 +146,16 @@ tasks: cmd: echo ${LATEST_VERSION} | cut -d'-' -f1 # Extract version before any hyphen (e.g., "0.52.0" from "0.52.0-upstream") setVariables: - name: LATEST_CORE_TAG + + - name: latest-bundle-release + inputs: + configFile: + description: "UDS_CONFIG file to use for the deployment" + actions: + - task: resolve-latest-core-release - description: "Upgrade plan" cmd: | - echo "Upgrading FROM ${LATEST_VERSION} TO ${VERSION} (flavor=${FLAVOR})" + echo "Upgrading FROM ${LATEST_VERSION} (tag ${LATEST_CORE_TAG}) TO main (flavor=${FLAVOR})" - description: "Create the latest version with bundle overrides" cmd: | if [ "${STUB_MODE}" = "true" ]; then @@ -203,41 +196,7 @@ tasks: - name: latest-release-test-resources actions: - - task: utils:determine-repo - - description: "Get latest tag version from OCI for aligning test resources (optionally pinned to TARGET_VERSION minor stream)" - shell: - darwin: bash - linux: bash - cmd: | - if [ "${STUB_MODE}" = "true" ]; then - if [ -n "${TARGET_VERSION}" ]; then - echo "[STUB] TARGET_VERSION='${TARGET_VERSION}'" - echo "[STUB] Command: uds zarf tools registry ls ${TARGET_REPO}/core | grep \"${FLAVOR}\" | grep -E \"^${TARGET_VERSION}\\.\" | sort -V | tail -1" - else - echo "[STUB] TARGET_VERSION is unset" - echo "[STUB] Command: uds zarf tools registry ls ${TARGET_REPO}/core | grep \"${FLAVOR}\" | sort -V | tail -1" - fi - echo "unknown-latest-${FLAVOR}" - else - set +e - if [ -n "${TARGET_VERSION}" ]; then - RES=$(uds zarf tools registry ls ${TARGET_REPO}/core 2>/dev/null | grep "${FLAVOR}" | grep -E "^${TARGET_VERSION}\\." | sort -V | tail -1) - else - RES=$(uds zarf tools registry ls ${TARGET_REPO}/core 2>/dev/null | grep "${FLAVOR}" | sort -V | tail -1) - fi - set -e - if [ -z "$RES" ]; then - echo "unknown-latest-${FLAVOR}" - else - echo "$RES" - fi - fi - setVariables: - - name: LATEST_VERSION - - description: "Extract unflavored version for git tag" - cmd: echo ${LATEST_VERSION} | cut -d'-' -f1 # Extract version before any hyphen (e.g., "0.52.0" from "0.52.0-upstream") - setVariables: - - name: LATEST_CORE_TAG + - task: resolve-latest-core-release - description: "Fetch src/test from tagged release" cmd: | if [ "${STUB_MODE}" = "true" ]; then