name: Build Catalog Lite on: workflow_dispatch: inputs: expiration_date: description: Catalog Lite expiration date, yyyy-MM-dd required: true default: '2026-12-31' type: string env: DOTNET_VERSION: 10.0.x PROJECT_PATH: CatalogLite/CatalogLite.csproj CATALOG_LITE_EXPIRATION_DATE: ${{ inputs.expiration_date }} jobs: build: runs-on: docker strategy: fail-fast: false matrix: include: - runtime: win-x64 artifact_name: catalog-lite-win-x64 executable_name: CatalogLite.exe - runtime: linux-x64 artifact_name: catalog-lite-linux-x64 executable_name: CatalogLite steps: - name: Checkout uses: actions/checkout@v4 - name: Setup .NET uses: actions/setup-dotnet@v4 with: dotnet-version: ${{ env.DOTNET_VERSION }} - name: Validate expiration date run: | set -eu case "${CATALOG_LITE_EXPIRATION_DATE}" in ????-??-??) ;; *) echo "expiration_date must use yyyy-MM-dd format" exit 1 ;; esac - name: Restore run: dotnet restore "${{ env.PROJECT_PATH }}" -r "${{ matrix.runtime }}" --configfile NuGet.Config - name: Publish Catalog Lite env: PUBLISH_DIR: artifacts/publish/${{ matrix.runtime }} run: | set -eu dotnet publish "${{ env.PROJECT_PATH }}" \ -c Release \ -r "${{ matrix.runtime }}" \ --self-contained false \ --no-restore \ -p:CatalogLiteExpirationDate="${CATALOG_LITE_EXPIRATION_DATE}" \ -p:PublishSingleFile=true \ -p:SelfContained=false \ -p:IncludeNativeLibrariesForSelfExtract=true \ -p:PublishTrimmed=false \ -p:PublishReadyToRun=false \ -p:DebugType=embedded \ -o "${PUBLISH_DIR}" - name: Validate published files env: PUBLISH_DIR: artifacts/publish/${{ matrix.runtime }} run: | set -eu executable="${PUBLISH_DIR}/${{ matrix.executable_name }}" if [ ! -f "${executable}" ]; then echo "Catalog Lite executable was not produced: ${executable}" exit 1 fi loose_library_count="$(find "${PUBLISH_DIR}" -maxdepth 1 -type f \( -iname '*.dll' -o -name '*.so' -o -name '*.dylib' \) | wc -l | tr -d ' ')" if [ "${loose_library_count}" -ne 0 ]; then echo "Catalog Lite publish must not contain loose native or managed libraries:" find "${PUBLISH_DIR}" -maxdepth 1 -type f \( -iname '*.dll' -o -name '*.so' -o -name '*.dylib' \) -print exit 1 fi extra_file_count="$(find "${PUBLISH_DIR}" -maxdepth 1 -type f ! -name "${{ matrix.executable_name }}" | wc -l | tr -d ' ')" if [ "${extra_file_count}" -ne 0 ]; then echo "Catalog Lite publish artifact must contain only ${{ matrix.executable_name }}:" find "${PUBLISH_DIR}" -maxdepth 1 -type f ! -name "${{ matrix.executable_name }}" -print exit 1 fi - name: Upload publish artifact uses: actions/upload-artifact@v3 with: name: ${{ matrix.artifact_name }} path: artifacts/publish/${{ matrix.runtime }}/${{ matrix.executable_name }} if-no-files-found: error release: needs: build runs-on: docker env: FORGEJO_TOKEN: ${{ secrets.FORGEJO_TOKEN }} steps: - name: Download Windows artifact uses: actions/download-artifact@v3 with: name: catalog-lite-win-x64 path: artifacts/release/win-x64 - name: Validate release token run: | set -eu if [ -z "${FORGEJO_TOKEN}" ]; then echo "secrets.FORGEJO_TOKEN is required for Catalog Lite releases" exit 1 fi - name: Create or update release run: | set -eu api_base="${FORGEJO_SERVER_URL%/}/api/v1/repos/${FORGEJO_REPOSITORY}" tag="catalog-lite-${CATALOG_LITE_EXPIRATION_DATE}" name="Catalog Lite ${CATALOG_LITE_EXPIRATION_DATE}" commit="${FORGEJO_SHA:-${GITHUB_SHA:-}}" create_payload="$(printf '{"tag_name":"%s","target_commitish":"%s","name":"%s","body":"Catalog Lite\\n\\nScadenza build: %s","draft":false,"prerelease":false}' "${tag}" "${commit}" "${name}" "${CATALOG_LITE_EXPIRATION_DATE}")" update_payload="$(printf '{"body":"Catalog Lite\\n\\nScadenza build: %s"}' "${CATALOG_LITE_EXPIRATION_DATE}")" http_code="$(curl -sS -o release.json -w '%{http_code}' \ -H "Authorization: token ${FORGEJO_TOKEN}" \ "${api_base}/releases/tags/${tag}")" if [ "${http_code}" = "200" ]; then release_id="$(sed -n 's/.*"id":\([0-9][0-9]*\).*/\1/p' release.json | head -n1)" curl -fsS \ -H "Authorization: token ${FORGEJO_TOKEN}" \ -H "Content-Type: application/json" \ -X PATCH \ -d "${update_payload}" \ "${api_base}/releases/${release_id}" \ -o release.json elif [ "${http_code}" = "404" ]; then curl -fsS \ -H "Authorization: token ${FORGEJO_TOKEN}" \ -H "Content-Type: application/json" \ -X POST \ -d "${create_payload}" \ "${api_base}/releases" \ -o release.json release_id="$(sed -n 's/.*"id":\([0-9][0-9]*\).*/\1/p' release.json | head -n1)" else echo "Unexpected response while loading release for tag ${tag}: ${http_code}" cat release.json exit 1 fi if [ -z "${release_id}" ]; then echo "Unable to resolve Forgejo release id" cat release.json exit 1 fi echo "RELEASE_ID=${release_id}" >> "${GITHUB_ENV}" - name: Upload release assets run: | set -eu api_base="${FORGEJO_SERVER_URL%/}/api/v1/repos/${FORGEJO_REPOSITORY}" windows_exe="$(find artifacts/release/win-x64 -maxdepth 1 -type f -iname '*.exe' | head -n1)" if [ -z "${windows_exe}" ]; then echo "No Windows executable found in downloaded artifact" exit 1 fi curl -fsS \ -H "Authorization: token ${FORGEJO_TOKEN}" \ "${api_base}/releases/${RELEASE_ID}/assets" \ -o assets.json for asset_id in $(tr '{' '\n' < assets.json | sed -n 's/.*"id":\([0-9][0-9]*\).*"name":"[^"]*".*/\1/p'); do curl -fsS \ -H "Authorization: token ${FORGEJO_TOKEN}" \ -X DELETE \ "${api_base}/releases/${RELEASE_ID}/assets/${asset_id}" done upload_asset() { asset_path="$1" asset_name="$2" curl -fsS \ -H "Authorization: token ${FORGEJO_TOKEN}" \ -H "Content-Type: application/octet-stream" \ --data-binary @"${asset_path}" \ "${api_base}/releases/${RELEASE_ID}/assets?name=${asset_name}" } upload_asset "${windows_exe}" "CatalogLite-${CATALOG_LITE_EXPIRATION_DATE}.exe"