diff --git a/.github/workflows/CI-actions.yml b/.github/workflows/CI-actions.yml index 0546aa1..7e1aa55 100644 --- a/.github/workflows/CI-actions.yml +++ b/.github/workflows/CI-actions.yml @@ -7,19 +7,13 @@ on: paths: - '.github/actions/**' jobs: - test-actions: - runs-on: ubuntu-latest - defaults: - run: - shell: pwsh - steps: - - name: Placeholder - run: echo "Placeholder for testing actions" + test-determine-image-tags: + uses: ./.github/workflows/test-determine-image-tags.yml validate-action-tests: # So we can add new tests without having to update branch protection rules name: Validate action test results - needs: [test-actions] + needs: [test-determine-image-tags] if: always() runs-on: ubuntu-latest defaults: diff --git a/.github/workflows/CI-workflows.yml b/.github/workflows/CI-workflows.yml index 1aaa02d..6c41fc4 100644 --- a/.github/workflows/CI-workflows.yml +++ b/.github/workflows/CI-workflows.yml @@ -7,19 +7,13 @@ on: paths: - '.github/workflows/**' jobs: - test-workflows: - runs-on: ubuntu-latest - defaults: - run: - shell: pwsh - steps: - - name: Placeholder - run: echo "Placeholder for testing workflows" + test-push-docker-images: + uses: ./.github/workflows/test-push-docker-images.yml validate-workflow-tests: # So we can add new tests without having to update branch protection rules name: Validate workflow test results - needs: [test-workflows] + needs: [test-push-docker-images] if: always() runs-on: ubuntu-latest defaults: diff --git a/.github/workflows/push-docker-images.yml b/.github/workflows/push-docker-images.yml index 4ca7adb..01f5169 100644 --- a/.github/workflows/push-docker-images.yml +++ b/.github/workflows/push-docker-images.yml @@ -14,6 +14,13 @@ on: required: false type: string default: .github/docker-images.json + dry-run: + description: > + If true, skips registry logins and all actual pushes/description updates with loging of what would have happened + instead. + required: false + type: boolean + default: false permissions: contents: read packages: write @@ -80,17 +87,20 @@ jobs: - name: Checkout uses: actions/checkout@v7.0.1 - name: Log in to GitHub container registry + if: ${{ !inputs.dry-run }} uses: docker/login-action@v4.2.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub + if: ${{ !inputs.dry-run }} uses: docker/login-action@v4.2.0 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Set up Docker Buildx + if: ${{ !inputs.dry-run }} uses: docker/setup-buildx-action@v4.1.0 - name: Publish to Docker Hub run: | @@ -108,12 +118,19 @@ jobs: $tagsCLI = $tags -replace "^", "--tag particular/${name}:" $cmd = "docker buildx imagetools create $tagsCLI ghcr.io/particular/${name}:$sourceTag" Write-Output "Command: $cmd" - Invoke-Expression $cmd + if ('${{ inputs.dry-run }}' -eq 'true') + { + Write-Output "[dry-run] Skipping execution." + } + else + { + Invoke-Expression $cmd + } Write-Output "::endgroup::" } update-descriptions: needs: [determine-image-configurations, push-to-container-registry] - if: ${{ needs.determine-image-configurations.outputs.latest == 'true' }} + if: ${{ needs.determine-image-configurations.outputs.latest == 'true' && !inputs.dry-run }} runs-on: ubuntu-latest name: Update Docker Hub description strategy: diff --git a/.github/workflows/test-determine-image-tags.yml b/.github/workflows/test-determine-image-tags.yml new file mode 100644 index 0000000..af9f90a --- /dev/null +++ b/.github/workflows/test-determine-image-tags.yml @@ -0,0 +1,88 @@ +name: Test - determine-image-tags +on: + workflow_call: +jobs: + test-determine-image-tags: + name: ${{ matrix.scenario }} + runs-on: ubuntu-latest + defaults: + run: + shell: pwsh + strategy: + fail-fast: false + matrix: + include: + - scenario: release version + version: 9.9.9 + expect-failure: false + - scenario: prerelease version + version: 9.9.9-beta.1 + expect-failure: false + - scenario: invalid version + version: not-a-version + expect-failure: true + steps: + - name: Checkout + uses: actions/checkout@v7.0.1 + - name: Determine image tags + id: tags + continue-on-error: ${{ matrix.expect-failure }} + uses: ./.github/actions/determine-image-tags + with: + version: ${{ matrix.version }} + - name: Verify + run: | + $version = '${{ matrix.version }}' + $expectFailure = '${{ matrix.expect-failure }}' -eq 'true' + $outcome = '${{ steps.tags.outcome }}' + + if ($expectFailure) + { + if ($outcome -ne 'failure') + { + throw "Expected determine-image-tags to fail for version '$version', but outcome was '$outcome'." + } + Write-Output "OK: failed as expected ($outcome)" + exit 0 + } + + if ($outcome -ne 'success') + { + throw "Expected determine-image-tags to succeed for version '$version', but outcome was '$outcome'." + } + + $isMatch = $version -match '^(?\d+)\.(?\d+)\.(?\d+)(-(?[\w\-\.]+))?$' + $expectedMajor = $Matches.Major + $expectedMinor = $Matches.Minor + $expectedPatch = $Matches.Patch + # Cast to [string] because GitHub actions output empty strings but unmatched groups are null + $expectedPrerelease = [string]$Matches.PrereleaseLabel + + $major = '${{ steps.tags.outputs.major }}' + $minor = '${{ steps.tags.outputs.minor }}' + $patch = '${{ steps.tags.outputs.patch }}' + $prerelease = '${{ steps.tags.outputs.prerelease }}' + $imageTags = '${{ steps.tags.outputs.image-tags }}' -split ',' + $latest = '${{ steps.tags.outputs.latest }}' + + Write-Output "major=$major minor=$minor patch=$patch prerelease=$prerelease image-tags=$imageTags latest=$latest" + + if ($major -ne $expectedMajor) { throw "Expected major '$expectedMajor', got '$major'." } + if ($minor -ne $expectedMinor) { throw "Expected minor '$expectedMinor', got '$minor'." } + if ($patch -ne $expectedPatch) { throw "Expected patch '$expectedPatch', got '$patch'." } + if ($prerelease -ne $expectedPrerelease) { throw "Expected prerelease '$expectedPrerelease', got '$prerelease'." } + if ($imageTags -notcontains $version) { throw "Expected image-tags to include the version itself ('$version'), got: $imageTags" } + + if ($expectedPrerelease) + { + # Prerelease versions never get floating tags - only the version itself. + if ($imageTags.Count -ne 1) { throw "Expected a prerelease version to produce exactly one tag, got: $imageTags" } + } + else + { + # The action uses this repo's release history, so just make sure we see the expected values since we + # can't reliably test exact scenarios without making a mess of the releases + if ($latest -ne 'true' -and $latest -ne 'false') { throw "Expected latest to be 'true' or 'false', got '$latest'." } + } + + Write-Output "OK" diff --git a/.github/workflows/test-push-docker-images.yml b/.github/workflows/test-push-docker-images.yml new file mode 100644 index 0000000..613c0da --- /dev/null +++ b/.github/workflows/test-push-docker-images.yml @@ -0,0 +1,19 @@ +name: Test - push-docker-images +on: + workflow_call: +jobs: + test-valid: + name: valid config (${{ matrix.scenario }}) + strategy: + fail-fast: false + matrix: + include: + - scenario: single image + image-config-file: test/push-docker-images/valid-single-image.json + - scenario: multiple images + image-config-file: test/push-docker-images/valid-multi-image.json + uses: ./.github/workflows/push-docker-images.yml + with: + version: 1.2.3 + image-config-file: ${{ matrix.image-config-file }} + dry-run: true diff --git a/test/push-docker-images/valid-multi-image.json b/test/push-docker-images/valid-multi-image.json new file mode 100644 index 0000000..529b520 --- /dev/null +++ b/test/push-docker-images/valid-multi-image.json @@ -0,0 +1,12 @@ +[ + { + "name": "servicecontrol", + "readme_filepath": "./src/ServiceControl/Container-README.md", + "short_description": "Gather status, performance and monitoring data for multiple endpoints from a single location." + }, + { + "name": "servicecontrol-audit", + "readme_filepath": "./src/ServiceControl.Audit/Container-README.md", + "short_description": "Provide valuable information about the message flow through a system." + } +] diff --git a/test/push-docker-images/valid-single-image.json b/test/push-docker-images/valid-single-image.json new file mode 100644 index 0000000..49b8f4c --- /dev/null +++ b/test/push-docker-images/valid-single-image.json @@ -0,0 +1,7 @@ +[ + { + "name": "servicepulse", + "readme_filepath": "./Container-README.md", + "short_description": "Keep track of the health and performance of your system's endpoints." + } +]