fix(stdlib): default to epoch for invalid date constructor inputs (#1… #5095
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build Linux | |
| on: | |
| push: | |
| branches: [master, "release/[0-9]*"] | |
| pull_request: | |
| branches: [master, "release/[0-9]*"] | |
| merge_group: | |
| # Allows you to run this workflow manually from the Actions tab | |
| workflow_dispatch: | |
| env: | |
| IMAGE_NAME: rusty | |
| jobs: | |
| check: | |
| name: Check | |
| runs-on: ubuntu-latest | |
| container: ghcr.io/plc-lang/rust-llvm:21-1.95 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Run Check | |
| run: | | |
| ./scripts/build.sh --check | |
| test-linux: | |
| name: Test Linux | |
| runs-on: ${{ matrix.config.os }} | |
| strategy: | |
| matrix: | |
| config: | |
| - { os: "ubuntu-latest" } | |
| - { os: "ubuntu-24.04-arm" } | |
| steps: | |
| - name: Free up disk space on runner | |
| uses: jlumbroso/free-disk-space@main | |
| with: | |
| tool-cache: true | |
| android: true | |
| dotnet: true | |
| haskell: true | |
| large-packages: true | |
| docker-images: false | |
| swap-storage: true | |
| - name: Show disk space after cleanup | |
| run: df -h | |
| - uses: actions/checkout@v6 | |
| - name: Cargo test | |
| run: | | |
| docker run --rm \ | |
| --entrypoint /bin/bash \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace \ | |
| ghcr.io/plc-lang/rust-llvm:21-1.95 \ | |
| -c "df -h && ./scripts/build.sh --build --test" | |
| test-linux-release: | |
| name: Test Linux (release) | |
| runs-on: ${{ matrix.config.os }} | |
| strategy: | |
| matrix: | |
| config: | |
| - { os: "ubuntu-latest" } | |
| - { os: "ubuntu-24.04-arm" } | |
| steps: | |
| - name: Free up disk space on runner | |
| uses: jlumbroso/free-disk-space@main | |
| with: | |
| tool-cache: true | |
| android: true | |
| dotnet: true | |
| haskell: true | |
| large-packages: true | |
| docker-images: false | |
| swap-storage: true | |
| - name: Show disk space after cleanup | |
| run: df -h | |
| - uses: actions/checkout@v6 | |
| - name: Cargo test (release) | |
| run: | | |
| docker run --rm \ | |
| --entrypoint /bin/bash \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace \ | |
| ghcr.io/plc-lang/rust-llvm:21-1.95 \ | |
| -c "df -h && ./scripts/build.sh --build --test --release" | |
| package-linux: | |
| name: Package Linux (${{ matrix.config.arch }}) | |
| runs-on: ${{ matrix.config.os }} | |
| strategy: | |
| matrix: | |
| config: | |
| - { os: "ubuntu-latest", arch: "x86_64" } | |
| - { os: "ubuntu-24.04-arm", arch: "aarch64" } | |
| container: ghcr.io/plc-lang/rust-llvm:21-1.95 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Release Build (native ${{ matrix.config.arch }}) | |
| shell: bash | |
| run: | | |
| echo "Building native binary for ${{ matrix.config.arch }}" | |
| ./scripts/build.sh --build --release --package --deb | |
| - name: Build and package the std lib | |
| if: matrix.config.arch == 'x86_64' | |
| shell: bash | |
| run: | | |
| # required by aarch64 build | |
| apt update && apt install -y gcc-aarch64-linux-gnu | |
| # Clean up apt cache to free disk space | |
| apt-get clean | |
| rm -rf /var/lib/apt/lists/* | |
| echo "Build command : ./scripts/build.sh --build --release" | |
| ./scripts/build.sh --build --release --package --deb \ | |
| --target x86_64-linux-gnu,aarch64-linux-gnu,x86_64-unknown-linux-gnu,aarch64-unknown-linux-gnu | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: plc-${{ matrix.config.arch }} | |
| path: target/release/plc | |
| if-no-files-found: error | |
| - uses: actions/upload-artifact@v7 | |
| if: matrix.config.arch == 'x86_64' | |
| with: | |
| name: stdlib | |
| path: output/ | |
| - uses: actions/upload-artifact@v7 | |
| if: matrix.config.arch == 'x86_64' | |
| with: | |
| name: schema | |
| path: compiler/plc_project/schema/ | |
| - uses: actions/upload-artifact@v7 | |
| with: | |
| name: deb-${{ matrix.config.arch }} | |
| path: target/debian/*.deb | |
| if-no-files-found: error | |
| build-and-push-image: | |
| name: Build Image (${{ matrix.config.arch }}) | |
| runs-on: ${{ matrix.config.os }} | |
| needs: package-linux | |
| strategy: | |
| matrix: | |
| config: | |
| - { os: "ubuntu-latest", arch: "x86_64", docker_arch: "amd64" } | |
| - { os: "ubuntu-24.04-arm", arch: "aarch64", docker_arch: "arm64" } | |
| permissions: | |
| actions: read | |
| packages: write | |
| contents: read | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Download deb artifacts (x86_64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: deb-x86_64 | |
| path: artifacts/deb-x86_64/ | |
| - name: Download deb artifacts (aarch64) | |
| uses: actions/download-artifact@v8 | |
| with: | |
| name: deb-aarch64 | |
| path: artifacts/deb-aarch64/ | |
| - name: Prepare deb artifacts | |
| run: | | |
| mkdir -p artifacts/deb | |
| # Debug: show artifact structure | |
| echo "Artifact structure:" | |
| find artifacts/ -name "*.deb" -type f | |
| # Copy the plc binary deb for this image's architecture only | |
| find artifacts/deb-${{ matrix.config.arch }}/ -name "plc-compiler_*_${{ matrix.config.docker_arch }}.deb" -exec cp {} artifacts/deb/ \; | |
| # Copy plc-stdlib debs for BOTH architectures (cross-compilation support) | |
| find artifacts/deb-x86_64/ -name "plc-stdlib_*_amd64.deb" -exec cp {} artifacts/deb/ \; | |
| find artifacts/deb-aarch64/ -name "plc-stdlib_*_arm64.deb" -exec cp {} artifacts/deb/ \; | |
| # Validate that expected files were copied | |
| echo "Deb packages for Docker image (${{ matrix.config.docker_arch }}):" | |
| ls -la artifacts/deb/ | |
| if [ -z "$(ls -A artifacts/deb/*.deb 2>/dev/null)" ]; then | |
| echo "ERROR: No deb files were copied to artifacts/deb/" | |
| exit 1 | |
| fi | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Build Docker image | |
| run: | | |
| docker buildx build . \ | |
| --platform linux/${{ matrix.config.docker_arch }} \ | |
| --file Dockerfile \ | |
| --tag ${{ env.IMAGE_NAME }}:local \ | |
| --load | |
| - name: Log in to registry | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| (github.event_name != 'pull_request' && github.ref == 'refs/heads/master') | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Push image with temp tag | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| (github.event_name != 'pull_request' && github.ref == 'refs/heads/master') | |
| run: | | |
| IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} | |
| IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') | |
| TEMP_TAG="build-${{ github.run_id }}-${{ matrix.config.arch }}" | |
| docker tag ${{ env.IMAGE_NAME }}:local $IMAGE_ID:$TEMP_TAG | |
| docker push $IMAGE_ID:$TEMP_TAG | |
| echo "Pushed: $IMAGE_ID:$TEMP_TAG" | |
| - name: Simulate push (PR only) | |
| if: ${{ github.event_name == 'pull_request' }} | |
| run: | | |
| echo "==========================================" | |
| echo "SIMULATION MODE (Pull Request)" | |
| echo "Would push: ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }}:build-${{ github.run_id }}-${{ matrix.config.arch }}" | |
| echo "Platform: linux/${{ matrix.config.docker_arch }}" | |
| echo "==========================================" | |
| push-multiplatform: | |
| name: Push Multiplatform Manifest | |
| needs: build-and-push-image | |
| runs-on: ubuntu-latest | |
| if: | | |
| github.event_name == 'workflow_dispatch' || | |
| (github.event_name != 'pull_request' && github.ref == 'refs/heads/master') | |
| permissions: | |
| packages: write | |
| steps: | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@v4 | |
| - name: Log in to registry | |
| uses: docker/login-action@v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create and push manifest | |
| run: | | |
| IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} | |
| IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') | |
| echo "Creating multiplatform manifest..." | |
| docker buildx imagetools create \ | |
| -t $IMAGE_ID:latest \ | |
| $IMAGE_ID:build-${{ github.run_id }}-x86_64 \ | |
| $IMAGE_ID:build-${{ github.run_id }}-aarch64 | |
| echo "Pushed: $IMAGE_ID:latest" | |
| - name: Cleanup temp tags | |
| if: always() | |
| continue-on-error: true | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} | |
| IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') | |
| # Delete temp images by tag | |
| for ARCH in x86_64 aarch64; do | |
| TEMP_TAG="build-${{ github.run_id }}-$ARCH" | |
| echo "Deleting $TEMP_TAG..." | |
| # Get version ID for this tag | |
| VERSION_ID=$(gh api \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "/orgs/${{ github.repository_owner }}/packages/container/${{ env.IMAGE_NAME }}/versions" \ | |
| --jq ".[] | select(.metadata.container.tags[] == \"$TEMP_TAG\") | .id") | |
| if [ -n "$VERSION_ID" ]; then | |
| gh api --method DELETE \ | |
| -H "Accept: application/vnd.github+json" \ | |
| "/orgs/${{ github.repository_owner }}/packages/container/${{ env.IMAGE_NAME }}/versions/$VERSION_ID" || true | |
| echo "Deleted version $VERSION_ID" | |
| fi | |
| done | |
| echo "Cleanup complete" | |
| style: | |
| name: Check Style | |
| runs-on: ubuntu-latest | |
| container: ghcr.io/plc-lang/rust-llvm:21-1.95 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Run Checks | |
| run: | | |
| ./scripts/build.sh --check-style | |
| coverage: | |
| name: Run Coverage | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Free up disk space on runner | |
| uses: jlumbroso/free-disk-space@main | |
| with: | |
| tool-cache: true | |
| android: true | |
| dotnet: true | |
| haskell: true | |
| large-packages: true | |
| docker-images: false | |
| swap-storage: true | |
| - name: Show disk space after cleanup | |
| run: df -h | |
| - uses: actions/checkout@v6 | |
| - name: Run coverage in container | |
| run: | | |
| docker run --rm \ | |
| --entrypoint /bin/bash \ | |
| -v ${{ github.workspace }}:/workspace \ | |
| -w /workspace \ | |
| ghcr.io/plc-lang/rust-llvm:21-1.95 \ | |
| -c "df -h && apt-get clean && rm -rf /var/lib/apt/lists/* && ./scripts/build.sh --coverage" | |
| - name: Upload to codecov.io | |
| uses: codecov/codecov-action@v6 | |
| with: | |
| files: lcov.info | |
| - name: Archive code coverage results | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: code-coverage-report | |
| path: lcov.info | |
| pr-artifacts: | |
| name: PR Artifacts | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| needs: package-linux | |
| permissions: | |
| pull-requests: write | |
| steps: | |
| - uses: actions/github-script@v9 | |
| with: | |
| script: | | |
| const { data: artifacts } = await github.rest.actions.listWorkflowRunArtifacts({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| run_id: context.runId, | |
| }); | |
| const runUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`; | |
| const lines = artifacts.artifacts | |
| .filter(a => a.name !== 'code-coverage-report') | |
| .map(a => `| \`${a.name}\` | [Download](${runUrl}/artifacts/${a.id}) | ${(a.size_in_bytes / 1024 / 1024).toFixed(1)} MB |`); | |
| const section = [ | |
| '#### :penguin: Linux', | |
| '| Artifact | Link | Size |', | |
| '|----------|------|------|', | |
| ...lines, | |
| '', | |
| `_From [workflow run](${runUrl})_`, | |
| ].join('\n'); | |
| const COMMENT_MARKER = '<!-- pr-artifacts -->'; | |
| const SECTION_START = '<!-- linux-start -->'; | |
| const SECTION_END = '<!-- linux-end -->'; | |
| const sectionBlock = `${SECTION_START}\n${section}\n${SECTION_END}`; | |
| const { data: comments } = await github.rest.issues.listComments({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| }); | |
| const existing = comments.find(c => c.body.includes(COMMENT_MARKER)); | |
| if (existing) { | |
| const re = new RegExp(`${SECTION_START}[\\s\\S]*?${SECTION_END}`); | |
| const body = re.test(existing.body) | |
| ? existing.body.replace(re, sectionBlock) | |
| : existing.body + '\n\n' + sectionBlock; | |
| await github.rest.issues.updateComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| comment_id: existing.id, | |
| body, | |
| }); | |
| } else { | |
| await github.rest.issues.createComment({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| issue_number: context.issue.number, | |
| body: `${COMMENT_MARKER}\n### Build Artifacts\n\n${sectionBlock}`, | |
| }); | |
| } | |