diff --git a/.github/workflows/build_template_zip.yml b/.github/workflows/build_template_zip.yml new file mode 100644 index 0000000..eff826c --- /dev/null +++ b/.github/workflows/build_template_zip.yml @@ -0,0 +1,285 @@ +name: Build Joomla Tenplate ZIP from src folder + +on: + workflow_dispatch: + inputs: + target_folder: + description: "Folder to zip (relative to repo root)" + required: false + default: "src" + zip_name: + description: "Base ZIP name (default: repository name, lowercase)" + required: false + default: "" + version_suffix: + description: "Optional version suffix for filename (example 01.02.03)" + required: false + default: "" + publish_release: + description: "If true, upload ZIP and SHA256 as GitHub Release assets" + required: false + default: "false" + type: choice + options: + - "false" + - "true" + release_tag: + description: "Release tag to publish to (required if publish_release=true)" + required: false + default: "" + prerelease: + description: "If true, mark the release as prerelease" + required: false + default: "true" + type: choice + options: + - "false" + - "true" + + workflow_call: + inputs: + target_folder: + description: "Folder to zip (relative to repo root)" + required: false + type: string + default: "src" + zip_name: + description: "Base ZIP name (default: repository name, lowercase)" + required: false + type: string + default: "" + version_suffix: + description: "Optional version suffix for filename (example 01.02.03)" + required: false + type: string + default: "" + publish_release: + description: "If true, upload ZIP and SHA256 as GitHub Release assets" + required: false + type: boolean + default: false + release_tag: + description: "Release tag to publish to (required if publish_release=true)" + required: false + type: string + default: "" + prerelease: + description: "If true, mark the release as prerelease" + required: false + type: boolean + default: false + +permissions: + contents: write + +jobs: + zip: + name: Package folder as ZIP + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Verify tooling + shell: bash + run: | + set -euo pipefail + + if ! command -v zip >/dev/null 2>&1; then + echo "ERROR: zip is not installed on runner" >&2 + exit 1 + fi + + if ! command -v sha256sum >/dev/null 2>&1; then + echo "ERROR: sha256sum is not available on runner" >&2 + exit 1 + fi + + - name: Resolve and validate inputs + shell: bash + run: | + set -euo pipefail + + # Prefer workflow_call inputs when present, otherwise use workflow_dispatch inputs. + TARGET_FOLDER="${{ inputs.target_folder }}" + ZIP_NAME_INPUT="${{ inputs.zip_name }}" + VERSION_SUFFIX="${{ inputs.version_suffix }}" + PUBLISH_RELEASE="${{ inputs.publish_release }}" + RELEASE_TAG="${{ inputs.release_tag }}" + PRERELEASE="${{ inputs.prerelease }}" + + if [[ -z "$TARGET_FOLDER" ]]; then TARGET_FOLDER="${{ github.event.inputs.target_folder }}"; fi + if [[ -z "$ZIP_NAME_INPUT" ]]; then ZIP_NAME_INPUT="${{ github.event.inputs.zip_name }}"; fi + if [[ -z "$VERSION_SUFFIX" ]]; then VERSION_SUFFIX="${{ github.event.inputs.version_suffix }}"; fi + if [[ -z "$PUBLISH_RELEASE" ]]; then PUBLISH_RELEASE="${{ github.event.inputs.publish_release }}"; fi + if [[ -z "$RELEASE_TAG" ]]; then RELEASE_TAG="${{ github.event.inputs.release_tag }}"; fi + if [[ -z "$PRERELEASE" ]]; then PRERELEASE="${{ github.event.inputs.prerelease }}"; fi + + TARGET_FOLDER="${TARGET_FOLDER//[[:space:]]/}" + ZIP_NAME_INPUT="${ZIP_NAME_INPUT//[[:space:]]/}" + VERSION_SUFFIX="${VERSION_SUFFIX//[[:space:]]/}" + RELEASE_TAG="${RELEASE_TAG//[[:space:]]/}" + + if [[ -z "$TARGET_FOLDER" ]]; then + TARGET_FOLDER="src" + fi + + if [[ "$PUBLISH_RELEASE" == "true" || "$PUBLISH_RELEASE" == "True" ]]; then + PUBLISH_RELEASE="true" + else + PUBLISH_RELEASE="false" + fi + + if [[ "$PRERELEASE" == "true" || "$PRERELEASE" == "True" ]]; then + PRERELEASE="true" + else + PRERELEASE="false" + fi + + if [[ ! -d "$TARGET_FOLDER" ]]; then + echo "ERROR: Folder does not exist: $TARGET_FOLDER" >&2 + exit 1 + fi + + if [[ -n "$VERSION_SUFFIX" ]] && [[ ! "$VERSION_SUFFIX" =~ ^[0-9]{2}\.[0-9]{2}\.[0-9]{2}$ ]]; then + echo "ERROR: version_suffix must match NN.NN.NN (example 01.02.03)" >&2 + exit 1 + fi + + if [[ -n "$ZIP_NAME_INPUT" ]]; then + ZIP_NAME_INPUT="$(echo "$ZIP_NAME_INPUT" | tr '[:upper:]' '[:lower:]')" + fi + + if [[ "$PUBLISH_RELEASE" == "true" ]] && [[ -z "$RELEASE_TAG" ]]; then + echo "ERROR: release_tag is required when publish_release=true" >&2 + exit 1 + fi + + echo "TARGET_FOLDER=$TARGET_FOLDER" >> "$GITHUB_ENV" + echo "INPUT_ZIP_NAME=$ZIP_NAME_INPUT" >> "$GITHUB_ENV" + echo "INPUT_VERSION_SUFFIX=$VERSION_SUFFIX" >> "$GITHUB_ENV" + echo "PUBLISH_RELEASE=$PUBLISH_RELEASE" >> "$GITHUB_ENV" + echo "RELEASE_TAG=$RELEASE_TAG" >> "$GITHUB_ENV" + echo "PRERELEASE=$PRERELEASE" >> "$GITHUB_ENV" + + - name: Prepare dist folder + shell: bash + run: | + set -euo pipefail + rm -rf dist + mkdir -p dist + + - name: Resolve version + shell: bash + run: | + set -euo pipefail + + VERSION_SUFFIX="$INPUT_VERSION_SUFFIX" + + if [[ -z "$VERSION_SUFFIX" ]]; then + XML_FILE="" + if [[ -f "$TARGET_FOLDER/templateDetails.xml" ]]; then + XML_FILE="$TARGET_FOLDER/templateDetails.xml" + elif [[ -f "$TARGET_FOLDER/manifest.xml" ]]; then + XML_FILE="$TARGET_FOLDER/manifest.xml" + fi + + if [[ -n "$XML_FILE" ]]; then + VERSION_SUFFIX=$(grep -oPm1 '(?<=)[^<]+' "$XML_FILE" || true) + VERSION_SUFFIX="${VERSION_SUFFIX//[[:space:]]/}" + fi + fi + + if [[ -n "$VERSION_SUFFIX" ]] && [[ ! "$VERSION_SUFFIX" =~ ^[0-9]{2}\.[0-9]{2}\.[0-9]{2}$ ]]; then + echo "ERROR: Version found in XML is invalid: $VERSION_SUFFIX" >&2 + exit 1 + fi + + if [[ -z "$VERSION_SUFFIX" ]]; then + VERSION_SUFFIX="$(echo "${GITHUB_REPOSITORY##*/}" | tr '[:upper:]' '[:lower:]')" + fi + + echo "VERSION_SUFFIX=$VERSION_SUFFIX" >> "$GITHUB_ENV" + + - name: Create ZIP archive and SHA256 + shell: bash + run: | + set -euo pipefail + + DEFAULT_REPO_NAME="$(echo "${GITHUB_REPOSITORY##*/}" | tr '[:upper:]' '[:lower:]')" + BASE_ZIP_NAME="$INPUT_ZIP_NAME" + + if [[ -z "$BASE_ZIP_NAME" ]]; then + BASE_ZIP_NAME="$DEFAULT_REPO_NAME" + fi + + SAFE_FOLDER_NAME="$(echo "$TARGET_FOLDER" | tr '/' '-')" + + ZIP_NAME="${BASE_ZIP_NAME}-${SAFE_FOLDER_NAME}-${VERSION_SUFFIX}.zip" + ZIP_PATH="dist/$ZIP_NAME" + + cd "$TARGET_FOLDER" + + zip -r "../$ZIP_PATH" . \ + -x "*.DS_Store" \ + -x "__MACOSX/*" \ + -x "node_modules/*" \ + -x "coverage/*" \ + -x "*.log" \ + -x "*.tmp" + + cd - >/dev/null 2>&1 + + SHA_PATH="${ZIP_PATH}.sha256" + sha256sum "$ZIP_PATH" | awk '{print $1}' > "$SHA_PATH" + + ZIP_ARTIFACT_NAME="${ZIP_NAME}" + echo "ZIP_NAME=$ZIP_NAME" >> "$GITHUB_ENV" + echo "ZIP_ARTIFACT_NAME=$ZIP_ARTIFACT_NAME" >> "$GITHUB_ENV" + echo "ZIP_PATH=$ZIP_PATH" >> "$GITHUB_ENV" + echo "SHA_PATH=$SHA_PATH" >> "$GITHUB_ENV" + + - name: Export artifact metadata + id: meta + shell: bash + run: | + set -euo pipefail + echo "zip_artifact_name=$ZIP_NAME" >> "$GITHUB_OUTPUT" + echo "sha_artifact_name=${ZIP_NAME}.sha256" >> "$GITHUB_OUTPUT" + echo "zip_file_name=$ZIP_NAME" >> "$GITHUB_OUTPUT" + echo "sha_file_name=$(basename "$SHA_PATH")" >> "$GITHUB_OUTPUT" + + - name: Upload ZIP artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ZIP_ARTIFACT_NAME }} + path: ${{ env.ZIP_PATH }} + + - name: Upload SHA256 artifact + uses: actions/upload-artifact@v4 + with: + name: ${{ env.ZIP_NAME }}.sha256 + path: ${{ env.SHA_PATH }} + + - name: Upload assets to GitHub Release + id: release_upload + if: ${{ env.PUBLISH_RELEASE == 'true' }} + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ env.RELEASE_TAG }} + prerelease: ${{ env.PRERELEASE == 'true' }} + files: | + ${{ env.ZIP_PATH }} + ${{ env.SHA_PATH }} + + - name: Export release upload status + id: release_status + shell: bash + run: | + set -euo pipefail + if [[ "$PUBLISH_RELEASE" == "true" ]]; then + echo "release_uploaded=true" >> "$GITHUB_OUTPUT" + else + echo "release_uploaded=false" >> "$GITHUB_OUTPUT" + fi