Add workflow to promote artifacts upon QA-approval#241
Add workflow to promote artifacts upon QA-approval#241seriAlizations wants to merge 3 commits intoionos-devfrom
Conversation
da01fa6 to
5e211e0
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds a GitHub Actions workflow to promote QA-approved artifacts from the development branch to the stable branch. The workflow ensures that artifacts are promoted without rebuilding, maintaining the exact same commit SHA throughout the process.
Changes:
- Adds a new workflow that performs a fast-forward merge from
ionos-devtoionos-stable - Implements artifact promotion from snapshot repository to release repository in Artifactory
- Includes verification steps to ensure the SHA exists in the development branch before promotion
978980a to
316d3e0
Compare
upon QA-approval Signed-off-by: Aliza Held <aliza.held@strato.de>
Signed-off-by: Aliza Held <aliza.held@strato.de>
e291e5a to
a120461
Compare
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Signed-off-by: Aliza Held <124045671+seriAlizations@users.noreply.github.com>
|
I took a look at the pipeline and it looks good to me |
| # Expected Artifactory layout: | ||
| # ionos-productivity-ncwserver-snapshot/ | ||
| # dev/<branch-name>/$SHA/<artifact-files> | ||
| # | ||
| # We search for a single .tar.gz artifact for the given SHA and | ||
| # derive its containing directory. This avoids using wildcards | ||
| # for the branch component when copying to the release repo. | ||
| set -e | ||
| SEARCH_RESULT=$(jf rt search --format=json --limit=2 "${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}/dev/*/$SHA/*.tar.gz") | ||
| MATCH_COUNT=$(echo "$SEARCH_RESULT" | jq '.results | length') | ||
|
|
||
| if [ "$MATCH_COUNT" -eq 0 ]; then | ||
| echo "No artifact with SHA $SHA found." | ||
| exit 1 | ||
| fi | ||
|
|
||
| if [ "$MATCH_COUNT" -gt 1 ]; then | ||
| echo "Multiple artifacts found for SHA $SHA; expected exactly one." | ||
| echo "$SEARCH_RESULT" | ||
| exit 1 | ||
| fi | ||
|
|
||
| ARTIFACT_REPO=$(echo "$SEARCH_RESULT" | jq -r '.results[0].repo') | ||
| ARTIFACT_PATH=$(echo "$SEARCH_RESULT" | jq -r '.results[0].path') | ||
| # Derive the directory that contains all artifacts for this SHA | ||
| ARTIFACT_DIR_PATH=$(dirname "$ARTIFACT_PATH") | ||
| ARTIFACT_DIR="$ARTIFACT_REPO/$ARTIFACT_DIR_PATH" | ||
|
|
||
| echo "Using artifact directory: $ARTIFACT_DIR" | ||
| # Expose the directory as a step output for the copy step | ||
| echo "artifact_dir=$ARTIFACT_DIR" >> "$GITHUB_OUTPUT" | ||
| - name: Copy artifact to target | ||
| id: copy_artifact | ||
| run: | | ||
| jf rt copy \ | ||
| "${{ steps.find_artifact.outputs.artifact_dir }}/*" \ | ||
| "${{ env.ARTIFACTORY_REPOSITORY_RELEASE }}/stable/${SHA}/" | ||
|
|
||
| - name: Confirm promoted artifacts | ||
| run: | | ||
| jf rt search --format=table "${{ env.ARTIFACTORY_REPOSITORY_RELEASE }}/stable/${SHA}/*" |
There was a problem hiding this comment.
The Artifactory search pattern here (.../dev/*/$SHA/*.tar.gz) doesn’t match the layout used by .github/workflows/build-artifact.yml when uploading the workspace artifact (stored as nc-workspace.zip under <stage>/ncw-<ncVersion>/<shortSha>/...). With the current path/extension and use of full SHA, this step will fail to find the QA-approved build. Update the search/copy logic to follow the actual upload structure (including using the short SHA if that’s what the upload uses).
| # Expected Artifactory layout: | |
| # ionos-productivity-ncwserver-snapshot/ | |
| # dev/<branch-name>/$SHA/<artifact-files> | |
| # | |
| # We search for a single .tar.gz artifact for the given SHA and | |
| # derive its containing directory. This avoids using wildcards | |
| # for the branch component when copying to the release repo. | |
| set -e | |
| SEARCH_RESULT=$(jf rt search --format=json --limit=2 "${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}/dev/*/$SHA/*.tar.gz") | |
| MATCH_COUNT=$(echo "$SEARCH_RESULT" | jq '.results | length') | |
| if [ "$MATCH_COUNT" -eq 0 ]; then | |
| echo "No artifact with SHA $SHA found." | |
| exit 1 | |
| fi | |
| if [ "$MATCH_COUNT" -gt 1 ]; then | |
| echo "Multiple artifacts found for SHA $SHA; expected exactly one." | |
| echo "$SEARCH_RESULT" | |
| exit 1 | |
| fi | |
| ARTIFACT_REPO=$(echo "$SEARCH_RESULT" | jq -r '.results[0].repo') | |
| ARTIFACT_PATH=$(echo "$SEARCH_RESULT" | jq -r '.results[0].path') | |
| # Derive the directory that contains all artifacts for this SHA | |
| ARTIFACT_DIR_PATH=$(dirname "$ARTIFACT_PATH") | |
| ARTIFACT_DIR="$ARTIFACT_REPO/$ARTIFACT_DIR_PATH" | |
| echo "Using artifact directory: $ARTIFACT_DIR" | |
| # Expose the directory as a step output for the copy step | |
| echo "artifact_dir=$ARTIFACT_DIR" >> "$GITHUB_OUTPUT" | |
| - name: Copy artifact to target | |
| id: copy_artifact | |
| run: | | |
| jf rt copy \ | |
| "${{ steps.find_artifact.outputs.artifact_dir }}/*" \ | |
| "${{ env.ARTIFACTORY_REPOSITORY_RELEASE }}/stable/${SHA}/" | |
| - name: Confirm promoted artifacts | |
| run: | | |
| jf rt search --format=table "${{ env.ARTIFACTORY_REPOSITORY_RELEASE }}/stable/${SHA}/*" | |
| # Expected Artifactory layout (from build-artifact.yml): | |
| # ionos-productivity-ncwserver-snapshot/ | |
| # <stage>/ncw-<ncVersion>/<shortSha>/nc-workspace.zip | |
| # | |
| # We derive the short SHA from the full SHA provided as input, | |
| # search for the nc-workspace.zip artifact for that short SHA, | |
| # and then derive its containing directory. This avoids using | |
| # wildcards for the version component when copying to the release repo. | |
| set -e | |
| SHORT_SHA=${SHA:0:7} | |
| SEARCH_RESULT=$(jf rt search --format=json --limit=2 "${{ env.ARTIFACTORY_REPOSITORY_SNAPSHOT }}/*/ncw-*/*${SHORT_SHA}/nc-workspace.zip") | |
| MATCH_COUNT=$(echo "$SEARCH_RESULT" | jq '.results | length') | |
| if [ "$MATCH_COUNT" -eq 0 ]; then | |
| echo "No artifact with short SHA $SHORT_SHA (from $SHA) found." | |
| exit 1 | |
| fi | |
| if [ "$MATCH_COUNT" -gt 1 ]; then | |
| echo "Multiple artifacts found for short SHA $SHORT_SHA (from $SHA); expected exactly one." | |
| echo "$SEARCH_RESULT" | |
| exit 1 | |
| fi | |
| ARTIFACT_REPO=$(echo "$SEARCH_RESULT" | jq -r '.results[0].repo') | |
| ARTIFACT_PATH=$(echo "$SEARCH_RESULT" | jq -r '.results[0].path') | |
| # Derive the directory that contains all artifacts for this short SHA | |
| ARTIFACT_DIR_PATH=$(dirname "$ARTIFACT_PATH") | |
| ARTIFACT_DIR="$ARTIFACT_REPO/$ARTIFACT_DIR_PATH" | |
| echo "Using artifact directory: $ARTIFACT_DIR" | |
| # Expose the directory and short SHA as step outputs for subsequent steps | |
| echo "artifact_dir=$ARTIFACT_DIR" >> "$GITHUB_OUTPUT" | |
| echo "short_sha=$SHORT_SHA" >> "$GITHUB_OUTPUT" | |
| - name: Copy artifact to target | |
| id: copy_artifact | |
| run: | | |
| jf rt copy \ | |
| "${{ steps.find_artifact.outputs.artifact_dir }}/*" \ | |
| "${{ env.ARTIFACTORY_REPOSITORY_RELEASE }}/stable/${{ steps.find_artifact.outputs.short_sha }}/" | |
| - name: Confirm promoted artifacts | |
| run: | | |
| jf rt search --format=table "${{ env.ARTIFACTORY_REPOSITORY_RELEASE }}/stable/${{ steps.find_artifact.outputs.short_sha }}/*" |
| # We search for a single .tar.gz artifact for the given SHA and | ||
| # derive its containing directory. This avoids using wildcards | ||
| # for the branch component when copying to the release repo. | ||
| set -e |
There was a problem hiding this comment.
This step uses set -e but relies on pipelines like echo "$SEARCH_RESULT" | jq ...; without set -o pipefail (and ideally -u), jq parse failures can be ignored and lead to misleading behavior downstream. Switch to set -euo pipefail (consistent with earlier steps) so JSON parsing errors fail the job.
| set -e | |
| set -euo pipefail |
| # Copy specified artifact to the release repo -> No rebuild | ||
| # (ionos-productivity-ncwserver-release) | ||
| needs: promote-git | ||
| runs-on: ubuntu-latest | ||
| steps: |
There was a problem hiding this comment.
Job ordering makes the git fast-forward/push happen before the Artifactory copy (promote-artifact depends on promote-git). If the artifact copy fails (missing artifact, JFrog outage, permission issue), ionos-stable will already have advanced, leaving the stable branch and release artifacts out of sync. Consider promoting/verifying artifacts first and only pushing ionos-stable after the copy succeeds (or otherwise enforce atomicity).
| sha: | ||
| description: 'Commit SHA to promote from ionos-dev to ionos-stable and copy artifacts for' | ||
| required: true | ||
| type: string | ||
| env: | ||
| SHA: ${{ inputs.sha }} | ||
| ARTIFACTORY_REPOSITORY_SNAPSHOT: ionos-productivity-ncwserver-snapshot |
There was a problem hiding this comment.
inputs.sha is accepted as an arbitrary git revision (e.g., a ref like origin/ionos-dev or HEAD), not strictly a commit hash. That can promote a moving target or an unintended commit. Validate the input to only allow a full 40-hex commit SHA (and derive SHORT_SHA=${SHA:0:7} from it if needed for artifact paths).
Summary
TODO
Checklist