name: Build and deploy containers # Pushes to main will build containers with staging env's and push them as staging images, whereas release goes to production. on: release: types: [published] push: branches: - main env: BACKEND_IMAGE_NAME: ${{ github.event_name == 'release' && 'nowdb-backend' || 'nowdb-backend-staging' }} FRONTEND_IMAGE_NAME: ${{ github.event_name == 'release' && 'nowdb-frontend' || 'nowdb-frontend-staging' }} BACKEND_URL: ${{ github.event_name == 'release' && secrets.BACKEND_URL_PROD || secrets.BACKEND_URL_STAGING }} RUNNING_ENV: ${{ github.event_name == 'release' && 'prod' || 'staging' }} ENABLE_WRITE: ${{ github.event_name == 'release' && 'false' || 'true' }} # Backend env's are defined inside the cluster, whereas frontend's have to be defined at build stage, that's why they're here jobs: push_backend: if: ${{ github.event_name == 'release' || (github.event_name == 'push' && !contains(github.event.head_commit.message, '#no-deploy')) }} runs-on: ubuntu-latest permissions: packages: write contents: read steps: - uses: actions/checkout@v5 - name: Build image run: docker build . --file backend/Dockerfile --tag $BACKEND_IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" --target node-run - name: Log in to registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin # - name: Push image run: | IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$BACKEND_IMAGE_NAME # This changes all uppercase characters to lowercase. IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') # This strips the git ref prefix from the version. VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') # This strips the "v" prefix from the tag name. [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') VERSION=latest echo IMAGE_ID=$IMAGE_ID echo VERSION=$VERSION docker tag $BACKEND_IMAGE_NAME $IMAGE_ID:$VERSION docker push $IMAGE_ID:$VERSION push_frontend: if: ${{ github.event_name == 'release' || (github.event_name == 'push' && !contains(github.event.head_commit.message, '#no-deploy')) }} runs-on: ubuntu-latest permissions: packages: write contents: read steps: - uses: actions/checkout@v5 - name: Build image run: docker build frontend --tag $FRONTEND_IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" --build-arg BACKEND_URL=${BACKEND_URL} --build-arg RUNNING_ENV=${RUNNING_ENV} --build-arg ENABLE_WRITE=${ENABLE_WRITE} --build-arg GEONAMES_USERNAME=${{ secrets.GEONAMES_USERNAME }} --target serve - name: Log in to registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin # - name: Push image run: | IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$FRONTEND_IMAGE_NAME # This changes all uppercase characters to lowercase. IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') # This strips the git ref prefix from the version. VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') # This strips the "v" prefix from the tag name. [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') # This uses the Docker `latest` tag convention. VERSION=latest echo IMAGE_ID=$IMAGE_ID echo VERSION=$VERSION docker tag $FRONTEND_IMAGE_NAME $IMAGE_ID:$VERSION docker push $IMAGE_ID:$VERSION # delete_old_prod: # runs-on: ubuntu-latest # if: ${{ github.event_name == 'release' }} # steps: # - uses: actions/delete-package-versions@v5 # with: # package-name: 'nowdb-frontend' # min-versions-to-keep: 5 # package-type: 'container' # - uses: actions/delete-package-versions@v5 # with: # package-name: 'nowdb-backend' # min-versions-to-keep: 5 # package-type: 'container' delete_old_staging: runs-on: ubuntu-latest if: ${{ github.event_name == 'push' }} permissions: packages: write contents: read steps: - uses: actions/github-script@v8 env: PACKAGE_NAME: nowdb-frontend-staging MIN_VERSIONS_TO_KEEP: '3' with: script: | const packageName = process.env.PACKAGE_NAME; const minVersionsToKeep = Number(process.env.MIN_VERSIONS_TO_KEEP ?? '0'); const owner = context.repo.owner; const listVersions = async () => { try { return await github.paginate( github.rest.packages.getAllPackageVersionsForPackageOwnedByOrg, { package_type: 'container', package_name: packageName, org: owner, per_page: 100, }, ); } catch (error) { if (error.status !== 404) { throw error; } return github.paginate( github.rest.packages.getAllPackageVersionsForPackageOwnedByUser, { package_type: 'container', package_name: packageName, username: owner, per_page: 100, }, ); } }; const deleteVersion = async (packageVersionId) => { try { await github.rest.packages.deletePackageVersionForOrg({ package_type: 'container', package_name: packageName, org: owner, package_version_id: packageVersionId, }); } catch (error) { if (error.status !== 404) { throw error; } await github.rest.packages.deletePackageVersionForUser({ package_type: 'container', package_name: packageName, username: owner, package_version_id: packageVersionId, }); } }; const versions = await listVersions(); const versionsToDelete = versions .slice() .sort((a, b) => new Date(b.created_at) - new Date(a.created_at)) .slice(minVersionsToKeep); core.info(`Found ${versions.length} versions for ${packageName}. Deleting ${versionsToDelete.length}.`); for (const version of versionsToDelete) { await deleteVersion(version.id); core.info(`Deleted ${packageName} version ${version.id}.`); } - uses: actions/github-script@v8 env: PACKAGE_NAME: nowdb-backend-staging MIN_VERSIONS_TO_KEEP: '3' with: script: | const packageName = process.env.PACKAGE_NAME; const minVersionsToKeep = Number(process.env.MIN_VERSIONS_TO_KEEP ?? '0'); const owner = context.repo.owner; const listVersions = async () => { try { return await github.paginate( github.rest.packages.getAllPackageVersionsForPackageOwnedByOrg, { package_type: 'container', package_name: packageName, org: owner, per_page: 100, }, ); } catch (error) { if (error.status !== 404) { throw error; } return github.paginate( github.rest.packages.getAllPackageVersionsForPackageOwnedByUser, { package_type: 'container', package_name: packageName, username: owner, per_page: 100, }, ); } }; const deleteVersion = async (packageVersionId) => { try { await github.rest.packages.deletePackageVersionForOrg({ package_type: 'container', package_name: packageName, org: owner, package_version_id: packageVersionId, }); } catch (error) { if (error.status !== 404) { throw error; } await github.rest.packages.deletePackageVersionForUser({ package_type: 'container', package_name: packageName, username: owner, package_version_id: packageVersionId, }); } }; const versions = await listVersions(); const versionsToDelete = versions .slice() .sort((a, b) => new Date(b.created_at) - new Date(a.created_at)) .slice(minVersionsToKeep); core.info(`Found ${versions.length} versions for ${packageName}. Deleting ${versionsToDelete.length}.`); for (const version of versionsToDelete) { await deleteVersion(version.id); core.info(`Deleted ${packageName} version ${version.id}.`); }